mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-21 21:30:47 +02:00
Enable custom rules to use the micromark parser, export micromark helpers for reuse.
This commit is contained in:
parent
264da24dae
commit
5cc40c54b7
16 changed files with 4109 additions and 113 deletions
57
README.md
57
README.md
|
@ -13,22 +13,31 @@ npm install markdownlint --save-dev
|
|||
|
||||
## Overview
|
||||
|
||||
The [Markdown](https://en.wikipedia.org/wiki/Markdown) markup language
|
||||
is designed to be easy to read, write, and understand. It succeeds -
|
||||
and its flexibility is both a benefit and a drawback. Many styles are
|
||||
possible, so formatting can be inconsistent. Some constructs don't
|
||||
work well in all parsers and should be avoided. The
|
||||
[CommonMark](https://commonmark.org/) specification standardizes
|
||||
parsers - but not authors.
|
||||
The [Markdown][markdown] markup language is designed to be easy to read, write,
|
||||
and understand. It succeeds - and its flexibility is both a benefit and a
|
||||
drawback. Many styles are possible, so formatting can be inconsistent; some
|
||||
constructs don't work well in all parsers and should be avoided.
|
||||
|
||||
`markdownlint` is a
|
||||
[static analysis](https://en.wikipedia.org/wiki/Static_program_analysis)
|
||||
tool for [Node.js](https://nodejs.org/) with a library of rules
|
||||
to enforce standards and consistency for Markdown files. It was
|
||||
inspired by - and heavily influenced by - Mark Harrison's
|
||||
[markdownlint](https://github.com/markdownlint/markdownlint) for
|
||||
[Ruby](https://www.ruby-lang.org/). The initial rules, rule documentation,
|
||||
and test cases came directly from that project.
|
||||
`markdownlint` is a [static analysis][static-analysis] tool for
|
||||
[Node.js][nodejs] with a library of rules to enforce standards and consistency
|
||||
for Markdown files. It was inspired by - and heavily influenced by - Mark
|
||||
Harrison's [markdownlint][markdownlint-ruby] for Ruby. The initial rules, rule
|
||||
documentation, and test cases came from that project.
|
||||
|
||||
`markdownlint` uses the [`micromark`][micromark] parser and honors the
|
||||
[CommonMark][commonmark] specification for Markdown. It additionally supports
|
||||
popular [GitHub Flavored Markdown (GFM)][gfm] syntax like autolinks and tables
|
||||
as well as directives, footnotes, and math syntax - all implemented by
|
||||
[`micromark` extensions][micromark-extensions].
|
||||
|
||||
[commonmark]: https://commonmark.org/
|
||||
[gfm]: https://github.github.com/gfm/
|
||||
[markdown]: https://en.wikipedia.org/wiki/Markdown
|
||||
[markdownlint-ruby]: https://github.com/markdownlint/markdownlint
|
||||
[micromark]: https://github.com/micromark/micromark
|
||||
[micromark-extensions]: https://github.com/micromark/micromark?tab=readme-ov-file#list-of-extensions
|
||||
[nodejs]: https://nodejs.org/
|
||||
[static-analysis]: https://en.wikipedia.org/wiki/Static_program_analysis
|
||||
|
||||
### Related
|
||||
|
||||
|
@ -565,7 +574,7 @@ Type: `Array` of `Array` of `Function` and plugin parameters
|
|||
|
||||
Specifies additional [`markdown-it` plugins][markdown-it-plugin] to use when
|
||||
parsing input. Plugins can be used to support additional syntax and features for
|
||||
advanced scenarios.
|
||||
advanced scenarios. *Deprecated.*
|
||||
|
||||
[markdown-it-plugin]: https://www.npmjs.com/search?q=keywords:markdown-it-plugin
|
||||
|
||||
|
@ -601,23 +610,20 @@ Specifies which version of the `result` object to return (see the "Usage"
|
|||
section below for examples).
|
||||
|
||||
Passing a `resultVersion` of `0` corresponds to the original, simple format
|
||||
where each error is identified by rule name and line number. *This is
|
||||
deprecated.*
|
||||
where each error is identified by rule name and line number. *Deprecated*
|
||||
|
||||
Passing a `resultVersion` of `1` corresponds to a detailed format where each
|
||||
error includes information about the line number, rule name, alias, description,
|
||||
as well as any additional detail or context that is available. *This is
|
||||
deprecated.*
|
||||
as well as any additional detail or context that is available. *Deprecated*
|
||||
|
||||
Passing a `resultVersion` of `2` corresponds to a detailed format where each
|
||||
error includes information about the line number, rule names, description, as
|
||||
well as any additional detail or context that is available. *This is
|
||||
deprecated.*
|
||||
well as any additional detail or context that is available. *Deprecated*
|
||||
|
||||
Passing a `resultVersion` of `3` corresponds to the detailed version `2` format
|
||||
with additional information about how to fix automatically-fixable errors. In
|
||||
this mode, all errors that occur on each line are reported (other versions
|
||||
report only the first error for each rule). *This is the default.*
|
||||
report only the first error for each rule). This is the default behavior.
|
||||
|
||||
##### options.strings
|
||||
|
||||
|
@ -946,10 +952,11 @@ Generate normal and minified scripts with:
|
|||
npm run build-demo
|
||||
```
|
||||
|
||||
Then reference `markdown-it` and `markdownlint`:
|
||||
Then reference `markdownlint` and `micromark` scripts:
|
||||
|
||||
```html
|
||||
<script src="demo/markdown-it.min.js"></script>
|
||||
<script src="demo/micromark-browser.js"></script>
|
||||
<script src="demo/micromark-html-browser.js"></script>
|
||||
<script src="demo/markdownlint-browser.min.js"></script>
|
||||
```
|
||||
|
||||
|
|
|
@ -1710,7 +1710,7 @@ function validateRuleList(ruleList, synchronous) {
|
|||
!result &&
|
||||
(rule.parser !== undefined) &&
|
||||
(rule.parser !== "markdownit") &&
|
||||
!((customIndex < 0) && (rule.parser === "micromark")) &&
|
||||
(rule.parser !== "micromark") &&
|
||||
(rule.parser !== "none")
|
||||
) {
|
||||
result = newError("parser", rule.parser);
|
||||
|
|
|
@ -14,9 +14,8 @@ built-in rules.
|
|||
For simple requirements like disallowing certain characters or patterns,
|
||||
the community-developed
|
||||
[markdownlint-rule-search-replace][markdownlint-rule-search-replace]
|
||||
plug-in can be used.
|
||||
This plug-in allows anyone to create a set of simple text-replacement rules in
|
||||
JSON without needing to write any code.
|
||||
plug-in can be used. This plug-in allows anyone to create a set of simple
|
||||
text-replacement rules without needing to write code.
|
||||
|
||||
[markdownlint-rule-search-replace]: https://www.npmjs.com/package/markdownlint-rule-search-replace
|
||||
|
||||
|
@ -27,29 +26,62 @@ 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:
|
||||
Custom rules can (should) operate on a structured set of tokens based on the
|
||||
[`micromark`][micromark] `parser` (this is preferred). Alternatively, custom
|
||||
rules can operate on a structured set of tokens based on the
|
||||
[`markdown-it`][markdown-it] `parser` (legacy support). Finally, custom rules
|
||||
can operate directly on text with the `none` `parser`.
|
||||
|
||||
A simple rule implementation using the `micromark` parser to report a violation
|
||||
for any use of blockquotes might look like:
|
||||
|
||||
```javascript
|
||||
/** @type import("markdownlint").Rule */
|
||||
module.exports = {
|
||||
"names": [ "any-blockquote" ],
|
||||
"names": [ "any-blockquote-micromark" ],
|
||||
"description": "Rule that reports an error for any blockquote",
|
||||
"information": new URL("https://example.com/rules/any-blockquote"),
|
||||
"tags": [ "test" ],
|
||||
"parser": "micromark",
|
||||
"function": (params, onError) => {
|
||||
const blockquotes = params.parsers.micromark.tokens
|
||||
.filter(((token) => token.type === "blockQuote"));
|
||||
for (const blockquote of blockquotes) {
|
||||
const lines = blockquote.endLine - blockquote.startLine + 1;
|
||||
onError({
|
||||
"lineNumber": blockquote.startLine,
|
||||
"detail": "Blockquote spans " + lines + " line(s).",
|
||||
"context": params.lines[blockquote.startLine - 1]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That same rule implemented using the `markdown-it` parser might look like:
|
||||
|
||||
```javascript
|
||||
/** @type import("markdownlint").Rule */
|
||||
module.exports = {
|
||||
"names": [ "any-blockquote-markdown-it" ],
|
||||
"description": "Rule that reports an error for any blockquote",
|
||||
"information": new URL("https://example.com/rules/any-blockquote"),
|
||||
"tags": [ "test" ],
|
||||
"parser": "markdownit",
|
||||
"function": function rule(params, onError) {
|
||||
params.parsers.markdownit.tokens.filter(function filterToken(token) {
|
||||
return token.type === "blockquote_open";
|
||||
}).forEach(function forToken(blockquote) {
|
||||
var lines = blockquote.map[1] - blockquote.map[0];
|
||||
"function": (params, onError) => {
|
||||
const blockquotes = params.parsers.markdownit.tokens
|
||||
.filter(((token) => token.type === "blockquote_open"));
|
||||
for (const blockquote of blockquotes) {
|
||||
const [ startIndex, endIndex ] = blockquote.map;
|
||||
const lines = endIndex - startIndex;
|
||||
onError({
|
||||
"lineNumber": blockquote.lineNumber,
|
||||
"detail": "Blockquote spans " + lines + " line(s).",
|
||||
"context": blockquote.line.substr(0, 7)
|
||||
"context": blockquote.line
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
A rule is implemented as an `Object`:
|
||||
|
@ -62,9 +94,8 @@ A rule is implemented as an `Object`:
|
|||
about the rule.
|
||||
- `tags` is a required `Array` of `String` values that groups related rules for
|
||||
easier customization.
|
||||
- `parser` is a required `String` value `"markdownit" | "none"` that specifies
|
||||
the parser data used via `params.parsers` (see below).
|
||||
- Note: The value `"micromark"` is valid but is NOT currently supported.
|
||||
- `parser` is a required `String` value `"markdownit" | "micromark" | "none"`
|
||||
that specifies the parser data used via `params.parsers` (see below).
|
||||
- `asynchronous` is an optional `Boolean` value that indicates whether the rule
|
||||
returns a `Promise` and runs asynchronously.
|
||||
- `function` is a required `Function` that implements the rule and is passed two
|
||||
|
@ -79,7 +110,10 @@ A rule is implemented as an `Object`:
|
|||
- `tokens` is an `Array` of [`markdown-it` `Token`s][markdown-it-token]
|
||||
with added `line` and `lineNumber` properties. (This property was
|
||||
previously on the `params` object.)
|
||||
- Samples for `tokens` are available via [test snapshots][tokens].
|
||||
- `micromark` is an `Object` that provides access to output from the
|
||||
[`micromark`][micromark] parser.
|
||||
- `tokens` is an `Array` of [`MicromarkToken`][micromark-token] objects.
|
||||
- Samples for both `tokens` are available via [test snapshots][tokens].
|
||||
- `lines` is an `Array` of `String` values corresponding to the lines of the
|
||||
input file/string.
|
||||
- `frontMatterLines` is an `Array` of `String` values corresponding to any
|
||||
|
@ -152,6 +186,8 @@ exception.
|
|||
[markdown-it]: https://github.com/markdown-it/markdown-it
|
||||
[markdown-it-token]: https://markdown-it.github.io/markdown-it/#Token
|
||||
[markdownlint-rule]: https://www.npmjs.com/search?q=keywords:markdownlint-rule
|
||||
[micromark]: https://github.com/micromark/micromark
|
||||
[micromark-token]: ../lib/markdownlint.d.ts
|
||||
[rule-helpers]: https://www.npmjs.com/package/markdownlint-rule-helpers
|
||||
[options-custom-rules]: ../README.md#optionscustomrules
|
||||
[test-rules]: ../test/rules
|
||||
|
|
1
helpers/.npmignore
Normal file
1
helpers/.npmignore
Normal file
|
@ -0,0 +1 @@
|
|||
test.js
|
|
@ -3,7 +3,10 @@
|
|||
"version": "0.26.0",
|
||||
"description": "A collection of markdownlint helper functions for custom rules",
|
||||
"main": "./helpers.js",
|
||||
"exports": "./helpers.js",
|
||||
"exports": {
|
||||
".": "./helpers.js",
|
||||
"./micromark": "./micromark-helpers.cjs"
|
||||
},
|
||||
"author": "David Anson (https://dlaa.me/)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/DavidAnson/markdownlint",
|
||||
|
|
28
helpers/test.cjs
Normal file
28
helpers/test.cjs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// @ts-check
|
||||
|
||||
"use strict";
|
||||
|
||||
// eslint-disable-next-line n/no-extraneous-require
|
||||
const test = require("ava").default;
|
||||
const { "exports": packageExports, name } = require("../helpers/package.json");
|
||||
|
||||
const exportMappings = new Map([
|
||||
[ ".", "../helpers/helpers.js" ],
|
||||
[ "./micromark", "../helpers/micromark-helpers.cjs" ]
|
||||
]);
|
||||
|
||||
test("exportMappings", (t) => {
|
||||
t.deepEqual(
|
||||
Object.keys(packageExports),
|
||||
[ ...exportMappings.keys() ]
|
||||
);
|
||||
});
|
||||
|
||||
for (const [ exportName, exportPath ] of exportMappings) {
|
||||
test(exportName, (t) => {
|
||||
t.is(
|
||||
require(exportName.replace(/^\./u, name)),
|
||||
require(exportPath)
|
||||
);
|
||||
});
|
||||
}
|
|
@ -58,7 +58,7 @@ function validateRuleList(ruleList, synchronous) {
|
|||
!result &&
|
||||
(rule.parser !== undefined) &&
|
||||
(rule.parser !== "markdownit") &&
|
||||
!((customIndex < 0) && (rule.parser === "micromark")) &&
|
||||
(rule.parser !== "micromark") &&
|
||||
(rule.parser !== "none")
|
||||
) {
|
||||
result = newError("parser", rule.parser);
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"lint-test-repos": "ava --timeout=10m test/markdownlint-test-repos-*.js",
|
||||
"serial-config-docs": "npm run build-config && npm run build-docs",
|
||||
"serial-declaration-demo": "npm run build-declaration && npm-run-all --continue-on-error --parallel build-demo test-declaration",
|
||||
"test": "ava --timeout=30s test/markdownlint-test.js test/markdownlint-test-config.js test/markdownlint-test-custom-rules.js test/markdownlint-test-helpers.js test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.js test/markdownlint-test-scenarios.js",
|
||||
"test": "ava --timeout=30s test/markdownlint-test.js test/markdownlint-test-config.js test/markdownlint-test-custom-rules.js test/markdownlint-test-helpers.js test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.js test/markdownlint-test-scenarios.js helpers/test.cjs",
|
||||
"test-cover": "c8 --100 npm test",
|
||||
"test-declaration": "cd example/typescript && tsc --module nodenext && tsc --module commonjs && node type-check.js",
|
||||
"test-extra": "ava --timeout=10m test/markdownlint-test-extra-parse.js test/markdownlint-test-extra-type.js",
|
||||
|
|
|
@ -7,6 +7,7 @@ const test = require("ava").default;
|
|||
const markdownlint = require("../lib/markdownlint");
|
||||
const customRules = require("./rules/rules.js");
|
||||
const { homepage, version } = require("../package.json");
|
||||
const { newLineRe } = require("../helpers/helpers.js");
|
||||
|
||||
test("customRulesV0", (t) => new Promise((resolve) => {
|
||||
t.plan(4);
|
||||
|
@ -22,7 +23,8 @@ test("customRulesV0", (t) => new Promise((resolve) => {
|
|||
t.falsy(err);
|
||||
const expectedResult = {};
|
||||
expectedResult[customRulesMd] = {
|
||||
"any-blockquote": [ 12 ],
|
||||
"any-blockquote-markdown-it": [ 12 ],
|
||||
"any-blockquote-micromark": [ 12 ],
|
||||
"every-n-lines": [ 2, 4, 6, 10, 12 ],
|
||||
"first-line": [ 1 ],
|
||||
"letters-E-X": [ 3, 7 ]
|
||||
|
@ -31,7 +33,9 @@ test("customRulesV0", (t) => new Promise((resolve) => {
|
|||
// @ts-ignore
|
||||
let actualMessage = actualResult.toString();
|
||||
let expectedMessage =
|
||||
"./test/custom-rules.md: 12: any-blockquote" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-markdown-it" +
|
||||
" Rule that reports an error for any blockquote\n" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-micromark" +
|
||||
" Rule that reports an error for any blockquote\n" +
|
||||
"./test/custom-rules.md: 2: every-n-lines" +
|
||||
" Rule that reports an error every N lines\n" +
|
||||
|
@ -53,7 +57,9 @@ test("customRulesV0", (t) => new Promise((resolve) => {
|
|||
// @ts-ignore
|
||||
actualMessage = actualResult.toString(true);
|
||||
expectedMessage =
|
||||
"./test/custom-rules.md: 12: any-blockquote" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-markdown-it" +
|
||||
" Rule that reports an error for any blockquote\n" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-micromark" +
|
||||
" Rule that reports an error for any blockquote\n" +
|
||||
"./test/custom-rules.md: 2: every-n-lines" +
|
||||
" Rule that reports an error every N lines\n" +
|
||||
|
@ -91,13 +97,22 @@ test("customRulesV1", (t) => new Promise((resolve) => {
|
|||
const expectedResult = {};
|
||||
expectedResult[customRulesMd] = [
|
||||
{ "lineNumber": 12,
|
||||
"ruleName": "any-blockquote",
|
||||
"ruleAlias": "any-blockquote",
|
||||
"ruleName": "any-blockquote-markdown-it",
|
||||
"ruleAlias": "any-blockquote-markdown-it",
|
||||
"ruleDescription": "Rule that reports an error for any blockquote",
|
||||
"ruleInformation":
|
||||
`${homepage}/blob/main/test/rules/any-blockquote.js`,
|
||||
"errorDetail": "Blockquote spans 1 line(s).",
|
||||
"errorContext": "> Block",
|
||||
"errorContext": "> Blockquote",
|
||||
"errorRange": null },
|
||||
{ "lineNumber": 12,
|
||||
"ruleName": "any-blockquote-micromark",
|
||||
"ruleAlias": "any-blockquote-micromark",
|
||||
"ruleDescription": "Rule that reports an error for any blockquote",
|
||||
"ruleInformation":
|
||||
`${homepage}/blob/main/test/rules/any-blockquote.js`,
|
||||
"errorDetail": "Blockquote spans 1 line(s).",
|
||||
"errorContext": "> Blockquote",
|
||||
"errorRange": null },
|
||||
{ "lineNumber": 2,
|
||||
"ruleName": "every-n-lines",
|
||||
|
@ -170,9 +185,12 @@ test("customRulesV1", (t) => new Promise((resolve) => {
|
|||
// @ts-ignore
|
||||
const actualMessage = actualResult.toString();
|
||||
const expectedMessage =
|
||||
"./test/custom-rules.md: 12: any-blockquote/any-blockquote" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-markdown-it/any-blockquote-markdown-it" +
|
||||
" Rule that reports an error for any blockquote" +
|
||||
" [Blockquote spans 1 line(s).] [Context: \"> Block\"]\n" +
|
||||
" [Blockquote spans 1 line(s).] [Context: \"> Blockquote\"]\n" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-micromark/any-blockquote-micromark" +
|
||||
" Rule that reports an error for any blockquote" +
|
||||
" [Blockquote spans 1 line(s).] [Context: \"> Blockquote\"]\n" +
|
||||
"./test/custom-rules.md: 2: every-n-lines/every-n-lines" +
|
||||
" Rule that reports an error every N lines [Line number 2]\n" +
|
||||
"./test/custom-rules.md: 4: every-n-lines/every-n-lines" +
|
||||
|
@ -211,12 +229,20 @@ test("customRulesV2", (t) => new Promise((resolve) => {
|
|||
const expectedResult = {};
|
||||
expectedResult[customRulesMd] = [
|
||||
{ "lineNumber": 12,
|
||||
"ruleNames": [ "any-blockquote" ],
|
||||
"ruleNames": [ "any-blockquote-markdown-it" ],
|
||||
"ruleDescription": "Rule that reports an error for any blockquote",
|
||||
"ruleInformation":
|
||||
`${homepage}/blob/main/test/rules/any-blockquote.js`,
|
||||
"errorDetail": "Blockquote spans 1 line(s).",
|
||||
"errorContext": "> Block",
|
||||
"errorContext": "> Blockquote",
|
||||
"errorRange": null },
|
||||
{ "lineNumber": 12,
|
||||
"ruleNames": [ "any-blockquote-micromark" ],
|
||||
"ruleDescription": "Rule that reports an error for any blockquote",
|
||||
"ruleInformation":
|
||||
`${homepage}/blob/main/test/rules/any-blockquote.js`,
|
||||
"errorDetail": "Blockquote spans 1 line(s).",
|
||||
"errorContext": "> Blockquote",
|
||||
"errorRange": null },
|
||||
{ "lineNumber": 2,
|
||||
"ruleNames": [ "every-n-lines" ],
|
||||
|
@ -281,9 +307,12 @@ test("customRulesV2", (t) => new Promise((resolve) => {
|
|||
// @ts-ignore
|
||||
const actualMessage = actualResult.toString();
|
||||
const expectedMessage =
|
||||
"./test/custom-rules.md: 12: any-blockquote" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-markdown-it" +
|
||||
" Rule that reports an error for any blockquote" +
|
||||
" [Blockquote spans 1 line(s).] [Context: \"> Block\"]\n" +
|
||||
" [Blockquote spans 1 line(s).] [Context: \"> Blockquote\"]\n" +
|
||||
"./test/custom-rules.md: 12: any-blockquote-micromark" +
|
||||
" Rule that reports an error for any blockquote" +
|
||||
" [Blockquote spans 1 line(s).] [Context: \"> Blockquote\"]\n" +
|
||||
"./test/custom-rules.md: 2: every-n-lines" +
|
||||
" Rule that reports an error every N lines [Line number 2]\n" +
|
||||
"./test/custom-rules.md: 4: every-n-lines" +
|
||||
|
@ -328,7 +357,8 @@ test("customRulesConfig", (t) => new Promise((resolve) => {
|
|||
t.falsy(err);
|
||||
const expectedResult = {};
|
||||
expectedResult[customRulesMd] = {
|
||||
"any-blockquote": [ 12 ],
|
||||
"any-blockquote-markdown-it": [ 12 ],
|
||||
"any-blockquote-micromark": [ 12 ],
|
||||
"every-n-lines": [ 3, 6, 12 ],
|
||||
"first-line": [ 1 ],
|
||||
"letters-E-X": [ 7 ]
|
||||
|
@ -402,7 +432,7 @@ test("customRulesBadProperty", (t) => {
|
|||
]) {
|
||||
const { propertyName, propertyValues } = testCase;
|
||||
for (const propertyValue of propertyValues) {
|
||||
const badRule = { ...customRules.anyBlockquote };
|
||||
const badRule = { ...customRules.firstLine };
|
||||
badRule[propertyName] = propertyValue;
|
||||
// eslint-disable-next-line jsdoc/valid-types
|
||||
/** @type import("../lib/markdownlint").Options */
|
||||
|
@ -592,7 +622,7 @@ test("customRulesParserMarkdownIt", (t) => {
|
|||
});
|
||||
|
||||
test("customRulesParserMicromark", (t) => {
|
||||
t.plan(1);
|
||||
t.plan(5);
|
||||
// eslint-disable-next-line jsdoc/valid-types
|
||||
/** @type import("../lib/markdownlint").Options */
|
||||
const options = {
|
||||
|
@ -603,12 +633,12 @@ test("customRulesParserMicromark", (t) => {
|
|||
"tags": [ "tag" ],
|
||||
"parser": "micromark",
|
||||
"function":
|
||||
() => {
|
||||
// t.false(Object.keys(params).includes("tokens"));
|
||||
// t.is(Object.keys(params.parsers).length, 1);
|
||||
// t.truthy(params.parsers.micromark);
|
||||
// t.is(Object.keys(params.parsers.micromark).length, 1);
|
||||
// t.truthy(params.parsers.micromark.tokens);
|
||||
(params) => {
|
||||
t.false(Object.keys(params).includes("tokens"));
|
||||
t.is(Object.keys(params.parsers).length, 1);
|
||||
t.truthy(params.parsers.micromark);
|
||||
t.is(Object.keys(params.parsers.micromark).length, 1);
|
||||
t.truthy(params.parsers.micromark.tokens);
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -616,10 +646,7 @@ test("customRulesParserMicromark", (t) => {
|
|||
"string": "# Heading\n"
|
||||
}
|
||||
};
|
||||
return markdownlint.promises.markdownlint(options).catch((error) => {
|
||||
// parser "micromark" currently unsupported for custom rules
|
||||
t.is(error.message, "Property 'parser' of custom rule at index 0 is incorrect: 'micromark'.");
|
||||
});
|
||||
return markdownlint.promises.markdownlint(options).then(() => null);
|
||||
});
|
||||
|
||||
test("customRulesMarkdownItParamsTokensSameObject", (t) => {
|
||||
|
@ -664,10 +691,41 @@ test("customRulesMarkdownItTokensSnapshot", (t) => {
|
|||
}
|
||||
}
|
||||
],
|
||||
"files": "./test/every-markdown-syntax.md",
|
||||
"noInlineConfig": true
|
||||
};
|
||||
return markdownlint.promises.markdownlint(options).then(() => null);
|
||||
return fs
|
||||
.readFile("./test/every-markdown-syntax.md", "utf8")
|
||||
.then((content) => {
|
||||
options.strings = { "content": content.split(newLineRe).join("\n") };
|
||||
return markdownlint.promises.markdownlint(options).then(() => null);
|
||||
});
|
||||
});
|
||||
|
||||
test("customRulesMicromarkTokensSnapshot", (t) => {
|
||||
t.plan(1);
|
||||
// eslint-disable-next-line jsdoc/valid-types
|
||||
/** @type import("../lib/markdownlint").Options */
|
||||
const options = {
|
||||
"customRules": [
|
||||
{
|
||||
"names": [ "name" ],
|
||||
"description": "description",
|
||||
"tags": [ "tag" ],
|
||||
"parser": "micromark",
|
||||
"function":
|
||||
(params) => {
|
||||
t.snapshot(params.parsers.micromark.tokens, "Unexpected tokens");
|
||||
}
|
||||
}
|
||||
],
|
||||
"noInlineConfig": true
|
||||
};
|
||||
return fs
|
||||
.readFile("./test/every-markdown-syntax.md", "utf8")
|
||||
.then((content) => {
|
||||
options.strings = { "content": content.split(newLineRe).join("\n") };
|
||||
return markdownlint.promises.markdownlint(options).then(() => null);
|
||||
});
|
||||
});
|
||||
|
||||
test("customRulesDefinitionStatic", (t) => new Promise((resolve) => {
|
||||
|
|
|
@ -17,26 +17,9 @@ const testTokens = new Promise((resolve, reject) => {
|
|||
testContent.then(parse).then(resolve, reject);
|
||||
});
|
||||
|
||||
const cloneToken = (token) => {
|
||||
for (const child of token.children) {
|
||||
const expectedParent = (token.type ? token : null);
|
||||
if (child.parent !== expectedParent) {
|
||||
throw new Error("Unexpected parent.");
|
||||
}
|
||||
}
|
||||
const clone = { ...token };
|
||||
delete clone.parent;
|
||||
clone.children = clone.children.map(cloneToken);
|
||||
return clone;
|
||||
};
|
||||
|
||||
const cloneTokens = (tokens) => (
|
||||
cloneToken({ "children": tokens }).children
|
||||
);
|
||||
|
||||
test("parse", async(t) => {
|
||||
t.plan(1);
|
||||
t.snapshot(cloneTokens(await testTokens), "Unexpected tokens");
|
||||
t.snapshot(await testTokens, "Unexpected tokens");
|
||||
});
|
||||
|
||||
test("getEvents/filterByPredicate", async(t) => {
|
||||
|
|
|
@ -2,26 +2,54 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/** @type import("../../lib/markdownlint").Rule */
|
||||
module.exports = {
|
||||
"names": [ "any-blockquote" ],
|
||||
"description": "Rule that reports an error for any blockquote",
|
||||
"information": new URL(
|
||||
"https://github.com/DavidAnson/markdownlint" +
|
||||
"/blob/main/test/rules/any-blockquote.js"
|
||||
),
|
||||
"tags": [ "test" ],
|
||||
"parser": "markdownit",
|
||||
"function": (params, onError) => {
|
||||
const blockquotes = params.parsers.markdownit.tokens
|
||||
.filter(((token) => token.type === "blockquote_open"));
|
||||
for (const blockquote of blockquotes) {
|
||||
const lines = blockquote.map[1] - blockquote.map[0];
|
||||
onError({
|
||||
"lineNumber": blockquote.lineNumber,
|
||||
"detail": "Blockquote spans " + lines + " line(s).",
|
||||
"context": blockquote.line.substr(0, 7)
|
||||
});
|
||||
/** @type import("../../lib/markdownlint").Rule[] */
|
||||
module.exports = [
|
||||
|
||||
// micromark parser (preferred)
|
||||
{
|
||||
"names": [ "any-blockquote-micromark" ],
|
||||
"description": "Rule that reports an error for any blockquote",
|
||||
"information": new URL(
|
||||
"https://github.com/DavidAnson/markdownlint/blob/main/test/rules/any-blockquote.js"
|
||||
),
|
||||
"tags": [ "test" ],
|
||||
"parser": "micromark",
|
||||
"function": (params, onError) => {
|
||||
const blockquotes = params.parsers.micromark.tokens
|
||||
.filter(((token) => token.type === "blockQuote"));
|
||||
for (const blockquote of blockquotes) {
|
||||
const lines = blockquote.endLine - blockquote.startLine + 1;
|
||||
onError({
|
||||
"lineNumber": blockquote.startLine,
|
||||
"detail": "Blockquote spans " + lines + " line(s).",
|
||||
"context": params.lines[blockquote.startLine - 1]
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// markdown-it parser (legacy)
|
||||
{
|
||||
"names": [ "any-blockquote-markdown-it" ],
|
||||
"description": "Rule that reports an error for any blockquote",
|
||||
"information": new URL(
|
||||
"https://github.com/DavidAnson/markdownlint/blob/main/test/rules/any-blockquote.js"
|
||||
),
|
||||
"tags": [ "test" ],
|
||||
"parser": "markdownit",
|
||||
"function": (params, onError) => {
|
||||
const blockquotes = params.parsers.markdownit.tokens
|
||||
.filter(((token) => token.type === "blockquote_open"));
|
||||
for (const blockquote of blockquotes) {
|
||||
const [ startIndex, endIndex ] = blockquote.map;
|
||||
const lines = endIndex - startIndex;
|
||||
onError({
|
||||
"lineNumber": blockquote.lineNumber,
|
||||
"detail": "Blockquote spans " + lines + " line(s).",
|
||||
"context": blockquote.line
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
];
|
||||
|
|
|
@ -21,7 +21,7 @@ const validateJson = require("./validate-json");
|
|||
module.exports.validateJson = validateJson;
|
||||
|
||||
module.exports.all = [
|
||||
anyBlockquote,
|
||||
...anyBlockquote,
|
||||
everyNLines,
|
||||
firstLine,
|
||||
lettersEX,
|
||||
|
|
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue