9 KiB
markdownlint
A Node.js style checker and lint tool for Markdown files.
Install
npm install markdownlint --save-dev
Overview
The Markdown markup language is designed to be easy to read, write, and understand. It succeeds - and its flexibility is both a benefit and a drawback. Many styles are possible, so formatting can be inconsistent. Some constructs don't work well in all parsers and should be avoided.
markdownlint
is a static analysis
tool for Node.js and io.js with a
library of rules to enforce standards and consistency for Markdown files. It
was inspired by - and heavily influenced by - Mark Harrison's
markdownlint for
Ruby. The rules, rule documentation, and test
cases come directly from that project.
If you need a Ruby implementation or a CLI, please consider the mdl gem.
Rules
- MD001 - Header levels should only increment by one level at a time
- MD002 - First header should be a h1 header
- MD003 - Header style
- MD004 - Unordered list style
- MD005 - Inconsistent indentation for list items at the same level
- MD006 - Consider starting bulleted lists at the beginning of the line
- MD007 - Unordered list indentation
- MD009 - Trailing spaces
- MD010 - Hard tabs
- MD011 - Reversed link syntax
- MD012 - Multiple consecutive blank lines
- MD013 - Line length
- MD014 - Dollar signs used before commands without showing output
- MD018 - No space after hash on atx style header
- MD019 - Multiple spaces after hash on atx style header
- MD020 - No space inside hashes on closed atx style header
- MD021 - Multiple spaces inside hashes on closed atx style header
- MD022 - Headers should be surrounded by blank lines
- MD023 - Headers must start at the beginning of the line
- MD024 - Multiple headers with the same content
- MD025 - Multiple top level headers in the same document
- MD026 - Trailing punctuation in header
- MD027 - Multiple spaces after blockquote symbol
- MD028 - Blank line inside blockquote
- MD029 - Ordered list item prefix
- MD030 - Spaces after list markers
- MD031 - Fenced code blocks should be surrounded by blank lines
- MD032 - Lists should be surrounded by blank lines
See Rules.md for more details.
Tags
- atx - MD018, MD019
- atx_closed - MD020, MD021
- blank_lines - MD012, MD022, MD031, MD032
- blockquote - MD027, MD028
- bullet - MD004, MD005, MD006, MD007, MD032
- code - MD014, MD031
- hard_tab - MD010
- headers - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026
- indentation - MD005, MD006, MD007, MD027
- line_length - MD013
- links - MD011
- ol - MD029, MD030, MD032
- spaces - MD018, MD019, MD020, MD021, MD023
- ul - MD004, MD005, MD006, MD007, MD030, MD032
- whitespace - MD009, MD010, MD012, MD027, MD028, MD030
API
Standard asynchronous interface:
/**
* Lint specified Markdown files according to configurable rules.
*
* @param {Object} options Configuration options.
* @param {Function} callback Callback (err, result) function.
* @returns {void}
*/
function markdownlint(options, callback) { ... }
Synchronous interface (for build scripts, etc.):
/**
* Lint specified Markdown files according to configurable rules.
*
* @param {Object} options Configuration options.
* @returns {Object} Result object.
*/
function markdownlint.sync(options) { ... }
options
Type: Object
Configures the function.
options.files
Type: Array
of String
List of files to lint.
Each array element should be a single file (via relative or absolute path); globbing is the caller's responsibility.
Example: [ "one.md", "dir/two.md" ]
options.config
Type: Object
mapping String
to Boolean | Object
Configures the rules to use.
Object keys are rule names and values are the rule's configuration.
The value false
disables a rule, true
enables its default configuration,
and passing an object customizes its settings. Setting the special default
rule to true
or false
includes/excludes all rules by default. Enabling or
disabling a tag name (ex: whitespace
) affects all rules having that tag.
The default
rule is applied first, then keys are processed in order from top
to bottom with later values overriding earlier ones.
Example:
{
"default": true,
"MD003": { "style": "atx_closed" },
"MD007": { "indent": 4 },
"MD009": false,
"whitespace": false
}
Sets of rules (known as a "style") can be stored separately and loaded as JSON.
Example:
var options = {
"files": [ "..." ],
"config": require("style/relaxed.json")
};
See the style directory for more samples.
callback
Type: Function
taking (Error
, Object
)
Standard completion callback.
result
Type: Object
Call result.toString()
for convenience or see below for an example of the
structure of the result
object.
Usage
Invoke markdownlint
and use the result
object's toString
method:
var markdownlint = require("markdownlint");
var options = {
"files": [ "good.md", "bad.md" ]
};
markdownlint(options, function callback(err, result) {
if (!err) {
console.log(result.toString());
}
});
Or invoke markdownlint.sync
for a synchronous call:
var result = markdownlint.sync(options);
console.log(result.toString());
Output of both calls:
bad.md: 3: MD010 Hard tabs
bad.md: 1: MD018 No space after hash on atx style header
bad.md: 3: MD018 No space after hash on atx style header
To examine the result
object directly:
markdownlint(options, function callback(err, result) {
if (!err) {
console.dir(result, { "colors": true });
}
});
Output:
{
"good.md": {},
"bad.md": {
"MD010": [ 3 ],
"MD018": [ 1, 3 ]
}
}
Integration with the gulp build system is straightforward:
var gulp = require("gulp");
var through2 = require("through2");
var markdownlint = require("markdownlint");
gulp.task("markdownlint", function task() {
return gulp.src("*.md", { "read": false })
.pipe(through2.obj(function obj(file, enc, next) {
markdownlint(
{ "files": [ file.relative ] },
function callback(err, result) {
var resultString = (result || "").toString();
if (resultString) {
console.log(resultString);
}
next(err, file);
});
}));
});
Output:
[00:00:00] Starting 'markdownlint'...
bad.md: 3: MD010 Hard tabs
bad.md: 1: MD018 No space after hash on atx style header
bad.md: 3: MD018 No space after hash on atx style header
[00:00:00] Finished 'markdownlint' after 10 ms
Integration with the Grunt build system is similar:
var markdownlint = require("markdownlint");
module.exports = function wrapper(grunt) {
grunt.initConfig({
"markdownlint": {
"example": {
"src": [ "*.md" ]
}
}
});
grunt.registerMultiTask("markdownlint", function task() {
var done = this.async();
markdownlint(
{ "files": this.filesSrc },
function callback(err, result) {
var resultString = err || ((result || "").toString());
if (resultString) {
grunt.fail.warn("\n" + resultString + "\n");
}
done(!err || !resultString);
});
});
};
Output:
Running "markdownlint:example" (markdownlint) task
Warning:
bad.md: 3: MD010 Hard tabs
bad.md: 1: MD018 No space after hash on atx style header
bad.md: 3: MD018 No space after hash on atx style header
Use --force to continue.
Release History
- 0.0.1 - Initial release.
- 0.0.2 - Improve documentation, tests, and code.
- 0.0.3 - Add synchronous API, improve documentation and code.