/remark-lint

Markdown code style linter

Primary LanguageJavaScriptMIT LicenseMIT

remark-lint

Build Status Coverage Status Chat

remark-lint is a markdown code style linter. Another linter? Yes. Ensuring the markdown you (and contributors) write is of great quality will provide better rendering in all the different markdown parsers, and makes sure less refactoring is needed afterwards.

What is quality? That’s up to you, but there are sensible presets.

remark-lint is built on remark, a powerful markdown processor powered by plugins (such as this one).

Table of Contents

Installation

npm:

npm install remark-lint

Command line

Example of how remark-lint looks on screen

Use remark-lint with remark-cli, and a preset.

npm install --save remark-cli remark-preset-lint-recommended

Then, configure remark in your package.json:

  // ...
  "scripts": {
    "lint-md": "remark ."
  },
  // ...
  "remarkConfig": {
    "plugins": ["remark-preset-lint-recommended"]
  }
  // ...

Let’s say there’s an example.md, which looks as follows:

* Hello

[World][]

Now, running our lint-md script with npm, npm run lint-md, yields:

example.md
       1:3  warning  Incorrect list-item indent: add 2 spaces  list-item-indent
  3:1-3:10  warning  Found reference to undefined definition   no-undefined-references
⚠ 2 warnings

See doc/rules.md for what those warnings are (and how to turn them off).

Programmatic

Use remark-lint together with remark:

npm install remark remark-lint remark-lint-first-heading-level

Let’s say example.js looks as follows:

var report = require('vfile-reporter');
var remark = require('remark');
var styleGuide = require('remark-preset-lint-markdown-style-guide');

var file = remark().use(styleGuide).processSync('_Hello world_');

console.log(report(file));

Now, running node example.js yields:

  1:1-1:14  warning  Emphasis should use `*` as a marker  emphasis-marker  remark-lint

⚠ 1 warning

Rules

doc/rules.md lists all available official rules.

Configuring remark-lint

remark-lint is a remark plug-in and supports configuration through its configuration files.

An example .remarkrc file could look as follows:

{
  "plugins": [
    "remark-preset-lint-recommended",
    ["remark-lint-list-item-indent", false]
  ]
}

Where the object at plugins.lint is a map of ruleIds and their values, which precede over presets.

Using our example.md from before:

* Hello

[World][]

Now, running npm run lint-md yields:

example.md
   3:1-3:10  warning  Found reference to undefined definition   no-undefined-references

⚠ 2 warnings

In addition, you can also provide configuration comments to turn a rule on or off inside a file. Note that you cannot change what a setting, such as maximum-line-length, just whether they are shown or not. Read more about configuration comments in remark-message-controls documentation.

The following file will warn twice for the duplicate headings:

# Hello

## Hello

### Hello

The following file will warn once (the second heading is ignored, but the third is re-enabled):

# Hello

<!--lint disable no-duplicate-headings-->

## Hello

<!--lint enable no-duplicate-headings-->

### Hello

Note: You’ll need the blank lines between comments and other nodes!

Using remark to fix your markdown

remark-stringify can format markdown syntax. It ensures a single style is used: list items use one type of bullet (*, -, +), emphasis (* or _) and importance (__ or **) use a standard marker, table fences are aligned, and more.

Example

If you require('remark'), remark-stringify is included unless an output format other than markdown (such as HTML) is defined.

Say we have the following file, example.js, showing how formatting rules can be used:

var report = require('vfile-reporter');
var remark = require('remark');
var emphasisMarker = require('remark-lint-emphasis-marker');
var strongMarker = require('remark-lint-strong-marker');

remark()
  .use(emphasisMarker, '*')
  .use(strongMarker, '*')
  // ^ two `remark-lint` rules.
  .use({
    settings: {emphasis: '*', strong: '*'}
    // ^ `remark-stringify` settings.
  })
  .process('_Hello_, __world__!', function (err, file) {
    console.error(report(err || file));
    console.log(String(file));
  });

Now, running node example yields warnings and a formatted file:

    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**!
Example

If you’re using remark-stringify yourself, you can pass options like any other plugin, like so:

var report = require('vfile-reporter');
var unified = require('unified');
var parse = require('remark-parse');
var stringify = require('remark-stringify');
var emphasisMarker = require('remark-lint-emphasis-marker');
var strongMarker = require('remark-lint-strong-marker');

unified()
  .use(parse)
  .use(emphasisMarker, '*')
  .use(strongMarker, '*')
  // ^ two `remark-lint` rules.
  .use(stringify, {emphasis: '*', strong: '*'})
  // ^ `remark-stringify` with settings.
  .process('_Hello_, __world__!', function (err, file) {
    console.error(report(err || file));
    console.log(String(file));
  });

Now, when running node example, this results in the same output as the previous example.

Example

If you’re using remark-cli, remark-stringify is included unless an output format other than markdown (such as HTML) is defined. In this case you can configure remark-stringify settings using the -s, --settings flag or a "settings" property in remark configuration files.

Say we have the following file, example.md:

_Hello_, __world__!

And our package.json looks as follows:

  // ...
  "remarkConfig": {
    "settings": {
      "emphasis": "*",
      "strong": "*"
    },
    "plugins": [
      "remark-lint-emphasis-marker",
      "remark-lint-strong-marker"
    ]
  }
  // ...

Now, running remark example.md yields warnings and a formatted file:

*Hello*, **world**!
example.md
    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

Note: running remark example.md -o or remark example.md --output overwrites example.md and formats it. So, if you’d run that twice (the first pass lints and fixes the markdown, the second pass checks it again), you’d see the output example.md: written as all warnings are now fixed.

Editor Integrations

Currently, remark-lint is integrated with Atom through linter-markdown.

If you want to run all of remark from Atom, use linter-remark.

To run remark, optionally with remark-lint from Gulp, use gulp-remark.

I’m very interested in more integrations. Let me know if I can help.

List of Presets

Presets can be loaded through the preset setting.

List of External Rules

External rules can be loaded just like normal rules.

⚠️ means the rule has not been updated for remark-lint 6.0.0.

Related

License

MIT © Titus Wormer