diff --git a/.eslintrc.js b/.eslintrc.js index 8c91c06..25c92dc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,5 +14,6 @@ module.exports = { "import/no-commonjs": "off", "filenames/match-regex": "off", "i18n-text/no-en": "off", + "eslint-comments/no-use": "off", }, }; diff --git a/.gitignore b/.gitignore index b512c09..aec49c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +markdown-violations.json \ No newline at end of file diff --git a/.markdownlint-cli2.cjs b/.markdownlint-cli2.cjs index 5981f5a..dec9564 100644 --- a/.markdownlint-cli2.cjs +++ b/.markdownlint-cli2.cjs @@ -9,4 +9,11 @@ const options = require('./index.js').init({ module.exports = { config: options, customRules: ["./index.js"], + outputFormatters: [ + ['markdownlint-cli2-formatter-pretty', {appendLink: true}], // ensures the error message includes a link to the rule documentation + [ + 'markdownlint-cli2-formatter-json', + {name: 'markdown-violations.json', spaces: 1} + ] + ] } diff --git a/package-lock.json b/package-lock.json index 95c9ee1..0ce5d2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,9 @@ "eslint-plugin-github": "^4.3.7", "jest": "^28.1.3", "markdownlint": "^0.26.1", - "markdownlint-cli2": "^0.5.1" + "markdownlint-cli2": "^0.5.1", + "markdownlint-cli2-formatter-json": "^0.0.7", + "markdownlint-cli2-formatter-pretty": "^0.0.4" } }, "node_modules/@ampproject/remapping": { @@ -4412,6 +4414,86 @@ "markdownlint-cli2": ">=0.0.4" } }, + "node_modules/markdownlint-cli2-formatter-json": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-json/-/markdownlint-cli2-formatter-json-0.0.7.tgz", + "integrity": "sha512-mTFzr7cgXF2IdUGq1X2DRWSKcOO/hrCDL9eDBqwdODXR55Xy1ivuFbvNAiVv3ux1zwZj2DKWzSQTCssJkHCQGw==", + "dev": true, + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" + } + }, + "node_modules/markdownlint-cli2-formatter-pretty": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-pretty/-/markdownlint-cli2-formatter-pretty-0.0.4.tgz", + "integrity": "sha512-Zz903THP1PrmC6k4Rm8jBegVcbsCeVmMhH/XdFzd8bL2rS60dRVev7CXZqbdGBeiCcmdut0EFMPk3huAhztcuQ==", + "dev": true, + "dependencies": { + "chalk": "5.0.0", + "terminal-link": "3.0.0" + }, + "engines": { + "node": ">=14.18.0" + }, + "peerDependencies": { + "markdownlint-cli2": ">=0.0.4" + } + }, + "node_modules/markdownlint-cli2-formatter-pretty/node_modules/ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2-formatter-pretty/node_modules/chalk": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz", + "integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/markdownlint-cli2-formatter-pretty/node_modules/terminal-link": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-3.0.0.tgz", + "integrity": "sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^5.0.0", + "supports-hyperlinks": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdownlint-cli2-formatter-pretty/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/markdownlint-cli2/node_modules/globby": { "version": "13.1.2", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", @@ -9105,6 +9187,56 @@ "dev": true, "requires": {} }, + "markdownlint-cli2-formatter-json": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-json/-/markdownlint-cli2-formatter-json-0.0.7.tgz", + "integrity": "sha512-mTFzr7cgXF2IdUGq1X2DRWSKcOO/hrCDL9eDBqwdODXR55Xy1ivuFbvNAiVv3ux1zwZj2DKWzSQTCssJkHCQGw==", + "dev": true, + "requires": {} + }, + "markdownlint-cli2-formatter-pretty": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/markdownlint-cli2-formatter-pretty/-/markdownlint-cli2-formatter-pretty-0.0.4.tgz", + "integrity": "sha512-Zz903THP1PrmC6k4Rm8jBegVcbsCeVmMhH/XdFzd8bL2rS60dRVev7CXZqbdGBeiCcmdut0EFMPk3huAhztcuQ==", + "dev": true, + "requires": { + "chalk": "5.0.0", + "terminal-link": "3.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dev": true, + "requires": { + "type-fest": "^1.0.2" + } + }, + "chalk": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.0.tgz", + "integrity": "sha512-/duVOqst+luxCQRKEo4bNxinsOQtMP80ZYm7mMqzuh5PociNL0PvmHFvREJ9ueYL2TxlHjBcmLCdmocx9Vg+IQ==", + "dev": true + }, + "terminal-link": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-3.0.0.tgz", + "integrity": "sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==", + "dev": true, + "requires": { + "ansi-escapes": "^5.0.0", + "supports-hyperlinks": "^2.2.0" + } + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", diff --git a/package.json b/package.json index b5b0ffc..efe1600 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "scripts": { "publish": "npm publish --access public --@github:registry=https://registry.npmjs.org", "test": "npm run lint && jest", - "lint": "markdownlint-cli2 \"**/*.{md,mdx}\" \"!node_modules\" \"!docs/rules\" \"!test/example.md\" && eslint .", + "markdownlint": "markdownlint-cli2 \"**/*.{md,mdx}\" \"!node_modules\" \"!docs/rules\" \"!test/example.md\"", + "lint": "npm run markdownlint && eslint .", "lint:fix": "npm run lint -- --fix" }, "dependencies": { @@ -20,7 +21,9 @@ "eslint-plugin-github": "^4.3.7", "jest": "^28.1.3", "markdownlint": "^0.26.1", - "markdownlint-cli2": "^0.5.1" + "markdownlint-cli2": "^0.5.1", + "markdownlint-cli2-formatter-json": "^0.0.7", + "markdownlint-cli2-formatter-pretty": "^0.0.4" }, "repository": { "type": "git", diff --git a/script/markdownlint-disable.js b/script/markdownlint-disable.js new file mode 100755 index 0000000..607a7eb --- /dev/null +++ b/script/markdownlint-disable.js @@ -0,0 +1,71 @@ +#!/usr/bin/env node + +// Disables markdownlint rules in markdown files with same-line comments. This is +// useful when introducing a new rule that causes many failures. The comments +// can be fixed and removed at while updating the file later. +// +// Usage: +// +// script/markdownlint-disable.js no-generic-link-text + +/* eslint-disable no-console */ + +const fs = require("fs"); +const { spawn } = require("child_process"); + +const rule = process.argv[2]; +if (!rule) { + console.error("Please specify a rule to disable."); // eslint-disable-line no-console + process.exit(1); +} +let verbose = false; +if (process.argv[3] === "--verbose" || process.argv[3] === "-v") { + verbose = true; +} + +// Cleanup from previous run +if (fs.existsSync("markdown-violations.json")) { + fs.unlinkSync("markdown-violations.json"); +} + +console.log(`Disabling "${rule}" rule in markdown files...`); // eslint-disable-line no-console +const childProcess = spawn("npm", ["run", "markdownlint", rule]); + +childProcess.stdout.on("data", (data) => { + if (verbose) console.log(data.toString()); +}); + +childProcess.stderr.on("data", function (data) { + if (verbose) console.log(data.toString()); +}); + +let matchingRulesFound = 0; +childProcess.on("close", (code) => { + if (code === 0) { + console.log(`No violations for rule, "${rule}" found.`); // eslint-disable-line no-console + process.exit(0); + } + + const markdownViolations = JSON.parse( + fs.readFileSync("markdown-violations.json", "utf8") + ); + console.log(`${markdownViolations.length} violations found.`); // eslint-disable-line no-console + + for (const { fileName, ruleNames, lineNumber } of markdownViolations) { + if (fileName.endsWith(".mdx")) { + // Skip mdx files for now, which support different comment format. + return; + } + if (ruleNames.includes(rule)) { + matchingRulesFound++; + const fileLines = fs.readFileSync(fileName, "utf8").split("\n"); + const offendingLine = fileLines[lineNumber - 1]; + fileLines[lineNumber - 1] = offendingLine.concat( + ` ` + ); + fs.writeFileSync(fileName, fileLines.join("\n"), "utf8"); + } + } + + console.log(`${matchingRulesFound} violations ignored.`); // eslint-disable-line no-console +});