Validate links to md files (#153)

This commit is contained in:
mi-hol 2023-09-17 19:33:58 +02:00 committed by GitHub
parent de961db2e9
commit 858aa44554
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 126 additions and 26 deletions

View File

@ -11,7 +11,7 @@
"lint:fix": "biome format --write . && biome check --apply .",
"lint:fix:unsafe": "biome check . --apply-unsafe .",
"lint:ts": "tsc",
"lint:links": "node scripts/linkValidator.js",
"lint:links": "node scripts/linkValidator.js 'docs/**/*.md?(x)'",
"lint:md": "npx markdownlint-cli docs",
"lint:biome": "biome check .",
"swizzle": "docusaurus swizzle",

View File

@ -1,27 +1,71 @@
/*
* usage:
* note: Windows path separator used below! (to avoid error with parsing of this comment block)
* " node .\scripts\linkValidator.js 'docs\**\*.md?(x)' "
*
* for testing:
* "node linkValidator.js .\linkValidator.test.md"
*/
const fs = require('fs');
const glob = require('glob');
const red = (text) => `\x1b[31m${text}\x1b[0m`;
/**
* Check whether links are not staring with "wiki.fome.tech"
* @param {Array<string>} files - List of file names to check
*/
const validateAbsoluteUrls = (files) => {
const wikiUrl = 'wiki.fome.tech';
const regexPattern = new RegExp(`\\]\\((https|http):\\/\\/${wikiUrl}`, 'i');
/** @type {Array<{ errType: string, fileName: string, lineContent: string, lineNo: number }>} */
const errors = [];
const wikiUrl = 'wiki.fome.tech';
/** @type {Array<{ fileName: string, lineContent: string, lineNo: number }>} */
const errors = [];
const validateDocRules = (files) => {
/**
* Check whether links are adhering to custom rules
* @param {Array<string>} files - List of file names to check
*/
console.log('Validating absolute URLs...');
let fileMatchIndicator = '';
if (files.length === 0) {
console.log('UsageError: no files qualify!');
process.exit(1);
}
if (files.length > 1) {
fileMatchIndicator = `${files.length} files`;
} else {
fileMatchIndicator = files[0];
}
console.log(`Validating rules for URL links in: ${fileMatchIndicator}`);
// * Check whether links are not staring with "https://wiki.fome.tech"
// Note: dynamic javascript string interpolation is used here (see https://www.crstin.com/js-regex-interpolation/)
const regexPatternDynAbsLink = new RegExp(`\\]\\((https|http):\\/\\/${wikiUrl}`, 'i');
// hint: test static regex via https://regex101.com
// * Check whether links are not using a "numbered prefix" like "(/01-blah)"
const regexPatternStatNumPrefix = new RegExp(/\(.*\/\d\d\-.*\)/, 'i');
// * Check whether links are not markdown links, meaning ending with .md or .mdx like "(/01-blah.md)"
const regexPatternStatMdLink = new RegExp(/\(.*\.(md|mdx)\)/, 'i');
files.forEach((fileName) => {
const lines = fs.readFileSync(fileName, 'utf8').split('\n');
lines.forEach((line) => {
if (regexPattern.test(line)) {
if (regexPatternDynAbsLink.test(line)) {
errors.push({
errType: 'AbsLink',
fileName,
lineContent: line,
lineNo: lines.indexOf(line) + 1,
});
}
if (regexPatternStatMdLink.test(line)) {
errors.push({
errType: 'MdLink',
fileName,
lineContent: line,
lineNo: lines.indexOf(line) + 1,
});
}
if (regexPatternStatNumPrefix.test(line)) {
errors.push({
errType: 'NumPrefix',
fileName,
lineContent: line,
lineNo: lines.indexOf(line) + 1,
@ -29,29 +73,36 @@ const validateAbsoluteUrls = (files) => {
}
});
});
if (errors.length > 0) {
console.log('❌ Failed\n');
console.log(red(`Absolute URLs to "${wikiUrl}" found in the following files:\n`));
errors.forEach((error) => {
console.log(`[${error.fileName}:${error.lineNo}] ${error.lineContent.trim()}`);
});
process.exit(1);
}
};
/**
* Load all md and mdx files from / docs and process them
*/
const main = () => {
const files = glob.sync('docs/**/*.md?(x)');
// ToDo: add try + catch?
const args = process.argv.slice(2);
const files = glob.sync(args[0]);
// process
validateAbsoluteUrls(files);
// validateRelativeUrls(files);
validateDocRules(files);
console.log('✅ Ok');
if (errors.length === 0) {
console.log('✅ Ok');
} else {
console.log('❌ Failed\n');
console.log(red(`Number of Errors found: ${errors.length}`));
errors.forEach((error) => {
console.log(
`[${error.fileName}]` +
`[Line:${error.lineNo}]` +
`[errType:${error.errType}]` +
`"${error.lineContent.trim()}"`,
);
});
process.exit(2);
}
};
// main
main();

View File

@ -0,0 +1,49 @@
# Tests for linkValidator.js
## 1. test case prevented by markdownlint MD034/no-bare-urls
[T] (https://wikiXfome.tech/01-test.md)
## 2. test case prevented by markdownlint MD034/no-bare-urls
blah (https://wiki.fome.tech/01-test.md)
## 3. test case expected: MdLink + AbsLink + NumPrefix
[T](https://wiki.fome.tech/01-test.md)
## 4. test case expected: false positive AbsLink
[T](https://wikiXfome.tech/test) # note: false positive, but extreme unlikely to hit in real world
## 5. test case expected: MdLink + NumPrefix
(/01-test.md)
## 6. test case expected: MdLink
(test.md)
## 7. test case expected: MdLink
(test.md) blah
## 8. test case expected: MdLink
blah (test.md) blah
## 9. test case expected: MdLink
(../test.mdx)
## 10. test case expected: no error
(T)(test.jpg)
## 11. test case expected: no error
(T)(../../test)
## 12. test case expected: NumPrefix
(/01-test)