From c074df5a417919382e830b53adbe490ead4b1d9c Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 12 Apr 2023 16:36:44 -0700 Subject: [PATCH] Fix the link checker test Closes #3541 --- package-lock.json | 6 +-- package.json | 1 + test/link-check.ts | 63 +++++++++++++++++++---------- tool/types/markdown-link-check.d.ts | 1 + 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 64b3adc8..ff33c810 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "name": "sass", "dependencies": { "@types/diff": "^5.0.1", "@types/glob": "^7.1.4", @@ -12,6 +13,7 @@ "diff": "^5.0.0", "glob": "^7.2.0", "immutable": "^4.0.0", + "indent-string": "^4.0.0", "markdown-link-check": "git+https://sassbot@github.com/nex3/markdown-link-check.git#check-references", "markdown-toc": "^1.2.0", "prettier": "^2.4.1", @@ -2256,7 +2258,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, "engines": { "node": ">=8" } @@ -6414,8 +6415,7 @@ "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, "inflight": { "version": "1.0.6", diff --git a/package.json b/package.json index 9eab8ddf..a8bb096c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "diff": "^5.0.0", "glob": "^7.2.0", "immutable": "^4.0.0", + "indent-string": "^4.0.0", "markdown-link-check": "git+https://sassbot@github.com/nex3/markdown-link-check.git#check-references", "markdown-toc": "^1.2.0", "prettier": "^2.4.1", diff --git a/test/link-check.ts b/test/link-check.ts index bb57a1ee..71d884c4 100644 --- a/test/link-check.ts +++ b/test/link-check.ts @@ -6,6 +6,7 @@ import * as linkCheck from 'markdown-link-check'; import markdownToc = require('markdown-toc'); import * as path from 'path'; import {fileURLToPath, pathToFileURL, URL} from 'url'; +import * as indentString from 'indent-string'; if (process.env.CI) colors.enable(); @@ -25,40 +26,62 @@ function getToc(file: string): string { return toc; } +function pathIsWithin(child: string, parent: string): boolean { + const relative = path.relative(parent, child); + return !relative.startsWith('../'); +} + +function flagDeadLink(link: string): void { + console.error(`${colors.red(colors.bold('Dead:'))} ${link}`); + process.exitCode = 1; +} + function verifyLinkCheckResults( file: string, results: linkCheck.Result[] ): void { - const toc = getToc(file); - for (const result of results) { const url = new URL(result.link, pathToFileURL(file)); // A link to another file. if (url.protocol === 'file:' && !result.link.match(/ \(.*\)$/)) { const target = fileURLToPath(url); - if (!fs.existsSync(target)) throw Error(`Missing file: ${result.link}`); - if (url.hash === '') return; - if (getToc(target).includes(url.hash)) return; - throw Error(`Dead: ${result.link}`); - } - - // A link to a section within this file. - if (result.link.match(/^#/)) { - if (toc.includes(result.link)) return; - throw Error(`Dead: ${result.link}`); + if (!fs.existsSync(target)) { + flagDeadLink(result.link); + } else if (url.hash !== '' && !getToc(target).includes(`(${url.hash})`)) { + flagDeadLink(result.link); + } else if ( + result.link.includes('../spec/') && + pathIsWithin(file, 'spec') + ) { + console.error( + `${colors.yellow(colors.bold('Unnecessary ../spec:'))} ${result.link}` + ); + process.exitCode = 1; + } + continue; } // A link to an external website. switch (result.status) { case 'dead': if (result.statusCode === 500) { - console.log(colors.yellow(`Server error on target: ${result.link}`)); - return; + console.error( + colors.yellow(`Server error on target: ${result.link}`) + ); + } else { + flagDeadLink(result.link); } - throw Error(`Dead: ${result.link}`); + break; + case 'error': - throw Error(`Error: ${result.link}`); + console.error( + `${colors.red(colors.bold('Error:'))} ${result.link}` + + (result.err + ? '\n' + indentString(result.err.toString(), 1, {indent: '| '}) + : '') + ); + process.exitCode = 1; } } } @@ -72,7 +95,7 @@ function runLinkCheck( markdownLinkCheck( fs.readFileSync(file).toString(), { - baseUrl: '', + baseUrl: pathToFileURL(file).toString(), // If Github rate limit is reached, wait 60s and try again. retryOn429: true, // Twitter links consistently fail. @@ -97,13 +120,11 @@ function runLinkCheck( (async () => { for (const file of files) { - console.log('Checking links in ' + file); + console.log(colors.grey('Checking links in ' + file)); try { await runLinkCheck(file, {rateLimit: 500}); } catch (error) { - console.log( - colors.red(error instanceof Error ? error.message : `${error}`) - ); + console.error(error); process.exitCode = 1; } } diff --git a/tool/types/markdown-link-check.d.ts b/tool/types/markdown-link-check.d.ts index 1ea91636..85a844df 100644 --- a/tool/types/markdown-link-check.d.ts +++ b/tool/types/markdown-link-check.d.ts @@ -10,6 +10,7 @@ declare module 'markdown-link-check' { link: string; status: string; statusCode: number; + err: string | null; } }