Custom markdownlint rules that enforce Hong Minhee's Markdown style conventions. These rules extend markdownlint with checks that cannot be achieved through built-in configuration alone.
This package is available on both JSR and npm.
deno add jsr:@hongminhee/markdownlint-rulesnpm add -D @hongminhee/markdownlint-rulespnpm add -D @hongminhee/markdownlint-rulesbun add -D @hongminhee/markdownlint-rulesCreate a .markdownlint-cli2.mjs file in your project root:
import customRules from "@hongminhee/markdownlint-rules";
import preset from "@hongminhee/markdownlint-rules/preset";
export default {
customRules,
config: preset,
};You can also import and use rules individually:
import {
fencedCodeFenceLength,
headingSentenceCase,
listItemMarkerSpace,
referenceLinkSectionPlacement,
setextHeadingBlankLines,
} from "@hongminhee/markdownlint-rules";
export default {
customRules: [
listItemMarkerSpace,
fencedCodeFenceLength,
],
config: {
"HM001": true,
"HM002": { "fence_length": 4 },
},
};Enforces the - format for unordered list items: exactly one space before
the marker and exactly two spaces after.
This unusual spacing creates visual alignment where the item content starts at column 5. When list items wrap or contain nested content, the 4-space indentation aligns perfectly with the parent content.
Correct:
- First item
- Second item
- Nested item
Incorrect:
- First item # No leading space, only one space after
- Second item # Only one space after marker
- Third item # Two leading spaces instead of one
nested_indent: Number of spaces for each nesting level. Default:4post_marker_spaces: Number of spaces after the marker. Default:2
Enforces that fenced code blocks use tildes with at least four characters (configurable), and that opening and closing fences have matching lengths.
Using four tildes (~~~~) instead of three provides visual distinction and
allows embedding triple-tilde blocks inside documentation about Markdown
itself. Longer fences (5+) are allowed for nesting code blocks within
documentation.
Correct:
~~~~ typescript
const x = 1;
~~~~
~~~~~ markdown
Nested code block example:
~~~~ typescript
const y = 2;
~~~~
~~~~~
Incorrect:
``` typescript # Uses backticks
const x = 1;
```
~~~ typescript # Only three tildes (below minimum)
const x = 1;
~~~
~~~~ typescript # Mismatched fence lengths
const x = 1;
~~~~~
min_fence_length: Minimum number of fence characters. Default:4
Enforces that reference link definitions appear at the end of their content block—the region between any two headings (of any level).
Placing reference links at the end of content blocks keeps related content together. When content is moved or extracted, its links travel with it.
Correct:
Some section
------------
Here is some text with a [link][example].
[example]: https://example.com/
### Subsection
More content with [another link][other].
[other]: https://other.example.com/
Incorrect:
Some section
------------
[example]: https://example.com/
Here is some text with a [link][example].
Enforces two blank lines before Setext-style section headings (level 2) and one blank line before the document title (level 1).
Extra vertical space before major sections improves document scanability.
Note
When a heading immediately follows a parent heading with no content between them (e.g., h2 directly after h1), only one blank line is required.
Correct:
Document title
==============
Introduction paragraph here.
First section
-------------
Section content.
Second section
--------------
More content.
Also correct (h2 directly after h1 with no content):
Document title
==============
First section
-------------
Section content.
Incorrect:
Document title
==============
Introduction paragraph here.
First section
-------------
Only one blank line above.
lines_before_h1: Blank lines required before h1. Default:1lines_before_h2: Blank lines required before h2. Default:2
Warns when headings do not follow sentence case conventions (capitalizing only the first word and proper nouns).
Sentence case is easier to read and more consistent than title case, especially for technical documentation with many proper nouns and acronyms.
Correct:
Development commands
API reference for JavaScript
Incorrect:
Development Commands # "Commands" should be lowercase
Api Reference For Javascript # Multiple violations
allowed_words: List of words allowed to be capitalized. Default includes common proper nouns like “JavaScript”, “TypeScript”, “GitHub”, etc.ignore_acronyms: Whether to ignore all-caps words. Default:true
The package exports a recommended configuration preset that combines built-in markdownlint rules with the custom rules:
import preset from "@hongminhee/markdownlint-rules/preset";The preset configures:
- MD003: Setext headings with ATX for subsections
- MD004: Dash list markers
- MD007: 4-space list indentation
- MD013: 80-character line length
- MD022: Blank lines around headings
- MD030: Disabled (replaced by HM001)
- MD048: Tilde code fences
- All five custom rules (HM001-HM005)
This is a polyglot package supporting Deno, Node.js, and Bun.
Install mise to manage runtime versions:
mise installdeno task check # Type check, lint, format check, and dry-run publish
deno task test # Run tests with Deno
deno task test:node # Run tests with Node.js
deno task test:bun # Run tests with Bun
pnpm run build # Build for npm publishingDistributed under the MIT License. See the LICENSE file for details.