1 | # markdownlint
|
2 |
|
3 | > A Node.js style checker and lint tool for Markdown/CommonMark files.
|
4 |
|
5 | [![npm version][npm-image]][npm-url]
|
6 | [![CI Status][ci-image]][ci-url]
|
7 | [![License][license-image]][license-url]
|
8 |
|
9 | ## Install
|
10 |
|
11 | ```shell
|
12 | npm install markdownlint --save-dev
|
13 | ```
|
14 |
|
15 | ## Overview
|
16 |
|
17 | The [Markdown](https://en.wikipedia.org/wiki/Markdown) markup language
|
18 | is designed to be easy to read, write, and understand. It succeeds -
|
19 | and its flexibility is both a benefit and a drawback. Many styles are
|
20 | possible, so formatting can be inconsistent. Some constructs don't
|
21 | work well in all parsers and should be avoided. The
|
22 | [CommonMark](https://commonmark.org/) specification standardizes
|
23 | parsers - but not authors.
|
24 |
|
25 | `markdownlint` is a
|
26 | [static analysis](https://en.wikipedia.org/wiki/Static_program_analysis)
|
27 | tool for [Node.js](https://nodejs.org/) with a library of rules
|
28 | to enforce standards and consistency for Markdown files. It was
|
29 | inspired by - and heavily influenced by - Mark Harrison's
|
30 | [markdownlint](https://github.com/markdownlint/markdownlint) for
|
31 | [Ruby](https://www.ruby-lang.org/). The initial rules, rule documentation,
|
32 | and test cases came directly from that project.
|
33 |
|
34 | ### Related
|
35 |
|
36 | * CLI
|
37 | * [markdownlint-cli command-line interface for Node.js](https://github.com/igorshubovych/markdownlint-cli)
|
38 | * [markdownlint-cli2 command-line interface for Node.js](https://github.com/DavidAnson/markdownlint-cli2)
|
39 | * GitHub
|
40 | * [GitHub Super-Linter Action](https://github.com/github/super-linter)
|
41 | * [GitHub Actions problem matcher for markdownlint-cli](https://github.com/xt0rted/markdownlint-problem-matcher)
|
42 | * Editor
|
43 | * [vscode-markdownlint extension for VS Code](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)
|
44 | * [Sublime Text markdownlint for Sublime Text](https://packagecontrol.io/packages/SublimeLinter-contrib-markdownlint)
|
45 | * [linter-node-markdownlint extension for Atom](https://atom.io/packages/linter-node-markdownlint)
|
46 | * [coc-markdownlint extension for Vim/Neovim](https://github.com/fannheyward/coc-markdownlint)
|
47 | * Tooling
|
48 | * [grunt-markdownlint for the Grunt task runner](https://github.com/sagiegurari/grunt-markdownlint)
|
49 | * [Cake.Markdownlint addin for Cake build automation system](https://github.com/cake-contrib/Cake.Markdownlint)
|
50 | * Ruby
|
51 | * [markdownlint/mdl gem for Ruby](https://rubygems.org/gems/mdl)
|
52 |
|
53 | ## Demonstration
|
54 |
|
55 | [`markdownlint` demo](https://dlaa.me/markdownlint/), an interactive, in-browser
|
56 | playground for learning and exploring.
|
57 |
|
58 | ## Rules / Aliases
|
59 |
|
60 |
|
61 |
|
62 | * **[MD001](doc/Rules.md#md001)** *heading-increment/header-increment* - Heading levels should only increment by one level at a time
|
63 | * ~~**[MD002](doc/Rules.md#md002)** *first-heading-h1/first-header-h1* - First heading should be a top-level heading~~
|
64 | * **[MD003](doc/Rules.md#md003)** *heading-style/header-style* - Heading style
|
65 | * **[MD004](doc/Rules.md#md004)** *ul-style* - Unordered list style
|
66 | * **[MD005](doc/Rules.md#md005)** *list-indent* - Inconsistent indentation for list items at the same level
|
67 | * ~~**[MD006](doc/Rules.md#md006)** *ul-start-left* - Consider starting bulleted lists at the beginning of the line~~
|
68 | * **[MD007](doc/Rules.md#md007)** *ul-indent* - Unordered list indentation
|
69 | * **[MD009](doc/Rules.md#md009)** *no-trailing-spaces* - Trailing spaces
|
70 | * **[MD010](doc/Rules.md#md010)** *no-hard-tabs* - Hard tabs
|
71 | * **[MD011](doc/Rules.md#md011)** *no-reversed-links* - Reversed link syntax
|
72 | * **[MD012](doc/Rules.md#md012)** *no-multiple-blanks* - Multiple consecutive blank lines
|
73 | * **[MD013](doc/Rules.md#md013)** *line-length* - Line length
|
74 | * **[MD014](doc/Rules.md#md014)** *commands-show-output* - Dollar signs used before commands without showing output
|
75 | * **[MD018](doc/Rules.md#md018)** *no-missing-space-atx* - No space after hash on atx style heading
|
76 | * **[MD019](doc/Rules.md#md019)** *no-multiple-space-atx* - Multiple spaces after hash on atx style heading
|
77 | * **[MD020](doc/Rules.md#md020)** *no-missing-space-closed-atx* - No space inside hashes on closed atx style heading
|
78 | * **[MD021](doc/Rules.md#md021)** *no-multiple-space-closed-atx* - Multiple spaces inside hashes on closed atx style heading
|
79 | * **[MD022](doc/Rules.md#md022)** *blanks-around-headings/blanks-around-headers* - Headings should be surrounded by blank lines
|
80 | * **[MD023](doc/Rules.md#md023)** *heading-start-left/header-start-left* - Headings must start at the beginning of the line
|
81 | * **[MD024](doc/Rules.md#md024)** *no-duplicate-heading/no-duplicate-header* - Multiple headings with the same content
|
82 | * **[MD025](doc/Rules.md#md025)** *single-title/single-h1* - Multiple top-level headings in the same document
|
83 | * **[MD026](doc/Rules.md#md026)** *no-trailing-punctuation* - Trailing punctuation in heading
|
84 | * **[MD027](doc/Rules.md#md027)** *no-multiple-space-blockquote* - Multiple spaces after blockquote symbol
|
85 | * **[MD028](doc/Rules.md#md028)** *no-blanks-blockquote* - Blank line inside blockquote
|
86 | * **[MD029](doc/Rules.md#md029)** *ol-prefix* - Ordered list item prefix
|
87 | * **[MD030](doc/Rules.md#md030)** *list-marker-space* - Spaces after list markers
|
88 | * **[MD031](doc/Rules.md#md031)** *blanks-around-fences* - Fenced code blocks should be surrounded by blank lines
|
89 | * **[MD032](doc/Rules.md#md032)** *blanks-around-lists* - Lists should be surrounded by blank lines
|
90 | * **[MD033](doc/Rules.md#md033)** *no-inline-html* - Inline HTML
|
91 | * **[MD034](doc/Rules.md#md034)** *no-bare-urls* - Bare URL used
|
92 | * **[MD035](doc/Rules.md#md035)** *hr-style* - Horizontal rule style
|
93 | * **[MD036](doc/Rules.md#md036)** *no-emphasis-as-heading/no-emphasis-as-header* - Emphasis used instead of a heading
|
94 | * **[MD037](doc/Rules.md#md037)** *no-space-in-emphasis* - Spaces inside emphasis markers
|
95 | * **[MD038](doc/Rules.md#md038)** *no-space-in-code* - Spaces inside code span elements
|
96 | * **[MD039](doc/Rules.md#md039)** *no-space-in-links* - Spaces inside link text
|
97 | * **[MD040](doc/Rules.md#md040)** *fenced-code-language* - Fenced code blocks should have a language specified
|
98 | * **[MD041](doc/Rules.md#md041)** *first-line-heading/first-line-h1* - First line in a file should be a top-level heading
|
99 | * **[MD042](doc/Rules.md#md042)** *no-empty-links* - No empty links
|
100 | * **[MD043](doc/Rules.md#md043)** *required-headings/required-headers* - Required heading structure
|
101 | * **[MD044](doc/Rules.md#md044)** *proper-names* - Proper names should have the correct capitalization
|
102 | * **[MD045](doc/Rules.md#md045)** *no-alt-text* - Images should have alternate text (alt text)
|
103 | * **[MD046](doc/Rules.md#md046)** *code-block-style* - Code block style
|
104 | * **[MD047](doc/Rules.md#md047)** *single-trailing-newline* - Files should end with a single newline character
|
105 | * **[MD048](doc/Rules.md#md048)** *code-fence-style* - Code fence style
|
106 |
|
107 |
|
108 |
|
109 | See [Rules.md](doc/Rules.md) for more details.
|
110 |
|
111 | ~~Struck through~~ rules are deprecated, and provided for backward-compatibility.
|
112 |
|
113 | > All rules with `heading` as part of their name are also available as
|
114 | > `header` aliases (e.g. `heading-increment` is also available as `header-increment`).
|
115 | > The use of `header` is deprecated and provided for backward-compatibility.
|
116 |
|
117 | ## Tags
|
118 |
|
119 | Tags group related rules and can be used to enable/disable multiple
|
120 | rules at once.
|
121 |
|
122 | * **accessibility** - MD045
|
123 | * **atx** - MD018, MD019
|
124 | * **atx_closed** - MD020, MD021
|
125 | * **blank_lines** - MD012, MD022, MD031, MD032, MD047
|
126 | * **blockquote** - MD027, MD028
|
127 | * **bullet** - MD004, MD005, MD006, MD007, MD032
|
128 | * **code** - MD014, MD031, MD038, MD040, MD046, MD048
|
129 | * **emphasis** - MD036, MD037
|
130 | * **hard_tab** - MD010
|
131 | * **headers** - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022,
|
132 | MD023, MD024, MD025, MD026, MD036, MD041, MD043
|
133 | * **headings** - MD001, MD002, MD003, MD018, MD019, MD020, MD021, MD022,
|
134 | MD023, MD024, MD025, MD026, MD036, MD041, MD043
|
135 | * **hr** - MD035
|
136 | * **html** - MD033
|
137 | * **images** - MD045
|
138 | * **indentation** - MD005, MD006, MD007, MD027
|
139 | * **language** - MD040
|
140 | * **line_length** - MD013
|
141 | * **links** - MD011, MD034, MD039, MD042
|
142 | * **ol** - MD029, MD030, MD032
|
143 | * **spaces** - MD018, MD019, MD020, MD021, MD023
|
144 | * **spelling** - MD044
|
145 | * **ul** - MD004, MD005, MD006, MD007, MD030, MD032
|
146 | * **url** - MD034
|
147 | * **whitespace** - MD009, MD010, MD012, MD027, MD028, MD030, MD037,
|
148 | MD038, MD039
|
149 |
|
150 | ## Configuration
|
151 |
|
152 | Text passed to `markdownlint` is parsed as Markdown, analyzed, and any
|
153 | issues reported. Two kinds of text are ignored:
|
154 |
|
155 | * [HTML comments](https://www.w3.org/TR/html5/syntax.html#comments)
|
156 | * [Front matter](https://jekyllrb.com/docs/frontmatter/) (see
|
157 | `options.frontMatter` below)
|
158 |
|
159 | Rules can be enabled, disabled, and configured via `options.config`
|
160 | (described below) to define the expected behavior for a set of inputs.
|
161 | To enable or disable rules at a particular location within a file, add
|
162 | one of these markers to the appropriate place (HTML comments don't
|
163 | appear in the final markup):
|
164 |
|
165 | * Disable all rules: `<!-- markdownlint-disable -->`
|
166 | * Enable all rules: `<!-- markdownlint-enable -->`
|
167 | * Disable all rules for the next line only: `<!-- markdownlint-disable-next-line -->`
|
168 | * Disable one or more rules by name: `<!-- markdownlint-disable MD001 MD005 -->`
|
169 | * Enable one or more rules by name: `<!-- markdownlint-enable MD001 MD005 -->`
|
170 | * Disable one or more rules by name for the next line only: `<!-- markdownlint-disable-next-line MD001 MD005 -->`
|
171 | * Capture the current rule configuration: `<!-- markdownlint-capture -->`
|
172 | * Restore the captured rule configuration: `<!-- markdownlint-restore -->`
|
173 |
|
174 | For example:
|
175 |
|
176 | ```markdown
|
177 | <!-- markdownlint-disable-next-line no-space-in-emphasis -->
|
178 | deliberate space * in * emphasis
|
179 | ```
|
180 |
|
181 | Or:
|
182 |
|
183 | ```markdown
|
184 | <!-- markdownlint-disable no-space-in-emphasis -->
|
185 | deliberate space * in * emphasis
|
186 | <!-- markdownlint-enable no-space-in-emphasis -->
|
187 | ```
|
188 |
|
189 | To temporarily disable rule(s), then restore the former configuration:
|
190 |
|
191 | ```markdown
|
192 | <!-- markdownlint-capture -->
|
193 | <!-- markdownlint-disable -->
|
194 | any violations you want
|
195 | <!-- markdownlint-restore -->
|
196 | ```
|
197 |
|
198 | The initial configuration is captured by default (as if every document
|
199 | began with `<!-- markdownlint-capture -->`), so the pattern above can
|
200 | be expressed more simply:
|
201 |
|
202 | ```markdown
|
203 | <!-- markdownlint-disable -->
|
204 | any violations you want
|
205 | <!-- markdownlint-restore -->
|
206 | ```
|
207 |
|
208 | Changes take effect starting with the line a comment is on, so the following
|
209 | has no effect:
|
210 |
|
211 | ```markdown
|
212 | space * in * emphasis <!-- markdownlint-disable --> <!-- markdownlint-enable -->
|
213 | ```
|
214 |
|
215 | To apply changes to an entire file regardless of where the comment is located,
|
216 | the following syntax is supported:
|
217 |
|
218 | * Disable all rules: `<!-- markdownlint-disable-file -->`
|
219 | * Enable all rules: `<!-- markdownlint-enable-file -->`
|
220 | * Disable one or more rules by name: `<!-- markdownlint-disable-file MD001 -->`
|
221 | * Enable one or more rules by name: `<!-- markdownlint-enable-file MD001 -->`
|
222 |
|
223 | This can be used to "hide" `markdownlint` comments at the bottom of a file.
|
224 |
|
225 | In cases where it is desirable to change the configuration of one or
|
226 | more rules for a file, the following more advanced syntax is supported:
|
227 |
|
228 | * Configure: `<!-- markdownlint-configure-file { options.config JSON } -->`
|
229 |
|
230 | For example:
|
231 |
|
232 | ```markdown
|
233 | <!-- markdownlint-configure-file { "MD013": { "line_length": 70 } } -->
|
234 | ```
|
235 |
|
236 | or
|
237 |
|
238 | ```markdown
|
239 | <!-- markdownlint-configure-file
|
240 | {
|
241 | "hr-style": {
|
242 | "style": "---"
|
243 | },
|
244 | "no-trailing-spaces": false
|
245 | }
|
246 | -->
|
247 | ```
|
248 |
|
249 | These changes apply to the entire file regardless of where the comment
|
250 | is located. Multiple such comments (if present) are applied top-to-bottom.
|
251 |
|
252 | ## API
|
253 |
|
254 | ### Linting
|
255 |
|
256 | Standard asynchronous API:
|
257 |
|
258 | ```js
|
259 | /**
|
260 | * Lint specified Markdown files.
|
261 | *
|
262 | * @param {Options} options Configuration options.
|
263 | * @param {LintCallback} callback Callback (err, result) function.
|
264 | * @returns {void}
|
265 | */
|
266 | function markdownlint(options, callback) { ... }
|
267 | ```
|
268 |
|
269 | Synchronous API (for build scripts, etc.):
|
270 |
|
271 | ```js
|
272 | /**
|
273 | * Lint specified Markdown files synchronously.
|
274 | *
|
275 | * @param {Options} options Configuration options.
|
276 | * @returns {LintResults} Results object.
|
277 | */
|
278 | function markdownlint.sync(options) { ... }
|
279 | ```
|
280 |
|
281 | Promise API (in the `promises` namespace like Node.js's
|
282 | [`fs` Promises API](https://nodejs.org/api/fs.html#fs_fs_promises_api)):
|
283 |
|
284 | ```js
|
285 | /**
|
286 | * Lint specified Markdown files.
|
287 | *
|
288 | * @param {Options} options Configuration options.
|
289 | * @returns {Promise<LintResults>} Results object.
|
290 | */
|
291 | function markdownlint(options) { ... }
|
292 | ```
|
293 |
|
294 | #### options
|
295 |
|
296 | Type: `Object`
|
297 |
|
298 | Configures the function.
|
299 |
|
300 | ##### options.customRules
|
301 |
|
302 | Type: `Array` of `Object`
|
303 |
|
304 | List of custom rules to include with the default rule set for linting.
|
305 |
|
306 | Each array element should define a rule. Rules are typically exported
|
307 | by another package, but can be defined locally. Custom rules are
|
308 | identified by the
|
309 | [keyword `markdownlint-rule` on npm](https://www.npmjs.com/search?q=keywords:markdownlint-rule).
|
310 |
|
311 | Example:
|
312 |
|
313 | ```js
|
314 | const extraRules = require("extraRules");
|
315 | const options = {
|
316 | "customRules": [ extraRules.one, extraRules.two ]
|
317 | };
|
318 | ```
|
319 |
|
320 | See [CustomRules.md](doc/CustomRules.md) for details about authoring
|
321 | custom rules.
|
322 |
|
323 | ##### options.files
|
324 |
|
325 | Type: `Array` of `String`
|
326 |
|
327 | List of files to lint.
|
328 |
|
329 | Each array element should be a single file (via relative or absolute path);
|
330 | [globbing](https://en.wikipedia.org/wiki/Glob_%28programming%29) is the
|
331 | caller's responsibility.
|
332 |
|
333 | Example: `[ "one.md", "dir/two.md" ]`
|
334 |
|
335 | ##### options.strings
|
336 |
|
337 | Type: `Object` mapping `String` to `String`
|
338 |
|
339 | Map of identifiers to strings for linting.
|
340 |
|
341 | When Markdown content is not available as files, it can be passed as
|
342 | strings. The keys of the `strings` object are used to identify each
|
343 | input value in the `result` summary.
|
344 |
|
345 | Example:
|
346 |
|
347 | ```json
|
348 | {
|
349 | "readme": "# README\n...",
|
350 | "changelog": "# CHANGELOG\n..."
|
351 | }
|
352 | ```
|
353 |
|
354 | ##### options.config
|
355 |
|
356 | Type: `Object` mapping `String` to `Boolean | Object`
|
357 |
|
358 | Configures the rules to use.
|
359 |
|
360 | Object keys are rule names or aliases and values are the rule's configuration.
|
361 | The value `false` disables a rule, `true` enables its default configuration,
|
362 | and passing an object customizes its settings. Setting the special `default`
|
363 | rule to `true` or `false` includes/excludes all rules by default. Enabling
|
364 | or disabling a tag name (ex: `whitespace`) affects all rules having that
|
365 | tag.
|
366 |
|
367 | The `default` rule is applied first, then keys are processed in order
|
368 | from top to bottom with later values overriding earlier ones. Keys
|
369 | (including rule names, aliases, tags, and `default`) are not case-sensitive.
|
370 |
|
371 | Example:
|
372 |
|
373 | ```json
|
374 | {
|
375 | "default": true,
|
376 | "MD003": { "style": "atx_closed" },
|
377 | "MD007": { "indent": 4 },
|
378 | "no-hard-tabs": false,
|
379 | "whitespace": false
|
380 | }
|
381 | ```
|
382 |
|
383 | See [.markdownlint.jsonc](schema/.markdownlint.jsonc) and/or
|
384 | [.markdownlint.yaml](schema/.markdownlint.yaml) for an example
|
385 | configuration object with all properties set to the default value.
|
386 |
|
387 | Sets of rules (known as a "style") can be stored separately and loaded
|
388 | as [JSON](https://en.wikipedia.org/wiki/JSON).
|
389 |
|
390 | Example:
|
391 |
|
392 | ```js
|
393 | const options = {
|
394 | "files": [ "..." ],
|
395 | "config": require("style/relaxed.json")
|
396 | };
|
397 | ```
|
398 |
|
399 | See the [style](style) directory for more samples.
|
400 |
|
401 | See [markdownlint-config-schema.json](schema/markdownlint-config-schema.json)
|
402 | for the [JSON Schema](https://json-schema.org/) of the `options.config`
|
403 | object.
|
404 |
|
405 | For more advanced scenarios, styles can reference and extend other styles.
|
406 | The `readConfig` and `readConfigSync` functions can be used to read such
|
407 | styles.
|
408 |
|
409 | For example, assuming a `base.json` configuration file:
|
410 |
|
411 | ```json
|
412 | {
|
413 | "default": true
|
414 | }
|
415 | ```
|
416 |
|
417 | And a `custom.json` configuration file:
|
418 |
|
419 | ```json
|
420 | {
|
421 | "extends": "base.json",
|
422 | "line-length": false
|
423 | }
|
424 | ```
|
425 |
|
426 | Then code like the following:
|
427 |
|
428 | ```js
|
429 | const options = {
|
430 | "config": markdownlint.readConfigSync("./custom.json")
|
431 | };
|
432 | ```
|
433 |
|
434 | Merges `custom.json` and `base.json` and is equivalent to:
|
435 |
|
436 | ```js
|
437 | const options = {
|
438 | "config": {
|
439 | "default": true,
|
440 | "line-length": false
|
441 | }
|
442 | };
|
443 | ```
|
444 |
|
445 | ##### options.frontMatter
|
446 |
|
447 | Type: `RegExp`
|
448 |
|
449 | Matches any [front matter](https://jekyllrb.com/docs/frontmatter/)
|
450 | found at the beginning of a file.
|
451 |
|
452 | Some Markdown content begins with metadata; the default `RegExp` for
|
453 | this option ignores common forms of "front matter". To match differently,
|
454 | specify a custom `RegExp` or use the value `null` to disable the feature.
|
455 |
|
456 | The default value:
|
457 |
|
458 | ```js
|
459 | /((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m
|
460 | ```
|
461 |
|
462 | Ignores [YAML](https://en.wikipedia.org/wiki/YAML),
|
463 | [TOML](https://en.wikipedia.org/wiki/TOML), and
|
464 | [JSON](https://en.wikipedia.org/wiki/JSON) front matter such as:
|
465 |
|
466 | ```text
|
467 | ---
|
468 | layout: post
|
469 | title: Title
|
470 | ---
|
471 | ```
|
472 |
|
473 | Note: Matches must occur at the start of the file.
|
474 |
|
475 | ##### options.handleRuleFailures
|
476 |
|
477 | Type: `Boolean`
|
478 |
|
479 | Catches exceptions thrown during rule processing and reports the problem
|
480 | as a rule violation.
|
481 |
|
482 | By default, exceptions thrown by rules (or the library itself) are unhandled
|
483 | and bubble up the stack to the caller in the conventional manner. By setting
|
484 | `handleRuleFailures` to `true`, exceptions thrown by failing rules will
|
485 | be handled by the library and the exception message logged as a rule violation.
|
486 | This setting can be useful in the presence of (custom) rules that encounter
|
487 | unexpected syntax and fail. By enabling this option, the linting process
|
488 | is allowed to continue and report any violations that were found.
|
489 |
|
490 | ##### options.noInlineConfig
|
491 |
|
492 | Type: `Boolean`
|
493 |
|
494 | Disables the use of HTML comments like `<!-- markdownlint-disable -->` to toggle
|
495 | rules within the body of Markdown content.
|
496 |
|
497 | By default, properly-formatted inline comments can be used to create exceptions
|
498 | for parts of a document. Setting `noInlineConfig` to `true` ignores all such
|
499 | comments.
|
500 |
|
501 | ##### options.resultVersion
|
502 |
|
503 | Type: `Number`
|
504 |
|
505 | Specifies which version of the `result` object to return (see the "Usage" section
|
506 | below for examples).
|
507 |
|
508 | Passing a `resultVersion` of `0` corresponds to the original, simple format where
|
509 | each error is identified by rule name and line number. *This is deprecated.*
|
510 |
|
511 | Passing a `resultVersion` of `1` corresponds to a detailed format where each error
|
512 | includes information about the line number, rule name, alias, description, as well
|
513 | as any additional detail or context that is available. *This is deprecated.*
|
514 |
|
515 | Passing a `resultVersion` of `2` corresponds to a detailed format where each error
|
516 | includes information about the line number, rule names, description, as well as any
|
517 | additional detail or context that is available. *This is the default.*
|
518 |
|
519 | Passing a `resultVersion` of `3` corresponds to the detailed version `2` format
|
520 | with additional information about how to fix automatically-fixable errors. In this
|
521 | mode, all errors that occur on each line are reported (other versions report only
|
522 | the first error for each rule).
|
523 |
|
524 | ##### options.markdownItPlugins
|
525 |
|
526 | Type: `Array` of `Array` of `Function` and plugin parameters
|
527 |
|
528 | Specifies additional [markdown-it plugins](https://www.npmjs.com/search?q=keywords:markdown-it-plugin)
|
529 | to use when parsing input. Plugins can be used to support additional syntax and
|
530 | features for advanced scenarios.
|
531 |
|
532 | Each item in the top-level `Array` should be of the form:
|
533 |
|
534 | ```js
|
535 | [ require("markdown-it-plugin"), plugin_param_0, plugin_param_1, ... ]
|
536 | ```
|
537 |
|
538 | #### callback
|
539 |
|
540 | Type: `Function` taking (`Error`, `Object`)
|
541 |
|
542 | Standard completion callback.
|
543 |
|
544 | #### result
|
545 |
|
546 | Type: `Object`
|
547 |
|
548 | Call `result.toString()` for convenience or see below for an example of the
|
549 | structure of the `result` object. Passing the value `true` to `toString()`
|
550 | uses rule aliases (ex: `no-hard-tabs`) instead of names (ex: `MD010`).
|
551 |
|
552 | ### Config
|
553 |
|
554 | The `options.config` configuration object is simple and can be stored in a file
|
555 | for readability and easy reuse. The `readConfig` and `readConfigSync` functions
|
556 | load configuration settings and support the `extends` keyword for referencing
|
557 | other files (see above).
|
558 |
|
559 | By default, configuration files are parsed as JSON (and named `.markdownlint.json`).
|
560 | Custom parsers can be provided to handle other formats like JSONC, YAML, and TOML.
|
561 |
|
562 | Asynchronous API:
|
563 |
|
564 | ```js
|
565 | /**
|
566 | * Read specified configuration file.
|
567 | *
|
568 | * @param {string} file Configuration file name.
|
569 | * @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing function(s).
|
570 | * @param {ReadConfigCallback} [callback] Callback (err, result) function.
|
571 | * @returns {void}
|
572 | */
|
573 | function readConfig(file, parsers, callback) { ... }
|
574 | ```
|
575 |
|
576 | Synchronous API:
|
577 |
|
578 | ```js
|
579 | /**
|
580 | * Read specified configuration file synchronously.
|
581 | *
|
582 | * @param {string} file Configuration file name.
|
583 | * @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
584 | * @returns {Configuration} Configuration object.
|
585 | */
|
586 | function readConfigSync(file, parsers) { ... }
|
587 | ```
|
588 |
|
589 | Promise API (in the `promises` namespace like Node.js's
|
590 | [`fs` Promises API](https://nodejs.org/api/fs.html#fs_fs_promises_api)):
|
591 |
|
592 | ```js
|
593 | /**
|
594 | * Read specified configuration file.
|
595 | *
|
596 | * @param {string} file Configuration file name.
|
597 | * @param {ConfigurationParser[]} [parsers] Parsing function(s).
|
598 | * @returns {Promise<Configuration>} Configuration object.
|
599 | */
|
600 | function readConfig(file, parsers) { ... }
|
601 | ```
|
602 |
|
603 | #### file
|
604 |
|
605 | Type: `String`
|
606 |
|
607 | Location of configuration file to read.
|
608 |
|
609 | The `file` is resolved relative to the current working directory. If an `extends`
|
610 | key is present once read, its value will be resolved as a path relative to `file`
|
611 | and loaded recursively. Settings from a file referenced by `extends` are applied
|
612 | first, then those of `file` are applied on top (overriding any of the same keys
|
613 | appearing in the referenced file).
|
614 |
|
615 | #### parsers
|
616 |
|
617 | Type: *Optional* `Array` of `Function` taking (`String`) and returning `Object`
|
618 |
|
619 | Array of functions to parse configuration files.
|
620 |
|
621 | The contents of a configuration file are passed to each parser function until one
|
622 | of them returns a value (vs. throwing an exception). Consequently, strict parsers
|
623 | should come before flexible parsers.
|
624 |
|
625 | For example:
|
626 |
|
627 | ```js
|
628 | [ JSON.parse, require("toml").parse, require("js-yaml").load ]
|
629 | ```
|
630 |
|
631 | #### callback
|
632 |
|
633 | Type: `Function` taking (`Error`, `Object`)
|
634 |
|
635 | Standard completion callback.
|
636 |
|
637 | #### result
|
638 |
|
639 | Type: `Object`
|
640 |
|
641 | Configuration object.
|
642 |
|
643 | ## Usage
|
644 |
|
645 | Invoke `markdownlint` and use the `result` object's `toString` method:
|
646 |
|
647 | ```js
|
648 | const markdownlint = require("markdownlint");
|
649 |
|
650 | const options = {
|
651 | "files": [ "good.md", "bad.md" ],
|
652 | "strings": {
|
653 | "good.string": "# good.string\n\nThis string passes all rules.",
|
654 | "bad.string": "#bad.string\n\n#This string fails\tsome rules."
|
655 | }
|
656 | };
|
657 |
|
658 | markdownlint(options, function callback(err, result) {
|
659 | if (!err) {
|
660 | console.log(result.toString());
|
661 | }
|
662 | });
|
663 | ```
|
664 |
|
665 | Output:
|
666 |
|
667 | ```text
|
668 | bad.string: 3: MD010/no-hard-tabs Hard tabs [Column: 19]
|
669 | bad.string: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.string"]
|
670 | bad.string: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This string fails some rules."]
|
671 | bad.string: 1: MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "#bad.string"]
|
672 | bad.md: 3: MD010/no-hard-tabs Hard tabs [Column: 17]
|
673 | bad.md: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.md"]
|
674 | bad.md: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This file fails some rules."]
|
675 | bad.md: 1: MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "#bad.md"]
|
676 | ```
|
677 |
|
678 | Or invoke `markdownlint.sync` for a synchronous call:
|
679 |
|
680 | ```js
|
681 | const result = markdownlint.sync(options);
|
682 | console.log(result.toString());
|
683 | ```
|
684 |
|
685 | To examine the `result` object directly:
|
686 |
|
687 | ```js
|
688 | markdownlint(options, function callback(err, result) {
|
689 | if (!err) {
|
690 | console.dir(result, { "colors": true, "depth": null });
|
691 | }
|
692 | });
|
693 | ```
|
694 |
|
695 | Output:
|
696 |
|
697 | ```json
|
698 | {
|
699 | "good.md": [],
|
700 | "bad.md": [
|
701 | { "lineNumber": 3,
|
702 | "ruleNames": [ "MD010", "no-hard-tabs" ],
|
703 | "ruleDescription": "Hard tabs",
|
704 | "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md010",
|
705 | "errorDetail": "Column: 17",
|
706 | "errorContext": null,
|
707 | "errorRange": [ 17, 1 ] },
|
708 | { "lineNumber": 1,
|
709 | "ruleNames": [ "MD018", "no-missing-space-atx" ],
|
710 | "ruleDescription": "No space after hash on atx style heading",
|
711 | "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md018",
|
712 | "errorDetail": null,
|
713 | "errorContext": "#bad.md",
|
714 | "errorRange": [ 1, 2 ] },
|
715 | { "lineNumber": 3,
|
716 | "ruleNames": [ "MD018", "no-missing-space-atx" ],
|
717 | "ruleDescription": "No space after hash on atx style heading",
|
718 | "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md018",
|
719 | "errorDetail": null,
|
720 | "errorContext": "#This file fails\tsome rules.",
|
721 | "errorRange": [ 1, 2 ] },
|
722 | { "lineNumber": 1,
|
723 | "ruleNames": [ "MD041", "first-line-heading", "first-line-h1" ],
|
724 | "ruleDescription": "First line in a file should be a top-level heading",
|
725 | "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md041",
|
726 | "errorDetail": null,
|
727 | "errorContext": "#bad.md",
|
728 | "errorRange": null }
|
729 | ]
|
730 | }
|
731 | ```
|
732 |
|
733 | Integration with the [gulp](https://gulpjs.com/) build system is straightforward:
|
734 |
|
735 | ```js
|
736 | const gulp = require("gulp");
|
737 | const through2 = require("through2");
|
738 | const markdownlint = require("markdownlint");
|
739 |
|
740 | gulp.task("markdownlint", function task() {
|
741 | return gulp.src("*.md", { "read": false })
|
742 | .pipe(through2.obj(function obj(file, enc, next) {
|
743 | markdownlint(
|
744 | { "files": [ file.relative ] },
|
745 | function callback(err, result) {
|
746 | const resultString = (result || "").toString();
|
747 | if (resultString) {
|
748 | console.log(resultString);
|
749 | }
|
750 | next(err, file);
|
751 | });
|
752 | }));
|
753 | });
|
754 | ```
|
755 |
|
756 | Output:
|
757 |
|
758 | ```text
|
759 | [00:00:00] Starting 'markdownlint'...
|
760 | bad.md: 3: MD010/no-hard-tabs Hard tabs [Column: 17]
|
761 | bad.md: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.md"]
|
762 | bad.md: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This file fails some rules."]
|
763 | bad.md: 1: MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "#bad.md"]
|
764 | [00:00:00] Finished 'markdownlint' after 10 ms
|
765 | ```
|
766 |
|
767 | Integration with the [Grunt](https://gruntjs.com/) build system is similar:
|
768 |
|
769 | ```js
|
770 | const markdownlint = require("markdownlint");
|
771 |
|
772 | module.exports = function wrapper(grunt) {
|
773 | grunt.initConfig({
|
774 | "markdownlint": {
|
775 | "example": {
|
776 | "src": [ "*.md" ]
|
777 | }
|
778 | }
|
779 | });
|
780 |
|
781 | grunt.registerMultiTask("markdownlint", function task() {
|
782 | const done = this.async();
|
783 | markdownlint(
|
784 | { "files": this.filesSrc },
|
785 | function callback(err, result) {
|
786 | const resultString = err || ((result || "").toString());
|
787 | if (resultString) {
|
788 | grunt.fail.warn("\n" + resultString + "\n");
|
789 | }
|
790 | done(!err || !resultString);
|
791 | });
|
792 | });
|
793 | };
|
794 | ```
|
795 |
|
796 | Output:
|
797 |
|
798 | ```text
|
799 | Running "markdownlint:example" (markdownlint) task
|
800 | Warning:
|
801 | bad.md: 3: MD010/no-hard-tabs Hard tabs [Column: 17]
|
802 | bad.md: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.md"]
|
803 | bad.md: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This file fails some rules."]
|
804 | bad.md: 1: MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "#bad.md"]
|
805 | Use --force to continue.
|
806 | ```
|
807 |
|
808 | ## Browser
|
809 |
|
810 | `markdownlint` also works in the browser.
|
811 |
|
812 | Generate normal and minified scripts with:
|
813 |
|
814 | ```shell
|
815 | npm run build-demo
|
816 | ```
|
817 |
|
818 | Then reference `markdown-it` and `markdownlint`:
|
819 |
|
820 | ```html
|
821 | <script src="demo/markdown-it.min.js"></script>
|
822 | <script src="demo/markdownlint-browser.min.js"></script>
|
823 | ```
|
824 |
|
825 | And call it like so:
|
826 |
|
827 | ```js
|
828 | const options = {
|
829 | "strings": {
|
830 | "content": "Some Markdown to lint."
|
831 | }
|
832 | };
|
833 | const results = window.markdownlint.sync(options).toString();
|
834 | ```
|
835 |
|
836 | ## Examples
|
837 |
|
838 | For ideas how to integrate `markdownlint` into your workflow, refer to the following projects:
|
839 |
|
840 | * [.NET Documentation](https://docs.microsoft.com/en-us/dotnet/) ([Search repository](https://github.com/dotnet/docs/search?q=markdownlint))
|
841 | * [ally.js](https://allyjs.io/) ([Search repository](https://github.com/medialize/ally.js/search?q=markdownlint))
|
842 | * [Boostnote](https://boostnote.io/) ([Search repository](https://github.com/BoostIO/Boostnote/search?q=markdownlint))
|
843 | * [CodiMD](https://github.com/hackmdio/codimd) ([Search repository](https://github.com/hackmdio/codimd/search?q=markdownlint))
|
844 | * [ESLint](https://eslint.org/) ([Search repository](https://github.com/eslint/eslint/search?q=markdownlint))
|
845 | * [Garden React Components](https://zendeskgarden.github.io/react-components/) ([Search repository](https://github.com/zendeskgarden/react-components/search?q=markdownlint))
|
846 | * [MkDocs](https://www.mkdocs.org/) ([Search repository](https://github.com/mkdocs/mkdocs/search?q=markdownlint))
|
847 | * [Mocha](https://mochajs.org/) ([Search repository](https://github.com/mochajs/mocha/search?q=markdownlint))
|
848 | * [Reactable](https://glittershark.github.io/reactable/) ([Search repository](https://github.com/glittershark/reactable/search?q=markdownlint))
|
849 | * [Sinon.JS](https://sinonjs.org/) ([Search repository](https://github.com/sinonjs/sinon/search?q=markdownlint))
|
850 | * [TestCafe](https://devexpress.github.io/testcafe/) ([Search repository](https://github.com/DevExpress/testcafe/search?q=markdownlint))
|
851 | * [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/basic-types.html) ([Search repository](https://github.com/Microsoft/TypeScript-Handbook/search?q=markdownlint))
|
852 | * [V8](https://v8.dev/) ([Search repository](https://github.com/v8/v8.dev/search?q=markdownlint))
|
853 | * [webhint](https://webhint.io/) ([Search repository](https://github.com/webhintio/hint/search?q=markdownlint))
|
854 | * [webpack](https://webpack.js.org/) ([Search repository](https://github.com/webpack/webpack.js.org/search?q=markdownlint))
|
855 | * [WordPress](https://wordpress.org/gutenberg/) ([Search repository](https://github.com/WordPress/gutenberg/search?q=markdownlint))
|
856 |
|
857 | ## Contributing
|
858 |
|
859 | See [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
|
860 |
|
861 | ## History
|
862 |
|
863 | * 0.0.1 - Initial release, includes tests MD001-MD032.
|
864 | * 0.0.2 - Improve documentation, tests, and code.
|
865 | * 0.0.3 - Add synchronous API, improve documentation and code.
|
866 | * 0.0.4 - Add tests MD033-MD040, update dependencies.
|
867 | * 0.0.5 - Add `strings` option to enable file-less scenarios, add in-browser demo.
|
868 | * 0.0.6 - Improve performance, simplify in-browser, update dependencies.
|
869 | * 0.0.7 - Add MD041, improve MD003, ignore front matter, update dependencies.
|
870 | * 0.0.8 - Support disabling/enabling rules inline, improve code fence, dependencies.
|
871 | * 0.1.0 - Add aliases, exceptions for MD033, exclusions for MD013, dependencies.
|
872 | * 0.1.1 - Fix bug handling HTML in tables, reference markdownlint-cli.
|
873 | * 0.2.0 - Add MD042/MD043, enhance MD002/MD003/MD004/MD007/MD011/MD025/MD041, dependencies.
|
874 | * 0.3.0 - More detailed error reporting with `resultVersion`, enhance MD010/MD012/MD036,
|
875 | fixes for MD027/MD029/MD030, include JSON schema, dependencies.
|
876 | * 0.3.1 - Fix regressions in MD032/MD038, update dependencies.
|
877 | * 0.4.0 - Add MD044, enhance MD013/MD032/MD041/MD042/MD043, fix for MD038, dependencies.
|
878 | * 0.4.1 - Fixes for MD038/front matter, improvements to MD044, update dependencies.
|
879 | * 0.5.0 - Add shareable configuration, `noInlineConfig` option, README links, fix MD030,
|
880 | improve MD009/MD041, update dependencies.
|
881 | * 0.6.0 - `resultVersion` defaults to 1 (breaking change), ignore HTML comments, TOML
|
882 | front matter, fixes for MD044, update dependencies.
|
883 | * 0.6.1 - Update `markdown-it` versioning, exclude demo/test from publishing.
|
884 | * 0.6.2 - Improve MD013/MD027/MD034/MD037/MD038/MD041/MD044, update dependencies.
|
885 | * 0.6.3 - Improve highlighting for MD020.
|
886 | * 0.6.4 - Improve MD029/MD042, update dependencies.
|
887 | * 0.7.0 - `resultVersion` defaults to 2 (breaking change), add MD045, improve MD029,
|
888 | remove trimLeft/trimRight, split rules, refactor, update dependencies.
|
889 | * 0.8.0 - Add support for using and authoring custom rules, improve MD004/MD007/MD013,
|
890 | add `engines` to `package.json`, refactor, update dependencies.
|
891 | * 0.8.1 - Update item loop to be iterative, improve MD014, update dependencies.
|
892 | * 0.9.0 - Remove support for end-of-life Node versions 0.10/0.12/4, change "header" to
|
893 | "heading" per spec (non-breaking), improve MD003/MD009/MD041, handle uncommon
|
894 | line-break characters, refactor for ES6, update dependencies.
|
895 | * 0.10.0 - Add support for non-JSON configuration files, pass file/string name to custom
|
896 | rules, update dependencies.
|
897 | * 0.11.0 - Improve MD005/MD024/MD029/MD038, improve custom rule example, add CONTRIBUTING.md,
|
898 | update dependencies.
|
899 | * 0.12.0 - Add `information` link for custom rules, `markdownItPlugins` for extensibility,
|
900 | improve MD023/MD032/MD038, update dependencies.
|
901 | * 0.13.0 - Improve MD013/MD022/MD025/MD029/MD031/MD032/MD037/MD041/, deprecate MD002,
|
902 | improve pandoc YAML support, update dependencies.
|
903 | * 0.14.0 - Remove support for end-of-life Node version 6, introduce `markdownlint-rule-helpers`,
|
904 | add MD046/MD047, improve MD033/MD034/MD039, improve custom rule validation and
|
905 | in-browser demo, update dependencies.
|
906 | * 0.14.1 - Improve MD033.
|
907 | * 0.14.2 - Improve MD047, add `handleRuleFailures` option.
|
908 | * 0.15.0 - Add `markdownlint-capture`/`markdownlint-restore` inline comments, improve
|
909 | MD009/MD013/MD026/MD033/MD036, update dependencies.
|
910 | * 0.16.0 - Add custom rule sample for linting code, improve MD026/MD031/MD033/MD038,
|
911 | update dependencies.
|
912 | * 0.17.0 - Add `resultVersion` 3 to support fix information for default and custom rules,
|
913 | add fix information for 24 rules, update newline handling to match latest
|
914 | CommonMark specification, improve MD014/MD037/MD039, update dependencies.
|
915 | * 0.17.1 - Fix handling of front matter by fix information.
|
916 | * 0.17.2 - Improve MD020/MD033/MD044.
|
917 | * 0.18.0 - Add MD048/code-fence-style, add fix information for MD007/ul-indent, add
|
918 | `markdownlint-disable-file`/`markdownlint-enable-file` inline comments, add
|
919 | type declaration file (.d.ts) for TypeScript dependents, update schema, improve
|
920 | MD006/MD007/MD009/MD013/MD030, update dependencies.
|
921 | * 0.19.0 - Remove support for end-of-life Node version 8, add fix information for
|
922 | MD005/list-indent, improve MD007/MD013/MD014, deprecate MD006/ul-start-left, add
|
923 | rationale for every rule, update test runner and code coverage, add more JSDoc
|
924 | comments, update dependencies.
|
925 | * 0.20.0 - Add `markdownlint-configure-file` inline comment, reimplement MD037,
|
926 | improve MD005/MD007/MD013/MD018/MD029/MD031/MD034/MD038/MD039, improve HTML
|
927 | comment handling, update dependencies.
|
928 | * 0.20.1 - Fix regression in MD037.
|
929 | * 0.20.2 - Fix regression in MD037, improve MD038.
|
930 | * 0.20.3 - Fix regression in MD037, improve MD044, add automatic regression testing.
|
931 | * 0.20.4 - Fix regression in MD037, improve MD034/MD044, improve documentation.
|
932 | * 0.21.0 - Lint concurrently for better performance (async only), add Promise-based APIs,
|
933 | update TypeScript declaration file, hide `toString` on `LintResults`, add ability
|
934 | to fix in browser demo, allow custom rules in `.markdownlint.json` schema, improve
|
935 | MD042/MD044, improve documentation, update dependencies.
|
936 | * 0.21.1 - Improve MD011/MD031, export `getVersion` API.
|
937 | * 0.22.0 - Allow `extends` in config to reference installed packages by name, add
|
938 | `markdownlint-disable-next-line` inline comment, support JSON front matter, improve
|
939 | MD009/MD026/MD028/MD043, update dependencies (including `markdown-it` to v12).
|
940 | * 0.23.0 - Add comprehensive example `.markdownlint.jsonc`/`.markdownlint.yaml` files, add fix
|
941 | information for MD004/ul-style, improve MD018/MD019/MD020/MD021/MD037/MD041, improve
|
942 | HTML comment handling, update test runner and test suite, update dependencies.
|
943 | * 0.23.1 - Work around lack of webpack support for dynamic calls to `require` (`.resolve`).
|
944 |
|
945 | [npm-image]: https://img.shields.io/npm/v/markdownlint.svg
|
946 | [npm-url]: https://www.npmjs.com/package/markdownlint
|
947 | [ci-image]: https://github.com/DavidAnson/markdownlint/workflows/CI/badge.svg?branch=main
|
948 | [ci-url]: https://github.com/DavidAnson/markdownlint/actions?query=branch%3Amain
|
949 | [license-image]: https://img.shields.io/npm/l/markdownlint.svg
|
950 | [license-url]: https://opensource.org/licenses/MIT
|