2020-05-08 11:53:08 -07:00
|
|
|
// @ts-check
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2020-05-08 12:27:41 -07:00
|
|
|
const { existsSync } = require("fs");
|
2020-11-24 16:25:08 -08:00
|
|
|
// eslint-disable-next-line unicorn/import-style
|
2020-05-08 11:53:08 -07:00
|
|
|
const { join } = require("path");
|
|
|
|
const { promisify } = require("util");
|
|
|
|
const jsYaml = require("js-yaml");
|
2021-01-10 20:46:00 -08:00
|
|
|
const test = require("ava").default;
|
2020-05-08 11:53:08 -07:00
|
|
|
const markdownlint = require("../lib/markdownlint");
|
|
|
|
const markdownlintPromise = promisify(markdownlint);
|
|
|
|
const readConfigPromise = promisify(markdownlint.readConfig);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lints a test repository.
|
|
|
|
*
|
2021-01-10 20:46:00 -08:00
|
|
|
* @param {Object} t Test instance.
|
2020-05-08 11:53:08 -07:00
|
|
|
* @param {string[]} globPatterns Array of files to in/exclude.
|
|
|
|
* @param {string} configPath Path to config file.
|
2021-11-29 22:21:23 -08:00
|
|
|
* @param {RegExp[]} [ignoreRes] Array of RegExp violations to ignore.
|
2021-01-10 20:46:00 -08:00
|
|
|
* @returns {Promise} Test result.
|
2020-05-08 11:53:08 -07:00
|
|
|
*/
|
2021-12-27 21:59:56 +00:00
|
|
|
async function lintTestRepo(t, globPatterns, configPath, ignoreRes) {
|
2021-01-10 20:46:00 -08:00
|
|
|
t.plan(1);
|
2021-12-27 21:59:56 +00:00
|
|
|
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
2021-12-27 22:40:44 +00:00
|
|
|
const { globby } = await import("globby");
|
|
|
|
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
2021-12-27 21:59:56 +00:00
|
|
|
const { "default": stripJsonComments } = await import("strip-json-comments");
|
|
|
|
const jsoncParse = (json) => JSON.parse(stripJsonComments(json));
|
|
|
|
const yamlParse = (yaml) => jsYaml.load(yaml);
|
2021-01-10 20:46:00 -08:00
|
|
|
return Promise.all([
|
2020-05-08 11:53:08 -07:00
|
|
|
globby(globPatterns),
|
|
|
|
// @ts-ignore
|
|
|
|
readConfigPromise(configPath, [ jsoncParse, yamlParse ])
|
|
|
|
]).then((globbyAndReadConfigResults) => {
|
|
|
|
const [ files, config ] = globbyAndReadConfigResults;
|
2021-06-13 16:45:38 -07:00
|
|
|
// eslint-disable-next-line no-console
|
2021-06-13 16:37:29 -07:00
|
|
|
console.log(`${t.title}: Linting ${files.length} files...`);
|
2022-04-10 05:37:57 +00:00
|
|
|
return markdownlintPromise({
|
|
|
|
files,
|
|
|
|
config,
|
|
|
|
"resultVersion": 3
|
|
|
|
// }).then((results) => {
|
|
|
|
// // Cross-check MD051/link-fragments results with markdown-link-check
|
|
|
|
// const resultFiles = [];
|
|
|
|
// const detectedErrors = new Set();
|
|
|
|
// for (const file of Object.keys(results)) {
|
|
|
|
// const errors =
|
|
|
|
// results[file].filter((error) => error.ruleNames[0] === "MD051");
|
|
|
|
// if (errors.length > 0) {
|
|
|
|
// resultFiles.push(file);
|
|
|
|
// }
|
|
|
|
// for (const error of errors) {
|
|
|
|
// const fragment = error.errorContext.replace(/^.*\((#.*)\)$/, "$1");
|
|
|
|
// detectedErrors.add(file + fragment);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// const { readFile } = require("fs").promises;
|
|
|
|
// const markdownLinkCheck = promisify(require("markdown-link-check"));
|
|
|
|
// const expectedErrors = new Set();
|
|
|
|
// return Promise.all(
|
|
|
|
// resultFiles.map((file) => readFile(file, "utf8")
|
|
|
|
// // @ts-ignore
|
|
|
|
// .then((markdown) => markdownLinkCheck(markdown, {
|
|
|
|
// "ignorePatterns": [
|
|
|
|
// {
|
|
|
|
// "pattern": "^[^#]"
|
|
|
|
// }
|
|
|
|
// ]
|
|
|
|
// }))
|
|
|
|
// .then((mlcResults) => {
|
|
|
|
// const deadResults =
|
|
|
|
// mlcResults.filter((result) => result.status === "dead");
|
|
|
|
// for (const link of deadResults.map((result) => result.link)) {
|
|
|
|
// expectedErrors.add(file + link);
|
|
|
|
// }
|
|
|
|
// })
|
|
|
|
// )
|
|
|
|
// ).then(() => {
|
|
|
|
// const extraErrors = [];
|
|
|
|
// // @ts-ignore
|
|
|
|
// for (const detectedError of detectedErrors) {
|
|
|
|
// if (!expectedErrors.has(detectedError)) {
|
|
|
|
// extraErrors.push(detectedError);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// t.deepEqual(extraErrors, [], "Extra errors");
|
|
|
|
// const missingErrors = [];
|
|
|
|
// // @ts-ignore
|
|
|
|
// for (const expectedError of expectedErrors) {
|
|
|
|
// if (!detectedErrors.has(expectedError)) {
|
|
|
|
// missingErrors.push(expectedError);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// t.deepEqual(missingErrors, [], "Missing errors");
|
|
|
|
// return results;
|
|
|
|
// });
|
|
|
|
}).then((results) => {
|
|
|
|
// Fail if any issues were found (that aren't ignored)
|
2021-11-29 22:21:23 -08:00
|
|
|
let resultsString = results.toString();
|
|
|
|
for (const ignoreRe of (ignoreRes || [])) {
|
2021-12-21 05:31:26 +00:00
|
|
|
const lengthBefore = resultsString.length;
|
2021-11-29 22:21:23 -08:00
|
|
|
resultsString = resultsString.replace(ignoreRe, "");
|
2021-12-21 05:31:26 +00:00
|
|
|
if (resultsString.length === lengthBefore) {
|
|
|
|
t.fail(`Unnecessary ignore: ${ignoreRe}`);
|
|
|
|
}
|
2021-11-29 22:21:23 -08:00
|
|
|
}
|
2020-09-06 20:34:10 -07:00
|
|
|
if (resultsString.length > 0) {
|
2020-05-08 11:53:08 -07:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.log(resultsString);
|
|
|
|
}
|
2021-02-06 19:55:22 -08:00
|
|
|
t.is(resultsString.length, 0, "Unexpected linting violations");
|
2020-05-08 11:53:08 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-10-23 22:24:47 -07:00
|
|
|
/**
|
|
|
|
* Excludes a list of globs.
|
|
|
|
*
|
|
|
|
* @param {string} rootDir Root directory for globs.
|
|
|
|
* @param {...string} globs Globs to exclude.
|
|
|
|
* @returns {string[]} Array of excluded globs.
|
|
|
|
*/
|
|
|
|
function excludeGlobs(rootDir, ...globs) {
|
|
|
|
return globs.map((glob) => "!" + join(rootDir, glob));
|
|
|
|
}
|
|
|
|
|
2020-05-08 11:53:08 -07:00
|
|
|
// Run markdownlint the same way the corresponding repositories do
|
|
|
|
|
2021-01-10 20:46:00 -08:00
|
|
|
test("https://github.com/eslint/eslint", (t) => {
|
2020-05-08 11:53:08 -07:00
|
|
|
const rootDir = "./test-repos/eslint-eslint";
|
2021-11-29 22:21:23 -08:00
|
|
|
const globPatterns = [ join(rootDir, "docs/**/*.md") ];
|
2020-05-08 11:53:08 -07:00
|
|
|
const configPath = join(rootDir, ".markdownlint.yml");
|
2022-01-19 18:37:01 -08:00
|
|
|
return lintTestRepo(t, globPatterns, configPath);
|
2020-05-08 11:53:08 -07:00
|
|
|
});
|
|
|
|
|
2021-01-10 20:46:00 -08:00
|
|
|
test("https://github.com/mkdocs/mkdocs", (t) => {
|
2020-05-08 11:53:08 -07:00
|
|
|
const rootDir = "./test-repos/mkdocs-mkdocs";
|
|
|
|
const globPatterns = [
|
|
|
|
join(rootDir, "README.md"),
|
|
|
|
join(rootDir, "CONTRIBUTING.md"),
|
2021-11-29 22:21:23 -08:00
|
|
|
join(rootDir, "docs"),
|
|
|
|
...excludeGlobs(
|
|
|
|
rootDir,
|
|
|
|
"docs/CNAME",
|
|
|
|
"docs/**/*.css",
|
|
|
|
"docs/**/*.png"
|
|
|
|
)
|
2020-05-08 11:53:08 -07:00
|
|
|
];
|
|
|
|
const configPath = join(rootDir, ".markdownlintrc");
|
2022-04-10 05:37:57 +00:00
|
|
|
const ignoreRes = [ /^[^:]+: \d+: MD051\/.*$\r?\n?/gm ];
|
|
|
|
return lintTestRepo(t, globPatterns, configPath, ignoreRes);
|
2020-05-08 11:53:08 -07:00
|
|
|
});
|
|
|
|
|
2021-06-13 16:37:29 -07:00
|
|
|
test("https://github.com/mochajs/mocha", (t) => {
|
|
|
|
const rootDir = "./test-repos/mochajs-mocha";
|
|
|
|
const globPatterns = [
|
|
|
|
join(rootDir, "*.md"),
|
|
|
|
join(rootDir, "docs/**/*.md"),
|
|
|
|
join(rootDir, ".github/*.md"),
|
|
|
|
join(rootDir, "lib/**/*.md"),
|
|
|
|
join(rootDir, "test/**/*.md"),
|
|
|
|
join(rootDir, "example/**/*.md")
|
|
|
|
];
|
|
|
|
const configPath = join(rootDir, ".markdownlint.json");
|
2022-04-10 05:37:57 +00:00
|
|
|
const ignoreRes = [ /^[^:]+: \d+: MD051\/.*$\r?\n?/gm ];
|
|
|
|
return lintTestRepo(t, globPatterns, configPath, ignoreRes);
|
2021-06-13 16:37:29 -07:00
|
|
|
});
|
|
|
|
|
2021-01-10 20:46:00 -08:00
|
|
|
test("https://github.com/pi-hole/docs", (t) => {
|
2020-05-08 11:53:08 -07:00
|
|
|
const rootDir = "./test-repos/pi-hole-docs";
|
2021-11-29 22:21:23 -08:00
|
|
|
const globPatterns = [ join(rootDir, "**/*.md") ];
|
2020-05-08 11:53:08 -07:00
|
|
|
const configPath = join(rootDir, ".markdownlint.json");
|
2022-04-10 05:37:57 +00:00
|
|
|
const ignoreRes = [ /^[^:]+: \d+: MD051\/.*$\r?\n?/gm ];
|
|
|
|
return lintTestRepo(t, globPatterns, configPath, ignoreRes);
|
2020-05-08 11:53:08 -07:00
|
|
|
});
|
2020-05-08 12:27:41 -07:00
|
|
|
|
2021-06-13 16:37:29 -07:00
|
|
|
test("https://github.com/webhintio/hint", (t) => {
|
|
|
|
const rootDir = "./test-repos/webhintio-hint";
|
|
|
|
const globPatterns = [
|
|
|
|
join(rootDir, "**/*.md"),
|
2021-10-23 22:24:47 -07:00
|
|
|
...excludeGlobs(rootDir, "**/CHANGELOG.md")
|
2021-06-13 16:37:29 -07:00
|
|
|
];
|
|
|
|
const configPath = join(rootDir, ".markdownlintrc");
|
|
|
|
return lintTestRepo(t, globPatterns, configPath);
|
|
|
|
});
|
|
|
|
|
|
|
|
test("https://github.com/webpack/webpack.js.org", (t) => {
|
|
|
|
const rootDir = "./test-repos/webpack-webpack-js-org";
|
|
|
|
const globPatterns = [ join(rootDir, "**/*.md") ];
|
|
|
|
const configPath = join(rootDir, ".markdownlint.json");
|
|
|
|
return lintTestRepo(t, globPatterns, configPath);
|
|
|
|
});
|
|
|
|
|
2020-05-08 12:27:41 -07:00
|
|
|
// Optional repositories (very large)
|
|
|
|
|
|
|
|
const dotnetDocsDir = "./test-repos/dotnet-docs";
|
|
|
|
if (existsSync(dotnetDocsDir)) {
|
2021-01-10 20:46:00 -08:00
|
|
|
test("https://github.com/dotnet/docs", (t) => {
|
2020-05-08 12:27:41 -07:00
|
|
|
const rootDir = dotnetDocsDir;
|
2021-11-29 22:21:23 -08:00
|
|
|
const globPatterns = [ join(rootDir, "**/*.md") ];
|
2020-05-08 12:27:41 -07:00
|
|
|
const configPath = join(rootDir, ".markdownlint.json");
|
2022-04-10 05:37:57 +00:00
|
|
|
const ignoreRes = [ /^[^:]+: \d+: MD051\/.*$\r?\n?/gm ];
|
|
|
|
return lintTestRepo(t, globPatterns, configPath, ignoreRes);
|
2020-05-08 12:27:41 -07:00
|
|
|
});
|
|
|
|
}
|
2021-06-13 16:37:29 -07:00
|
|
|
|
|
|
|
const v8v8DevDir = "./test-repos/v8-v8-dev";
|
|
|
|
if (existsSync(v8v8DevDir)) {
|
|
|
|
test("https://github.com/v8/v8.dev", (t) => {
|
|
|
|
const rootDir = v8v8DevDir;
|
2021-11-29 22:21:23 -08:00
|
|
|
const globPatterns = [ join(rootDir, "src/**/*.md") ];
|
2021-06-13 16:37:29 -07:00
|
|
|
const configPath = join(rootDir, ".markdownlint.json");
|
2022-04-10 05:37:57 +00:00
|
|
|
const ignoreRes = [ /^[^:]+: \d+: (MD049|MD051)\/.*$\r?\n?/gm ];
|
2021-11-29 22:21:23 -08:00
|
|
|
return lintTestRepo(t, globPatterns, configPath, ignoreRes);
|
2021-06-13 16:37:29 -07:00
|
|
|
});
|
|
|
|
}
|