remark plugins to check (lint) markdown code style.
- What is this?
- When should I use this?
- Presets
- Rules
- Configure
- Ignore warnings
- Examples
- Integrations
- Syntax
- Compatibility
- Security
- Contribute
- License
You can use this to check markdown.
Say we have a markdown file doc/example.md
that contains:
1) Hello, _Jupiter_ and *Neptune*!
Then assuming we installed dependencies and run:
npx remark doc/ --use remark-preset-lint-consistent --use remark-preset-lint-recommended
We would get a report like this:
doc/example.md
1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint
1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint
1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint
⚠ 3 warnings
This GitHub repository is a monorepo that contains ±70 plugins (each a rule that checks one specific thing) and 3 presets (combinations of rules configured to check for certain styles).
These packages are build on unified (remark). unified is a project that inspects and transforms content with abstract syntax trees (ASTs). remark adds support for markdown to unified. mdast is the markdown AST that remark uses. These lint rules inspect mdast.
This project is useful when developers or technical writers are authoring documentation in markdown and you want to ensure that the markdown is consistent, free of bugs, and works well across different markdown parsers.
These packages are quite good at checking markdown. They especially shine when combined with other remark plugins and at letting you make your own rules.
Presets are combinations of rules configured to check for certain styles. The following presets only contain lint rules but you can make your own that include any remark plugins or other presets. The presets that are maintained here:
remark-preset-lint-consistent
— rules that enforce consistencyremark-preset-lint-markdown-style-guide
— rules that enforce the markdown style guideremark-preset-lint-recommended
— rules that prevent mistakes or stuff that fails across vendors.
The rules that are maintained here:
remark-lint-blockquote-indentation
— warn when block quotes are either indented too much or too littleremark-lint-checkbox-character-style
— warn when list item checkboxes violate a given styleremark-lint-checkbox-content-indent
— warn when list item checkboxes are followed by too much whitespaceremark-lint-code-block-style
— warn when code blocks do not adhere to a given styleremark-lint-definition-case
— warn when definition labels are not lowercaseremark-lint-definition-spacing
— warn when consecutive whitespace is used in a definitionremark-lint-emphasis-marker
— warn when emphasis markers violate the given styleremark-lint-fenced-code-flag
— warn when fenced code blocks occur without language flagremark-lint-fenced-code-marker
— warn when fenced code markers violate the given styleremark-lint-file-extension
— warn when the file’s extension violates the given styleremark-lint-final-definition
— warn when definitions are not placed at the end of the fileremark-lint-final-newline
— warn when a newline at the end of a file is missingremark-lint-first-heading-level
— warn when the first heading has a level other than a specified valueremark-lint-hard-break-spaces
— warn when too many spaces are used to create a hard breakremark-lint-heading-increment
— warn when headings increment with more than 1 level at a timeremark-lint-heading-style
— warn when heading style violates the given styleremark-lint-linebreak-style
— warn when linebreaks violate a given or detected styleremark-lint-link-title-style
— warn when link and definition titles occur with incorrect quotesremark-lint-list-item-bullet-indent
— warn when list item bullets are indentedremark-lint-list-item-content-indent
— warn when the content of a list item has mixed indentationremark-lint-list-item-indent
— warn when the spacing between a list item’s bullet and its content violates a given styleremark-lint-list-item-spacing
— warn when list looseness is incorrectremark-lint-maximum-heading-length
— warn when headings are too longremark-lint-maximum-line-length
— warn when lines are too longremark-lint-no-blockquote-without-marker
— warn when blank lines without markers (`>`) are found in a block quoteremark-lint-no-consecutive-blank-lines
— warn for too many consecutive blank linesremark-lint-no-duplicate-defined-urls
— warn on definitions that define the same urlsremark-lint-no-duplicate-definitions
— warn on duplicate definitionsremark-lint-no-duplicate-headings
— warn on duplicate headingsremark-lint-no-duplicate-headings-in-section
— warn on duplicate headings in a sectionremark-lint-no-emphasis-as-heading
— warn when emphasis or importance is used instead of a headingremark-lint-no-empty-url
— warn on empty URLs in links and imagesremark-lint-no-file-name-articles
— warn when file name start with an articleremark-lint-no-file-name-consecutive-dashes
— warn when file names contain consecutive dashesremark-lint-no-file-name-irregular-characters
— warn when file names contain irregular charactersremark-lint-no-file-name-mixed-case
— warn when file names use mixed caseremark-lint-no-file-name-outer-dashes
— warn when file names contain initial or final dashesremark-lint-no-heading-content-indent
— warn when heading content is indentedremark-lint-no-heading-indent
— warn when headings are indentedremark-lint-no-heading-like-paragraph
— for too many hashes (h7+ “headings”)remark-lint-no-heading-punctuation
— warn when headings end in illegal charactersremark-lint-no-html
— warn when HTML nodes are usedremark-lint-no-inline-padding
— warn when inline nodes are padded with spacesremark-lint-no-literal-urls
— warn when URLs without angle brackets are usedremark-lint-no-missing-blank-lines
— warn when missing blank linesremark-lint-no-multiple-toplevel-headings
— warn when multiple top level headings are usedremark-lint-no-paragraph-content-indent
— warn when the content in paragraphs are indentedremark-lint-no-reference-like-url
— warn when URLs are also defined identifiersremark-lint-no-shell-dollars
— warn when shell code is prefixed by dollarsremark-lint-no-shortcut-reference-image
— warn when shortcut reference images are usedremark-lint-no-shortcut-reference-link
— warn when shortcut reference links are usedremark-lint-no-table-indentation
— warn when tables are indentedremark-lint-no-tabs
— warn when hard tabs are used instead of spacesremark-lint-no-undefined-references
— warn when references to undefined definitions are foundremark-lint-no-unneeded-full-reference-image
— warn when full reference images are used if they can be collapsedremark-lint-no-unneeded-full-reference-link
— warn when full reference links are used if they can be collapsedremark-lint-no-unused-definitions
— warn when unused definitions are foundremark-lint-ordered-list-marker-style
— warn when the markers of ordered lists violate a given styleremark-lint-ordered-list-marker-value
— warn when the marker value of ordered lists violates a given styleremark-lint-rule-style
— warn when horizontal rules violate a given styleremark-lint-strikethrough-marker
— warn when strikethrough markers violate the given styleremark-lint-strong-marker
— warn when importance (strong) markers violate the given styleremark-lint-table-cell-padding
— warn when table cells are incorrectly paddedremark-lint-table-pipe-alignment
— warn when table pipes are not alignedremark-lint-table-pipes
— warn when table rows are not fenced with pipesremark-lint-unordered-list-marker-style
— warn when markers of unordered lists violate a given style
You can make and share your own rules, which can be used just like the rules maintained here. The following rules are maintained by the community:
remark-lint-alphabetize-lists
— ensure list items are in alphabetical orderremark-lint-appropriate-heading
— check that the top level heading matches the directory nameremark-lint-blank-lines-1-0-2
— ensure a specific number of lines between blocksremark-lint-books-links
— ensure links in lists of books follow a standard formatremark-lint-code
— lint fenced code blocks by corresponding language tags, currently supporting ESLintremark-lint-match-punctuation
— ensures punctuations are used in pairs if necessary.remark-lint-mdash-style
— ensure em-dash (—
) style follows a standard formatremark-lint-no-chinese-punctuation-in-number
— ensures that Chinese punctuation’s not used in numbersremark-lint-no-dead-urls
— check that external links are aliveremark-lint-no-long-code
— ensures that each line in code block won't be too long.remark-lint-no-repeat-punctuation
— ensures punctuation is not repeatedremark-lint-emoji-limit
— enforce a limit of emoji per paragraphremark-lint-no-empty-sections
— ensure every heading is followed by content (forming a section)remark-lint-frontmatter-schema
— validate YAML frontmatter against a JSON schemaremark-lint-heading-length
— ensure headings have the appropriate lengthremark-lint-heading-whitespace
— ensure heading parsing is not broken by weird whitespaceremark-lint-are-links-valid
— check if your links are reachable and/or uniqueremark-lint-spaces-around-number
— ensures there are spaces around number and Chinese.remark-lint-spaces-around-word
— ensures there are spaces around English word and Chinese.remark-lint-no-url-trailing-slash
— ensure that thehref
of links has no trailing slashremark-lint-write-good
— wrapper forwrite-good
remark-lint-double-link
— ensure the same URL is not linked multiple times.
For help creating your own rule, it’s suggested to look at existing rules and to follow this tutorial.
All rules can be configured in one standard way:
import {remark} from 'remark'
import remarkLintFinalNewline from 'remark-lint-final-newline'
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length'
import remarkLintUnorderedListMarkerStyle from 'remark-lint-unordered-list-marker-style'
remark()
// Pass `false` to turn a rule off — the code no longer runs:
.use(remarkLintFinalNewline, false)
// Pass `true` to turn a rule on again:
.use(remarkLintFinalNewline, true)
// You can also configure whether messages by the rule should be ignored,
// are seen as code style warnings (default), or are seen as exceptions.
// Ignore messages with `'off'` or `0` as the first value of an array:
.use(remarkLintFinalNewline, ['off'])
.use(remarkLintFinalNewline, [0])
// Use `'warn'`, `'on'`, or `1` to treat messages as code style warnings:
.use(remarkLintFinalNewline, ['warn'])
.use(remarkLintFinalNewline, ['on'])
.use(remarkLintFinalNewline, [1])
// Use `'error'` or `2` to treat messages as exceptions:
.use(remarkLintFinalNewline, ['error'])
.use(remarkLintFinalNewline, [2])
// Some rules accept options, and what they exactly accept is different for
// each rule (sometimes a string, a number, or an object).
// The following rule accepts a string:
.use(remarkLintUnorderedListMarkerStyle, '*')
.use(remarkLintUnorderedListMarkerStyle, ['on', '*'])
.use(remarkLintUnorderedListMarkerStyle, [1, '*'])
// The following rule accepts a number:
.use(remarkLintMaximumLineLength, 72)
.use(remarkLintMaximumLineLength, ['on', 72])
.use(remarkLintMaximumLineLength, [1, 72])
See use()
in unified
s readme for more info on how to use
plugins.
🧑🏫 Info: messages in
remark-lint
are warnings instead of errors. Other linters (such as ESLint) almost always use errors. Why? Those tools only check code style. They don’t generate, transform, and format code, which is what remark and unified focus on, too. Errors in unified mean the same as an exception in your JavaScript code: a crash. That’s why we use warnings instead, because we continue checking more markdown and continue running more plugins.
You can use HTML comments to hide or show warnings from within markdown.
Turn off all remark lint messages with <!--lint disable-->
and turn them on
again with <!--lint enable-->
:
<!--lint disable-->
[Naiad]: https://naiad.neptune
[Thalassa]: https://thalassa.neptune
<!--lint enable-->
You can toggle specific rules by using their names without remark-lint-
:
<!--lint disable no-unused-definitions definition-case-->
[Naiad]: https://naiad.neptune
[Thalassa]: https://thalassa.neptune
<!--lint enable no-unused-definitions definition-case-->
You can ignore a message in the next block with <!--lint ignore-->
:
<!--lint ignore-->
[Naiad]: https://naiad.neptune
ignore
also accepts a list of rules:
<!--lint ignore no-unused-definitions definition-case-->
[Naiad]: https://naiad.neptune
👉 Note: you’ll typically need blank lines between HTML comments and other constructs. More info is available at the package that handles comments,
remark-message-control
.
💡 Tip: MDX comments are supported when
remark-mdx
is used:{/* lint ignore no-unused-definitions definition-case */}
The following example checks that markdown code style is consistent and follows some best practices. It also reconfigures a rule. First install dependencies:
npm install vfile-reporter remark remark-preset-lint-consistent remark-preset-lint-recommended remark-lint-list-item-indent --save-dev
Then create a module example.js
that contains:
import {reporter} from 'vfile-reporter'
import {remark} from 'remark'
import remarkPresetLintConsistent from 'remark-preset-lint-consistent'
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
import remarkLintListItemIndent from 'remark-lint-list-item-indent'
main()
async function main() {
const file = await remark()
// Check that markdown is consistent.
.use(remarkPresetLintConsistent)
// Few recommended rules.
.use(remarkPresetLintRecommended)
// `remark-lint-list-item-indent` is configured with `tab-size` in the
// recommended preset, but if we’d prefer something else, it can be
// reconfigured:
.use(remarkLintListItemIndent, 'space')
.process('1) Hello, _Jupiter_ and *Neptune*!')
console.error(reporter(file))
}
Running that with node example.js
yields:
1:1 warning Missing newline character at end of file final-newline remark-lint
1:1-1:35 warning Marker style should be `.` ordered-list-marker-style remark-lint
1:25-1:34 warning Emphasis should use `_` as a marker emphasis-marker remark-lint
⚠ 3 warnings
remark lint rules check markdown.
remark-stringify
(used in remark) formats markdown.
When you configure lint rules and use remark to format markdown, you must
manually synchronize their configuration:
import {reporter} from 'vfile-reporter'
import {remark} from 'remark'
import remarkLintEmphasisMarker from 'remark-lint-emphasis-marker'
import remarkLintStrongMarker from 'remark-lint-strong-marker'
main()
async function main() {
const file = await remark()
.use(remarkLintEmphasisMarker, '*')
.use(remarkLintStrongMarker, '*')
.use({
settings: {emphasis: '*', strong: '*'} // `remark-stringify` settings.
})
.process('_Hello_, __world__!')
console.error(reporter(file))
console.log(String(file))
}
Yields:
1:1-1:8 warning Emphasis should use `*` as a marker emphasis-marker remark-lint
1:10-1:19 warning Strong should use `*` as a marker strong-marker remark-lint
⚠ 2 warnings
*Hello*, **world**!
Observe that the lint rules check the input and afterwards remark formats using asterisks. If that output was given the the processor, the lint rules would be satisfied.
This example checks markdown with remark-cli
.
It assumes you’re in a Node.js package.
First install dependencies:
npm install remark-cli remark-preset-lint-consistent remark-preset-lint-recommended remark-lint-list-item-indent --save-dev
Then add an npm script to your package.json
:
/* … */
"scripts": {
/* … */
"check": "remark . --quiet --frail",
/* … */
},
/* … */
💡 Tip: add ESLint and such in the
check
script too.
Observe that the above change adds a check
script, which can be run with
npm run check
.
It runs remark on all markdown files (.
), shows only warnings and errors
(--quiet
), and exits as failed on warnings (--frail
).
Run ./node_modules/.bin/remark --help
for more info on the CLI.
Now add a remarkConfig
to your package.json
to configure remark:
/* … */
"remarkConfig": {
"plugins": [
"remark-preset-lint-consistent", // Check that markdown is consistent.
"remark-preset-lint-recommended", // Few recommended rules.
// `remark-lint-list-item-indent` is configured with `tab-size` in the
// recommended preset, but if we’d prefer something else, it can be
// reconfigured:
[
"remark-lint-list-item-indent",
"space"
]
]
},
/* … */
👉 Note: you must remove the comments in the above examples when copy/pasting them, as comments are not supported in
package.json
files.
Finally run the npm script to check markdown files in your project:
npm run check
remark lint rules check markdown. The CLI can format markdown. You can combine these features but have to manually synchronize their configuration. Please first follow the previous example (checking markdown on the CLI) and then change the npm script:
/* … */
"scripts": {
/* … */
"format": "remark . --quiet --frail --output",
/* … */
},
/* … */
The script is now called format
to reflect what it does.
It now includes an --output
flag, which means it will overwrite existing files
with changes.
Update remarkConfig
:
/* … */
"remarkConfig": {
"settings": {
"emphasis": "*",
"strong": "*"
},
"plugins": [
"remark-preset-lint-consistent",
"remark-preset-lint-recommended",
["remark-lint-list-item-indent", "space"]
["remark-lint-emphasis-marker", "*"],
["remark-lint-strong-marker", "*"]
]
},
/* … */
This now includes settings
, which configures
remark-stringify
, and explicitly prefers asterisks
for emphasis and strong.
Install the new dependencies:
npm install remark-lint-emphasis-marker remark-lint-strong-marker --save-dev
Finally run the npm script to format markdown files in your project:
npm run format
👉 Note: running
npm run format
now checks and formats your files. The first time you run it, assuming you have underscores for emphasis and strong, it would first warn and then format. The second time you run it, no warnings should appear.
vscode-remark-lint
(VS Code) — useremark-lint
from Visual Studio CodeSublimeLinter-contrib-remark-lint
(Sublime) — useremark-lint
from Sublime Textale
(Vim) — useremark-lint
from Vimjest-runner-remark
(Jest) — use remark with Jest
Markdown is parsed by remark-parse
(included in remark
)
according to CommonMark.
You can combine it with other plugins to add syntax extensions.
Notable examples that deeply integrate with it are
remark-gfm
,
remark-mdx
,
remark-frontmatter
,
remark-math
, and
remark-directive
.
Projects maintained by the unified collective are compatible with all maintained versions of Node.js. As of now, that is Node.js 12.20+, 14.14+, and 16.0+. Our projects sometimes work with older versions, but this is not guaranteed.
Use of remark-lint
does not change the tree so there are no openings for
cross-site scripting (XSS) attacks.
Messages from linting rules may be hidden from user content though, causing
builds to fail or pass.
See contributing.md
in remarkjs/.github
for ways
to get started.
See support.md
for ways to get help.
This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.