2015-03-12 23:42:06 -07:00
|
|
|
# markdownlint
|
|
|
|
|
2015-03-14 22:34:28 -07:00
|
|
|
> A Node.js style checker and lint tool for Markdown files.
|
2015-03-12 23:42:06 -07:00
|
|
|
|
2015-03-17 22:58:26 -07:00
|
|
|
[![npm version][npm-image]][npm-url]
|
|
|
|
[![GitHub tag][github-tag-image]][github-tag-url]
|
|
|
|
[![Build status][travis-image]][travis-url]
|
|
|
|
[![Coverage][coveralls-image]][coveralls-url]
|
|
|
|
[![License][license-image]][license-url]
|
|
|
|
|
2015-03-12 23:42:06 -07:00
|
|
|
## Install
|
|
|
|
|
|
|
|
```shell
|
|
|
|
npm install markdownlint --save-dev
|
|
|
|
```
|
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
|
|
|
The [Markdown](http://en.wikipedia.org/wiki/Markdown) markup language is
|
2015-03-14 22:34:28 -07:00
|
|
|
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.
|
2015-03-12 23:42:06 -07:00
|
|
|
|
|
|
|
`markdownlint` is a [static analysis](http://en.wikipedia.org/wiki/Static_program_analysis)
|
|
|
|
tool for [Node.js](https://nodejs.org/) and [io.js](https://iojs.org/) with a
|
2015-03-14 22:34:28 -07:00
|
|
|
library of rules to enforce standards and consistency for Markdown files. It
|
|
|
|
was inspired by - and heavily influenced by - Mark Harrison's
|
|
|
|
[markdownlint](https://github.com/mivok/markdownlint) for
|
|
|
|
[Ruby](https://www.ruby-lang.org/). The rules, rule documentation, and test
|
|
|
|
cases come directly from that project.
|
2015-03-12 23:42:06 -07:00
|
|
|
|
2015-03-14 22:34:28 -07:00
|
|
|
> If you need a Ruby implementation or a [CLI](http://en.wikipedia.org/wiki/Command-line_interface),
|
|
|
|
> please consider the [mdl](https://rubygems.org/gems/mdl) gem.
|
2015-03-12 23:42:06 -07:00
|
|
|
|
|
|
|
## Rules
|
|
|
|
|
2015-03-16 22:31:18 -07:00
|
|
|
* **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
|
2015-03-14 22:34:28 -07:00
|
|
|
|
|
|
|
See [Rules.md](doc/Rules.md) for more details.
|
2015-03-12 23:42:06 -07:00
|
|
|
|
2015-03-16 22:31:18 -07:00
|
|
|
## 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
|
2015-03-17 22:34:47 -07:00
|
|
|
* **hard_tab** - MD010
|
2015-03-16 22:31:18 -07:00
|
|
|
* **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
|
|
|
|
|
2015-03-15 23:39:17 -07:00
|
|
|
## API
|
|
|
|
|
|
|
|
```js
|
|
|
|
/**
|
|
|
|
* 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) { ... }
|
|
|
|
```
|
|
|
|
|
|
|
|
### 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](http://en.wikipedia.org/wiki/Glob_%28programming%29) is the caller's
|
|
|
|
responsibility.
|
|
|
|
|
|
|
|
Example: `[ "one.md", "dir/two.md" ]`
|
|
|
|
|
|
|
|
#### options.config
|
|
|
|
|
2015-03-16 22:31:18 -07:00
|
|
|
Type: `Object` mapping `String` to `Boolean | Object`
|
2015-03-15 23:39:17 -07:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
```json
|
|
|
|
{
|
|
|
|
"default": true,
|
|
|
|
"MD007": {
|
|
|
|
"indent": 4
|
|
|
|
},
|
|
|
|
"MD013": {
|
|
|
|
"line_length": 100
|
|
|
|
},
|
|
|
|
"MD029": false
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### callback
|
|
|
|
|
|
|
|
Type: `Function` taking (`Error`, `Object`)
|
|
|
|
|
|
|
|
Function to call upon completion.
|
|
|
|
|
|
|
|
See below for an example of the structure of the `result` object.
|
|
|
|
|
2015-03-12 23:42:06 -07:00
|
|
|
## Usage
|
|
|
|
|
2015-03-14 22:34:28 -07:00
|
|
|
Invoke `markdownlint` and use the `result` object's `toString` method:
|
2015-03-12 23:42:06 -07:00
|
|
|
|
|
|
|
```js
|
2015-03-14 23:47:34 -07:00
|
|
|
var markdownlint = require("markdownlint");
|
2015-03-14 22:34:28 -07:00
|
|
|
|
|
|
|
var options = {
|
|
|
|
"files": [ "good.md", "bad.md" ]
|
|
|
|
};
|
|
|
|
|
|
|
|
markdownlint(options, function callback(err, result) {
|
|
|
|
if (!err) {
|
|
|
|
console.log(result.toString());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
```text
|
|
|
|
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
|
|
|
|
```
|
|
|
|
|
|
|
|
Or examine the `result` object directly:
|
|
|
|
|
|
|
|
```js
|
|
|
|
markdownlint(options, function callback(err, result) {
|
|
|
|
if (!err) {
|
|
|
|
console.dir(result, { "colors": true });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
```json
|
|
|
|
{
|
2015-03-16 22:31:18 -07:00
|
|
|
"good.md": {},
|
|
|
|
"bad.md": {
|
|
|
|
"MD010": [ 3 ],
|
|
|
|
"MD018": [ 1, 3 ]
|
2015-03-14 22:34:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Integration with the [gulp](http://gulpjs.com/) build system is straightforward:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var gulp = require("gulp");
|
|
|
|
var through2 = require("through2");
|
2015-03-14 23:47:34 -07:00
|
|
|
var markdownlint = require("markdownlint");
|
2015-03-14 22:34:28 -07:00
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
```text
|
|
|
|
[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
|
2015-03-12 23:42:06 -07:00
|
|
|
```
|
|
|
|
|
2015-03-14 23:47:34 -07:00
|
|
|
Integration with the [Grunt](http://gruntjs.com/) build system is similar:
|
|
|
|
|
|
|
|
```js
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
```text
|
|
|
|
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.
|
|
|
|
```
|
|
|
|
|
2015-03-12 23:42:06 -07:00
|
|
|
## Release History
|
|
|
|
|
|
|
|
* 0.0.1 - Initial release.
|
2015-03-17 23:05:37 -07:00
|
|
|
* 0.0.2 - Improve documentation, tests, and code.
|
2015-03-17 22:58:26 -07:00
|
|
|
|
|
|
|
[npm-image]: https://img.shields.io/npm/v/markdownlint.svg
|
|
|
|
[npm-url]: https://www.npmjs.com/package/markdownlint
|
|
|
|
[github-tag-image]: https://img.shields.io/github/tag/DavidAnson/markdownlint.svg
|
|
|
|
[github-tag-url]: https://github.com/DavidAnson/markdownlint
|
|
|
|
[travis-image]: https://img.shields.io/travis/DavidAnson/markdownlint.svg
|
|
|
|
[travis-url]: https://travis-ci.org/DavidAnson/markdownlint
|
|
|
|
[coveralls-image]: https://img.shields.io/coveralls/DavidAnson/markdownlint.svg
|
|
|
|
[coveralls-url]: https://coveralls.io/r/DavidAnson/markdownlint
|
|
|
|
[license-image]: https://img.shields.io/npm/l/markdownlint.svg
|
|
|
|
[license-url]: http://opensource.org/licenses/MIT
|