Skip to content

Commit

Permalink
Validate links to md files (FOME-Tech#153)
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-hol authored Sep 17, 2023
1 parent de961db commit 858aa44
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 26 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
101 changes: 76 additions & 25 deletions scripts/linkValidator.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,108 @@
/*
* 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
*/

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}`);

console.log('Validating absolute URLs...');
// * 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,
});
}
});
});

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);

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()}"`,
);
});

console.log('✅ Ok');
process.exit(2);
}
};

// main
main();
49 changes: 49 additions & 0 deletions scripts/tests/linkValidator.test.md
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 858aa44

Please sign in to comment.