Reimplement MD014/commands-show-output using micromark tokens.

This commit is contained in:
David Anson 2024-06-22 15:12:37 -07:00
parent ec957029a5
commit 347302169c
6 changed files with 132 additions and 80 deletions

View file

@ -4115,7 +4115,8 @@ module.exports = {
const { addErrorContext, filterTokens } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { addErrorContext } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { filterByTypes } = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs");
const dollarCommandRe = /^(\s*)(\$\s+)/; const dollarCommandRe = /^(\s*)(\$\s+)/;
@ -4125,47 +4126,45 @@ module.exports = {
"names": [ "MD014", "commands-show-output" ], "names": [ "MD014", "commands-show-output" ],
"description": "Dollar signs used before commands without showing output", "description": "Dollar signs used before commands without showing output",
"tags": [ "code" ], "tags": [ "code" ],
"parser": "markdownit", "parser": "micromark",
"function": function MD014(params, onError) { "function": function MD014(params, onError) {
for (const type of [ "code_block", "fence" ]) { const codeBlocks = filterByTypes(
filterTokens(params, type, (token) => { params.parsers.micromark.tokens,
const margin = (token.type === "fence") ? 1 : 0; [ "codeFenced", "codeIndented" ]
const dollarInstances = []; );
let allDollars = true; for (const codeBlock of codeBlocks) {
for (let i = token.map[0] + margin; i < token.map[1] - margin; i++) { const codeFlowValues = filterByTypes(
const line = params.lines[i]; codeBlock.children,
const lineTrim = line.trim(); [ "codeFlowValue" ]
if (lineTrim) { );
const match = dollarCommandRe.exec(line); const dollarMatches = codeFlowValues.
if (match) { map((codeFlowValue) => ({
const column = match[1].length + 1; "result": codeFlowValue.text.match(dollarCommandRe),
const length = match[2].length; "startColumn": codeFlowValue.startColumn,
dollarInstances.push([ i, lineTrim, column, length ]); "startLine": codeFlowValue.startLine,
} else { "text": codeFlowValue.text
allDollars = false; })).
filter((dollarMatch) => dollarMatch.result);
if (dollarMatches.length === codeFlowValues.length) {
for (const dollarMatch of dollarMatches) {
// @ts-ignore
const column = dollarMatch.startColumn + dollarMatch.result[1].length;
// @ts-ignore
const length = dollarMatch.result[2].length;
addErrorContext(
onError,
dollarMatch.startLine,
dollarMatch.text,
undefined,
undefined,
[ column, length ],
{
"editColumn": column,
"deleteCount": length
} }
} );
} }
if (allDollars) { }
for (const instance of dollarInstances) {
const [ i, lineTrim, column, length ] = instance;
addErrorContext(
onError,
// @ts-ignore
i + 1,
// @ts-ignore
lineTrim,
null,
null,
[ column, length ],
{
"editColumn": column,
"deleteCount": length
}
);
}
}
});
} }
} }
}; };

View file

@ -2,7 +2,8 @@
"use strict"; "use strict";
const { addErrorContext, filterTokens } = require("../helpers"); const { addErrorContext } = require("../helpers");
const { filterByTypes } = require("../helpers/micromark.cjs");
const dollarCommandRe = /^(\s*)(\$\s+)/; const dollarCommandRe = /^(\s*)(\$\s+)/;
@ -12,47 +13,45 @@ module.exports = {
"names": [ "MD014", "commands-show-output" ], "names": [ "MD014", "commands-show-output" ],
"description": "Dollar signs used before commands without showing output", "description": "Dollar signs used before commands without showing output",
"tags": [ "code" ], "tags": [ "code" ],
"parser": "markdownit", "parser": "micromark",
"function": function MD014(params, onError) { "function": function MD014(params, onError) {
for (const type of [ "code_block", "fence" ]) { const codeBlocks = filterByTypes(
filterTokens(params, type, (token) => { params.parsers.micromark.tokens,
const margin = (token.type === "fence") ? 1 : 0; [ "codeFenced", "codeIndented" ]
const dollarInstances = []; );
let allDollars = true; for (const codeBlock of codeBlocks) {
for (let i = token.map[0] + margin; i < token.map[1] - margin; i++) { const codeFlowValues = filterByTypes(
const line = params.lines[i]; codeBlock.children,
const lineTrim = line.trim(); [ "codeFlowValue" ]
if (lineTrim) { );
const match = dollarCommandRe.exec(line); const dollarMatches = codeFlowValues.
if (match) { map((codeFlowValue) => ({
const column = match[1].length + 1; "result": codeFlowValue.text.match(dollarCommandRe),
const length = match[2].length; "startColumn": codeFlowValue.startColumn,
dollarInstances.push([ i, lineTrim, column, length ]); "startLine": codeFlowValue.startLine,
} else { "text": codeFlowValue.text
allDollars = false; })).
filter((dollarMatch) => dollarMatch.result);
if (dollarMatches.length === codeFlowValues.length) {
for (const dollarMatch of dollarMatches) {
// @ts-ignore
const column = dollarMatch.startColumn + dollarMatch.result[1].length;
// @ts-ignore
const length = dollarMatch.result[2].length;
addErrorContext(
onError,
dollarMatch.startLine,
dollarMatch.text,
undefined,
undefined,
[ column, length ],
{
"editColumn": column,
"deleteCount": length
} }
} );
} }
if (allDollars) { }
for (const instance of dollarInstances) {
const [ i, lineTrim, column, length ] = instance;
addErrorContext(
onError,
// @ts-ignore
i + 1,
// @ts-ignore
lineTrim,
null,
null,
[ column, length ],
{
"editColumn": column,
"deleteCount": length
}
);
}
}
});
} }
} }
}; };

View file

@ -74,3 +74,7 @@ All commands with no output:
$ mkdir test {MD014} $ mkdir test {MD014}
$ cd test {MD014} $ cd test {MD014}
$ ls test {MD014} $ ls test {MD014}
Space-prefixed command with no output:
$ ls example {MD014}

View file

@ -40,4 +40,8 @@ text
$ npm install --save multimatch {MD014} $ npm install --save multimatch {MD014}
``` ```
text Space-prefixed command with no output:
```sh
$ ls example {MD014}
```

View file

@ -10083,6 +10083,25 @@ Generated by [AVA](https://avajs.dev).
'commands-show-output', 'commands-show-output',
], ],
}, },
{
errorContext: ' $ ls example {MD014}',
errorDetail: null,
errorRange: [
6,
2,
],
fixInfo: {
deleteCount: 2,
editColumn: 6,
},
lineNumber: 80,
ruleDescription: 'Dollar signs used before commands without showing output',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md014.md',
ruleNames: [
'MD014',
'commands-show-output',
],
},
{ {
errorContext: null, errorContext: null,
errorDetail: 'Expected: indented; Actual: fenced', errorDetail: 'Expected: indented; Actual: fenced',
@ -10173,6 +10192,10 @@ Generated by [AVA](https://avajs.dev).
mkdir test {MD014}␊ mkdir test {MD014}␊
cd test {MD014}␊ cd test {MD014}␊
ls test {MD014}␊ ls test {MD014}␊
Space-prefixed command with no output:␊
ls example {MD014}␊
`, `,
} }
@ -10344,6 +10367,25 @@ Generated by [AVA](https://avajs.dev).
'commands-show-output', 'commands-show-output',
], ],
}, },
{
errorContext: ' $ ls example {MD014}',
errorDetail: null,
errorRange: [
2,
2,
],
fixInfo: {
deleteCount: 2,
editColumn: 2,
},
lineNumber: 46,
ruleDescription: 'Dollar signs used before commands without showing output',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md014.md',
ruleNames: [
'MD014',
'commands-show-output',
],
},
], ],
fixed: `# Code Block Dollar Fence␊ fixed: `# Code Block Dollar Fence␊
@ -10387,7 +10429,11 @@ Generated by [AVA](https://avajs.dev).
npm install --save multimatch {MD014}␊ npm install --save multimatch {MD014}␊
\`\`\`␊ \`\`\`␊
text␊ Space-prefixed command with no output:␊
\`\`\`sh␊
ls example {MD014}␊
\`\`\`␊
`, `,
} }