9.3 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:
const { URL } = require("url");
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 four required properties:
namesis anArrayofStringvalues that identify the rule in output messages and config.descriptionis aStringvalue that describes the rule in output messages.informationis an optional (absolute)URLof a link to more information about the rule.tagsis anArrayofStringvalues that groups related rules for easier customization.functionis a 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 three 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: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 count of characters to delete with the edit.insertTextis an optionalStringspecifying text to insert as part of the edit.
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
}
}