9.7 KiB
Custom Rules
In addition to its built-in rules, markdownlint lets you enhance the linting experience by passing a list of custom rules using the
options.customRules property.
Custom rules can do everything the built-in rules can and are defined inline or imported from another package
(keyword markdownlint-rule on npm).
Custom rules can be disabled, enabled, and customized using the same syntax as built-in rules.
Authoring
Rules are defined by a name (or multiple names), a description, an optional link to more information, one or more tags, and a function that implements the rule's behavior. That function is called once for each file/string input and is passed the parsed input and a function to log any violations.
A simple rule implementation looks like:
module.exports = {
"names": [ "any-blockquote" ],
"description": "Rule that reports an error for any blockquote",
"information": new URL("https://example.com/rules/any-blockquote"),
"tags": [ "test" ],
"function": function rule(params, onError) {
params.tokens.filter(function filterToken(token) {
return token.type === "blockquote_open";
}).forEach(function forToken(blockquote) {
var lines = blockquote.map[1] - blockquote.map[0];
onError({
"lineNumber": blockquote.lineNumber,
"detail": "Blockquote spans " + lines + " line(s).",
"context": blockquote.line.substr(0, 7)
});
});
}
};
A rule is implemented as an Object with one optional and four required properties:
namesis a requiredArrayofStringvalues that identify the rule in output messages and config.descriptionis a requiredStringvalue that describes the rule in output messages.informationis an optional (absolute)URLof a link to more information about the rule.tagsis a requiredArrayofStringvalues that groups related rules for easier customization.functionis a required synchronousFunctionthat implements the rule and is passed two parameters:paramsis anObjectwith properties that describe the content being analyzed:nameis aStringthat identifies the input file/string.tokensis anArrayofmarkdown-itTokenobjects with addedlineandlineNumberproperties.linesis anArrayofStringvalues corresponding to the lines of the input file/string.frontMatterLinesis anArrayofStringvalues corresponding to any front matter (not present inlines).configis anObjectcorresponding to the rule's entry inoptions.config(if present).
onErroris a function that takes a singleObjectparameter with one required and four optional properties:lineNumberis a requiredNumberspecifying the 1-based line number of the error.detailsis an optionalStringwith information about what caused the error.contextis an optionalStringwith relevant text surrounding the error location.rangeis an optionalArraywith twoNumbervalues identifying the 1-based column and length of the error.fixInfois an optionalObjectwith information about how to fix the error (all properties are optional, but at least one ofdeleteCountandinsertTextshould be present; when applying a fix, the delete should be performed before the insert):lineNumberis an optionalNumberspecifying the 1-based line number of the edit.editColumnis an optionalNumberspecifying the 1-based column number of the edit.deleteCountis an optionalNumberspecifying the number of characters to delete (the value-1is used to delete the line).insertTextis an optionalStringspecifying the text to insert.\nis the platform-independent way to add a line break; line breaks should be added at the beginning of a line instead of at the end).
The collection of helper functions shared by the built-in rules is available for use by custom rules in the markdownlint-rule-helpers package.
Examples
- Simple rules used by the project's test cases
- Code for all
markdownlintbuilt-in rules - Package configuration for publishing to npm
- Packages should export a single rule object or an
Arrayof rule objects
- Packages should export a single rule object or an
- Custom rules from the Microsoft/vscode-docs-authoring repository
- Custom rules from the axibase/docs-util repository
- Custom rules from the webhintio/hint repository
References
Params
The Markdown document:
# Title
Text *text* text.
Yields the params object:
{
"name": "doc/example.md",
"tokens": [
{
"type": "heading_open",
"tag": "h1",
"attrs": null,
"map": [ 0, 1 ],
"nesting": 1,
"level": 0,
"children": null,
"content": "",
"markup": "#",
"info": "",
"meta": null,
"block": true,
"hidden": false,
"line": "# Title",
"lineNumber": 1
},
{
"type": "inline",
"tag": "",
"attrs": null,
"map": [ 0, 1 ],
"nesting": 0,
"level": 1,
"children": [
{
"type": "text",
"tag": "",
"attrs": null,
"map": null,
"nesting": 0,
"level": 0,
"children": null,
"content": "Title",
"markup": "",
"info": "",
"meta": null,
"block": false,
"hidden": false,
"lineNumber": 1,
"line": "# Title"
}
],
"content": "Title",
"markup": "",
"info": "",
"meta": null,
"block": true,
"hidden": false,
"line": "# Title",
"lineNumber": 1
},
{
"type": "heading_close",
"tag": "h1",
"attrs": null,
"map": null,
"nesting": -1,
"level": 0,
"children": null,
"content": "",
"markup": "#",
"info": "",
"meta": null,
"block": true,
"hidden": false
},
{
"type": "paragraph_open",
"tag": "p",
"attrs": null,
"map": [ 2, 3 ],
"nesting": 1,
"level": 0,
"children": null,
"content": "",
"markup": "",
"info": "",
"meta": null,
"block": true,
"hidden": false,
"line": "Text *text* text.",
"lineNumber": 3
},
{
"type": "inline",
"tag": "",
"attrs": null,
"map": [ 2, 3 ],
"nesting": 0,
"level": 1,
"children": [
{
"type": "text",
"tag": "",
"attrs": null,
"map": null,
"nesting": 0,
"level": 0,
"children": null,
"content": "Text ",
"markup": "",
"info": "",
"meta": null,
"block": false,
"hidden": false,
"lineNumber": 3,
"line": "Text *text* text."
},
{
"type": "em_open",
"tag": "em",
"attrs": null,
"map": null,
"nesting": 1,
"level": 1,
"children": null,
"content": "",
"markup": "*",
"info": "",
"meta": null,
"block": false,
"hidden": false,
"lineNumber": 3,
"line": "Text *text* text."
},
{
"type": "text",
"tag": "",
"attrs": null,
"map": null,
"nesting": 0,
"level": 1,
"children": null,
"content": "text",
"markup": "",
"info": "",
"meta": null,
"block": false,
"hidden": false,
"lineNumber": 3,
"line": "Text *text* text."
},
{
"type": "em_close",
"tag": "em",
"attrs": null,
"map": null,
"nesting": -1,
"level": 0,
"children": null,
"content": "",
"markup": "*",
"info": "",
"meta": null,
"block": false,
"hidden": false,
"lineNumber": 3,
"line": "Text *text* text."
},
{
"type": "text",
"tag": "",
"attrs": null,
"map": null,
"nesting": 0,
"level": 0,
"children": null,
"content": " text.",
"markup": "",
"info": "",
"meta": null,
"block": false,
"hidden": false,
"lineNumber": 3,
"line": "Text *text* text."
}
],
"content": "Text *text* text.",
"markup": "",
"info": "",
"meta": null,
"block": true,
"hidden": false,
"line": "Text *text* text.",
"lineNumber": 3
},
{
"type": "paragraph_close",
"tag": "p",
"attrs": null,
"map": null,
"nesting": -1,
"level": 0,
"children": null,
"content": "",
"markup": "",
"info": "",
"meta": null,
"block": true,
"hidden": false
}
],
"lines": [
"# Title",
"",
"Text *text* text.",
""
],
"frontMatterLines": [],
"config": {
"customValue1": "abc",
"customValue2": 123
}
}