UNPKG

36.6 kBMarkdownView Raw
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
12npm install markdownlint --save-dev
13```
14
15## Overview
16
17The [Markdown](https://en.wikipedia.org/wiki/Markdown) markup language
18is designed to be easy to read, write, and understand. It succeeds -
19and its flexibility is both a benefit and a drawback. Many styles are
20possible, so formatting can be inconsistent. Some constructs don't
21work well in all parsers and should be avoided. The
22[CommonMark](https://commonmark.org/) specification standardizes
23parsers - but not authors.
24
25`markdownlint` is a
26[static analysis](https://en.wikipedia.org/wiki/Static_program_analysis)
27tool for [Node.js](https://nodejs.org/) with a library of rules
28to enforce standards and consistency for Markdown files. It was
29inspired 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,
32and 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
56playground for learning and exploring.
57
58## Rules / Aliases
59
60<!-- markdownlint-disable line-length -->
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<!-- markdownlint-restore -->
108
109See [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
119Tags group related rules and can be used to enable/disable multiple
120rules 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
152Text passed to `markdownlint` is parsed as Markdown, analyzed, and any
153issues 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
159Rules can be enabled, disabled, and configured via `options.config`
160(described below) to define the expected behavior for a set of inputs.
161To enable or disable rules at a particular location within a file, add
162one of these markers to the appropriate place (HTML comments don't
163appear 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
174For example:
175
176```markdown
177<!-- markdownlint-disable-next-line no-space-in-emphasis -->
178deliberate space * in * emphasis
179```
180
181Or:
182
183```markdown
184<!-- markdownlint-disable no-space-in-emphasis -->
185deliberate space * in * emphasis
186<!-- markdownlint-enable no-space-in-emphasis -->
187```
188
189To temporarily disable rule(s), then restore the former configuration:
190
191```markdown
192<!-- markdownlint-capture -->
193<!-- markdownlint-disable -->
194any violations you want
195<!-- markdownlint-restore -->
196```
197
198The initial configuration is captured by default (as if every document
199began with `<!-- markdownlint-capture -->`), so the pattern above can
200be expressed more simply:
201
202```markdown
203<!-- markdownlint-disable -->
204any violations you want
205<!-- markdownlint-restore -->
206```
207
208Changes take effect starting with the line a comment is on, so the following
209has no effect:
210
211```markdown
212space * in * emphasis <!-- markdownlint-disable --> <!-- markdownlint-enable -->
213```
214
215To apply changes to an entire file regardless of where the comment is located,
216the 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
223This can be used to "hide" `markdownlint` comments at the bottom of a file.
224
225In cases where it is desirable to change the configuration of one or
226more rules for a file, the following more advanced syntax is supported:
227
228* Configure: `<!-- markdownlint-configure-file { options.config JSON } -->`
229
230For example:
231
232```markdown
233<!-- markdownlint-configure-file { "MD013": { "line_length": 70 } } -->
234```
235
236or
237
238```markdown
239<!-- markdownlint-configure-file
240{
241 "hr-style": {
242 "style": "---"
243 },
244 "no-trailing-spaces": false
245}
246-->
247```
248
249These changes apply to the entire file regardless of where the comment
250is located. Multiple such comments (if present) are applied top-to-bottom.
251
252## API
253
254### Linting
255
256Standard 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 */
266function markdownlint(options, callback) { ... }
267```
268
269Synchronous 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 */
278function markdownlint.sync(options) { ... }
279```
280
281Promise 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 */
291function markdownlint(options) { ... }
292```
293
294#### options
295
296Type: `Object`
297
298Configures the function.
299
300##### options.customRules
301
302Type: `Array` of `Object`
303
304List of custom rules to include with the default rule set for linting.
305
306Each array element should define a rule. Rules are typically exported
307by another package, but can be defined locally. Custom rules are
308identified by the
309[keyword `markdownlint-rule` on npm](https://www.npmjs.com/search?q=keywords:markdownlint-rule).
310
311Example:
312
313```js
314const extraRules = require("extraRules");
315const options = {
316 "customRules": [ extraRules.one, extraRules.two ]
317};
318```
319
320See [CustomRules.md](doc/CustomRules.md) for details about authoring
321custom rules.
322
323##### options.files
324
325Type: `Array` of `String`
326
327List of files to lint.
328
329Each array element should be a single file (via relative or absolute path);
330[globbing](https://en.wikipedia.org/wiki/Glob_%28programming%29) is the
331caller's responsibility.
332
333Example: `[ "one.md", "dir/two.md" ]`
334
335##### options.strings
336
337Type: `Object` mapping `String` to `String`
338
339Map of identifiers to strings for linting.
340
341When Markdown content is not available as files, it can be passed as
342strings. The keys of the `strings` object are used to identify each
343input value in the `result` summary.
344
345Example:
346
347```json
348{
349 "readme": "# README\n...",
350 "changelog": "# CHANGELOG\n..."
351}
352```
353
354##### options.config
355
356Type: `Object` mapping `String` to `Boolean | Object`
357
358Configures the rules to use.
359
360Object keys are rule names or aliases and values are the rule's configuration.
361The value `false` disables a rule, `true` enables its default configuration,
362and passing an object customizes its settings. Setting the special `default`
363rule to `true` or `false` includes/excludes all rules by default. Enabling
364or disabling a tag name (ex: `whitespace`) affects all rules having that
365tag.
366
367The `default` rule is applied first, then keys are processed in order
368from top to bottom with later values overriding earlier ones. Keys
369(including rule names, aliases, tags, and `default`) are not case-sensitive.
370
371Example:
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
383See [.markdownlint.jsonc](schema/.markdownlint.jsonc) and/or
384[.markdownlint.yaml](schema/.markdownlint.yaml) for an example
385configuration object with all properties set to the default value.
386
387Sets of rules (known as a "style") can be stored separately and loaded
388as [JSON](https://en.wikipedia.org/wiki/JSON).
389
390Example:
391
392```js
393const options = {
394 "files": [ "..." ],
395 "config": require("style/relaxed.json")
396};
397```
398
399See the [style](style) directory for more samples.
400
401See [markdownlint-config-schema.json](schema/markdownlint-config-schema.json)
402for the [JSON Schema](https://json-schema.org/) of the `options.config`
403object.
404
405For more advanced scenarios, styles can reference and extend other styles.
406The `readConfig` and `readConfigSync` functions can be used to read such
407styles.
408
409For example, assuming a `base.json` configuration file:
410
411```json
412{
413 "default": true
414}
415```
416
417And a `custom.json` configuration file:
418
419```json
420{
421 "extends": "base.json",
422 "line-length": false
423}
424```
425
426Then code like the following:
427
428```js
429const options = {
430 "config": markdownlint.readConfigSync("./custom.json")
431};
432```
433
434Merges `custom.json` and `base.json` and is equivalent to:
435
436```js
437const options = {
438 "config": {
439 "default": true,
440 "line-length": false
441 }
442};
443```
444
445##### options.frontMatter
446
447Type: `RegExp`
448
449Matches any [front matter](https://jekyllrb.com/docs/frontmatter/)
450found at the beginning of a file.
451
452Some Markdown content begins with metadata; the default `RegExp` for
453this option ignores common forms of "front matter". To match differently,
454specify a custom `RegExp` or use the value `null` to disable the feature.
455
456The default value:
457
458```js
459/((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m
460```
461
462Ignores [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---
468layout: post
469title: Title
470---
471```
472
473Note: Matches must occur at the start of the file.
474
475##### options.handleRuleFailures
476
477Type: `Boolean`
478
479Catches exceptions thrown during rule processing and reports the problem
480as a rule violation.
481
482By default, exceptions thrown by rules (or the library itself) are unhandled
483and bubble up the stack to the caller in the conventional manner. By setting
484`handleRuleFailures` to `true`, exceptions thrown by failing rules will
485be handled by the library and the exception message logged as a rule violation.
486This setting can be useful in the presence of (custom) rules that encounter
487unexpected syntax and fail. By enabling this option, the linting process
488is allowed to continue and report any violations that were found.
489
490##### options.noInlineConfig
491
492Type: `Boolean`
493
494Disables the use of HTML comments like `<!-- markdownlint-disable -->` to toggle
495rules within the body of Markdown content.
496
497By default, properly-formatted inline comments can be used to create exceptions
498for parts of a document. Setting `noInlineConfig` to `true` ignores all such
499comments.
500
501##### options.resultVersion
502
503Type: `Number`
504
505Specifies which version of the `result` object to return (see the "Usage" section
506below for examples).
507
508Passing a `resultVersion` of `0` corresponds to the original, simple format where
509each error is identified by rule name and line number. *This is deprecated.*
510
511Passing a `resultVersion` of `1` corresponds to a detailed format where each error
512includes information about the line number, rule name, alias, description, as well
513as any additional detail or context that is available. *This is deprecated.*
514
515Passing a `resultVersion` of `2` corresponds to a detailed format where each error
516includes information about the line number, rule names, description, as well as any
517additional detail or context that is available. *This is the default.*
518
519Passing a `resultVersion` of `3` corresponds to the detailed version `2` format
520with additional information about how to fix automatically-fixable errors. In this
521mode, all errors that occur on each line are reported (other versions report only
522the first error for each rule).
523
524##### options.markdownItPlugins
525
526Type: `Array` of `Array` of `Function` and plugin parameters
527
528Specifies additional [markdown-it plugins](https://www.npmjs.com/search?q=keywords:markdown-it-plugin)
529to use when parsing input. Plugins can be used to support additional syntax and
530features for advanced scenarios.
531
532Each 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
540Type: `Function` taking (`Error`, `Object`)
541
542Standard completion callback.
543
544#### result
545
546Type: `Object`
547
548Call `result.toString()` for convenience or see below for an example of the
549structure of the `result` object. Passing the value `true` to `toString()`
550uses rule aliases (ex: `no-hard-tabs`) instead of names (ex: `MD010`).
551
552### Config
553
554The `options.config` configuration object is simple and can be stored in a file
555for readability and easy reuse. The `readConfig` and `readConfigSync` functions
556load configuration settings and support the `extends` keyword for referencing
557other files (see above).
558
559By default, configuration files are parsed as JSON (and named `.markdownlint.json`).
560Custom parsers can be provided to handle other formats like JSONC, YAML, and TOML.
561
562Asynchronous 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 */
573function readConfig(file, parsers, callback) { ... }
574```
575
576Synchronous 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 */
586function readConfigSync(file, parsers) { ... }
587```
588
589Promise 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 */
600function readConfig(file, parsers) { ... }
601```
602
603#### file
604
605Type: `String`
606
607Location of configuration file to read.
608
609The `file` is resolved relative to the current working directory. If an `extends`
610key is present once read, its value will be resolved as a path relative to `file`
611and loaded recursively. Settings from a file referenced by `extends` are applied
612first, then those of `file` are applied on top (overriding any of the same keys
613appearing in the referenced file).
614
615#### parsers
616
617Type: *Optional* `Array` of `Function` taking (`String`) and returning `Object`
618
619Array of functions to parse configuration files.
620
621The contents of a configuration file are passed to each parser function until one
622of them returns a value (vs. throwing an exception). Consequently, strict parsers
623should come before flexible parsers.
624
625For example:
626
627```js
628[ JSON.parse, require("toml").parse, require("js-yaml").load ]
629```
630
631#### callback
632
633Type: `Function` taking (`Error`, `Object`)
634
635Standard completion callback.
636
637#### result
638
639Type: `Object`
640
641Configuration object.
642
643## Usage
644
645Invoke `markdownlint` and use the `result` object's `toString` method:
646
647```js
648const markdownlint = require("markdownlint");
649
650const 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
658markdownlint(options, function callback(err, result) {
659 if (!err) {
660 console.log(result.toString());
661 }
662});
663```
664
665Output:
666
667```text
668bad.string: 3: MD010/no-hard-tabs Hard tabs [Column: 19]
669bad.string: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.string"]
670bad.string: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This string fails some rules."]
671bad.string: 1: MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "#bad.string"]
672bad.md: 3: MD010/no-hard-tabs Hard tabs [Column: 17]
673bad.md: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.md"]
674bad.md: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This file fails some rules."]
675bad.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
678Or invoke `markdownlint.sync` for a synchronous call:
679
680```js
681const result = markdownlint.sync(options);
682console.log(result.toString());
683```
684
685To examine the `result` object directly:
686
687```js
688markdownlint(options, function callback(err, result) {
689 if (!err) {
690 console.dir(result, { "colors": true, "depth": null });
691 }
692});
693```
694
695Output:
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
733Integration with the [gulp](https://gulpjs.com/) build system is straightforward:
734
735```js
736const gulp = require("gulp");
737const through2 = require("through2");
738const markdownlint = require("markdownlint");
739
740gulp.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
756Output:
757
758```text
759[00:00:00] Starting 'markdownlint'...
760bad.md: 3: MD010/no-hard-tabs Hard tabs [Column: 17]
761bad.md: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.md"]
762bad.md: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This file fails some rules."]
763bad.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
767Integration with the [Grunt](https://gruntjs.com/) build system is similar:
768
769```js
770const markdownlint = require("markdownlint");
771
772module.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
796Output:
797
798```text
799Running "markdownlint:example" (markdownlint) task
800Warning:
801bad.md: 3: MD010/no-hard-tabs Hard tabs [Column: 17]
802bad.md: 1: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#bad.md"]
803bad.md: 3: MD018/no-missing-space-atx No space after hash on atx style heading [Context: "#This file fails some rules."]
804bad.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
812Generate normal and minified scripts with:
813
814```shell
815npm run build-demo
816```
817
818Then 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
825And call it like so:
826
827```js
828const options = {
829 "strings": {
830 "content": "Some Markdown to lint."
831 }
832};
833const results = window.markdownlint.sync(options).toString();
834```
835
836## Examples
837
838For 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
859See [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