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-recommendedWe would get a report like this:
doc/example.md
1:2 warning Unexpected ordered list marker `)`, expected `.` ordered-list-marker-style remark-lint
1:25-1:34 warning Unexpected emphasis marker `*`, expected `_` emphasis-marker remark-lint
[cause]:
1:11-1:20 info Emphasis marker style `'_'` first defined for `'consistent'` here emphasis-marker remark-lint
β 2 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β check whitespace after block quote markersremark-lint-checkbox-character-styleβ check list item checkbox charactersremark-lint-checkbox-content-indentβ warn when too much whitespace follows list item checkboxesremark-lint-code-block-styleβ warn when code blocks do not adhere to a given styleremark-lint-correct-media-syntaxβ check for accidental bracket and paren mixup for images and linksremark-lint-definition-caseβ warn when definition labels are not lowercaseremark-lint-definition-sortβ check definition orderremark-lint-definition-spacingβ warn when consecutive whitespace is used in a definitionremark-lint-directive-attribute-sortβ check directive attribute orderremark-lint-directive-collapsed-attributeβ check that collapsed attributes are used in directivesremark-lint-directive-quote-styleβ check quotes of directive attributesremark-lint-directive-shortcut-attributeβ check that shortcut attributes are used in directivesremark-lint-directive-unique-attribute-nameβ check that attribute names are uniqueremark-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β check the spacing between list item bullets and contentremark-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-mdx-jsx-attribute-sortβ check mdx jsx attribute orderremark-lint-mdx-jsx-no-void-childrenβ check mdx jsx quotesremark-lint-mdx-jsx-quote-styleβ check mdx jsx quotesremark-lint-mdx-jsx-self-closeβ check that self-closing tags are used when possibleremark-lint-mdx-jsx-shorthand-attributeβ check that shorthand attributes are used in MDX JSXremark-lint-mdx-jsx-unique-attribute-nameβ check that mdx jsx attributes are uniqueremark-lint-media-styleβ check whether references or resources are usedremark-lint-no-blockquote-without-markerβ warn when block quotes have blank lines without markersremark-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-hidden-table-cellβ check superfluous table cellsremark-lint-no-htmlβ warn when HTML nodes are usedremark-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β check that full reference images can be collapsedremark-lint-no-unneeded-full-reference-linkβ check that full reference links 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β check the marker value of ordered listsremark-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-are-links-validβ check if your links are reachable and/or uniqueremark-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-check-tocβ ensure TOC is correctremark-lint-codeβ lint fenced code blocks by corresponding language tags, currently supporting ESLintremark-lint-code-block-split-listβ ensure code block inside list doesn't split the listremark-lint-double-linkβ ensure the same URL is not linked multiple times.remark-lint-emoji-limitβ enforce a limit of emoji per paragraphremark-lint-fenced-code-flag-caseβ warn when fenced code blocks have improperly cased language flagsremark-lint-frontmatter-schemaβ validate YAML frontmatter against a JSON schemaremark-lint-heading-capitalizationβ ensure headings capitalization is correctremark-lint-heading-lengthβ ensure headings have the appropriate lengthremark-lint-heading-whitespaceβ ensure heading parsing is not broken by weird whitespaceremark-lint-heading-word-lengthβ warn when headings have too many or too few words with unicode supportremark-lint-list-item-styleβ warn when list items violate a given capitalization or punctuation styleremark-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-empty-sectionsβ ensure every heading is followed by content (forming a section)remark-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-no-url-trailing-slashβ ensure that thehrefof links has no trailing slashremark-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-write-goodβ wrapper forwrite-good
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 unifieds readme for more info on how to use
plugins.
π§βπ« Info: messages in
remark-lintare 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.neptuneignore 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-mdxis 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-devThen create a module example.js that contains:
import {remark} from 'remark'
import remarkLintListItemIndent from 'remark-lint-list-item-indent'
import remarkPresetLintConsistent from 'remark-preset-lint-consistent'
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
import {reporter} from 'vfile-reporter'
const file = await remark()
// Check that markdown is consistent.
.use(remarkPresetLintConsistent)
// Few recommended rules.
.use(remarkPresetLintRecommended)
// `remark-lint-list-item-indent` is configured with `one` in the
// recommended preset, but if weβd prefer something else, it can be
// reconfigured:
.use(remarkLintListItemIndent, 'tab')
.process('1) Hello, _Jupiter_ and *Neptune*!')
console.error(reporter(file))Running that with node example.js yields:
1:2 warning Unexpected ordered list marker `)`, expected `.` ordered-list-marker-style remark-lint
1:4 warning Unexpected `1` space between list item marker and content, expected `2` spaces, add `1` space list-item-indent remark-lint
1:25-1:34 warning Unexpected emphasis marker `*`, expected `_` emphasis-marker remark-lint
[cause]:
1:11-1:20 info Emphasis marker style `'_'` first defined for `'consistent'` here emphasis-marker remark-lint
1:35 warning Unexpected missing final newline character, expected line feed (`\n`) at end of file final-newline remark-lint
β 4 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 {remark} from 'remark'
import remarkLintEmphasisMarker from 'remark-lint-emphasis-marker'
import remarkLintStrongMarker from 'remark-lint-strong-marker'
import {reporter} from 'vfile-reporter'
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-devThen add an npm script to your package.json:
/* β¦ */
"scripts": {
/* β¦ */
"check": "remark . --quiet --frail",
/* β¦ */
},
/* β¦ */π‘ Tip: add ESLint and such in the
checkscript 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 `one` in the
// recommended preset, but if weβd prefer something else, it can be
// reconfigured:
[
"remark-lint-list-item-indent",
"tab"
]
]
},
/* β¦ */π Note: you must remove the comments in the above examples when copy/pasting them, as comments are not supported in
package.jsonfiles.
Finally run the npm script to check markdown files in your project:
npm run checkremark 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 . --frail --output --quiet",
/* β¦ */
},
/* β¦ */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", "tab"]
["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-devFinally run the npm script to format markdown files in your project:
npm run formatπ Note: running
npm run formatnow 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-lintfrom Visual Studio CodeSublimeLinter-contrib-remark-lint(Sublime) β useremark-lintfrom Sublime Textale(Vim) β useremark-lintfrom 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 maintained versions of Node.js.
When we cut a new major release, we drop support for unmaintained versions of
Node.
This means we try to keep the current release line, remark-lint@9, compatible
with Node.js 16.
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.
MIT Β© Titus Wormer
