doc: tests local links in markdown documents

PR-URL: https://github.com/nodejs/node/pull/32359
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Antoine du HAMEL 2020-03-19 09:38:41 +01:00 committed by Anna Henningsen
parent bac401c42c
commit 19db0e60bd
No known key found for this signature in database
GPG Key ID: A94130F0BFC8EBE9
6 changed files with 84 additions and 9 deletions

View File

@ -633,6 +633,7 @@ test-doc: doc-only lint ## Builds, lints, and verifies the docs.
else \
$(PYTHON) tools/test.py $(PARALLEL_ARGS) doctool; \
fi
$(NODE) tools/doc/checkLinks.js .
test-known-issues: all
$(PYTHON) tools/test.py $(PARALLEL_ARGS) known_issues

View File

@ -37,8 +37,8 @@
This document explains how Collaborators manage the Node.js project.
Collaborators should understand the
[guidelines for new contributors](CONTRIBUTING.md) and the
[project governance model](GOVERNANCE.md).
[guidelines for new contributors](../../CONTRIBUTING.md) and the
[project governance model](../../GOVERNANCE.md).
## Issues and Pull Requests
@ -50,7 +50,7 @@ request. See [Who to CC in the issue tracker](#who-to-cc-in-the-issue-tracker).
Always show courtesy to individuals submitting issues and pull requests. Be
welcoming to first-time contributors, identified by the GitHub
![First-time contributor](./doc/first_timer_badge.png) badge.
![First-time contributor](../first_timer_badge.png) badge.
For first-time contributors, check if the commit author is the same as the pull
request author. This way, once their pull request lands, GitHub will show them
@ -474,7 +474,7 @@ $ git checkout master
```
Update the tree (assumes your repo is set up as detailed in
[CONTRIBUTING.md](./doc/guides/contributing/pull-requests.md#step-1-fork)):
[CONTRIBUTING.md](./contributing/pull-requests.md#step-1-fork)):
```text
$ git fetch upstream

View File

@ -1,7 +1,7 @@
# C++ Style Guide
See also the [C++ codebase README](src/README.md) for C++ idioms in the Node.js
codebase not related to stylistic issues.
See also the [C++ codebase README](../../src/README.md) for C++ idioms in the
Node.js codebase not related to stylistic issues.
## Table of Contents

View File

@ -322,8 +322,8 @@ accordingly by removing the bold styling from the previous release.
If this release includes new APIs then it is necessary to document that they
were first added in this version. The relevant commits should already include
`REPLACEME` tags as per the example in the
[docs README](../tools/doc/README.md). Check for these tags with `grep REPLACEME
doc/api/*.md`, and substitute this node version with `sed -i
[docs README](../../tools/doc/README.md). Check for these tags with `grep
REPLACEME doc/api/*.md`, and substitute this node version with `sed -i
"s/REPLACEME/$VERSION/g" doc/api/*.md` or `perl -pi -e "s/REPLACEME/$VERSION/g"
doc/api/*.md`.

View File

@ -83,7 +83,7 @@ onboarding session.
* Be nice about closing issues! Let people know why, and that issues and PRs
can be reopened if necessary
* [**See "Labels"**](./onboarding-extras.md#labels)
* [**See "Labels"**](./doc/guides/onboarding-extras.md#labels)
* There is [a bot](https://github.com/nodejs-github-bot/github-bot) that
applies subsystem labels (for example, `doc`, `test`, `assert`, or `buffer`)
so that we know what parts of the code base the pull request modifies. It is

74
tools/doc/checkLinks.js Normal file
View File

@ -0,0 +1,74 @@
'use strict';
const fs = require('fs');
const { Worker, isMainThread, workerData: path } = require('worker_threads');
function* getLinksRecursively(node) {
if (
(node.type === 'link' && !node.url.startsWith('#')) ||
node.type === 'image'
) {
yield node;
}
for (const child of node.children || []) {
yield* getLinksRecursively(child);
}
}
if (isMainThread) {
const { extname, join, resolve } = require('path');
const DIR = resolve(process.argv[2]);
console.log('Running Markdown link checker...');
async function* findMarkdownFilesRecursively(dirPath) {
const fileNames = await fs.promises.readdir(dirPath);
for (const fileName of fileNames) {
const path = join(dirPath, fileName);
const stats = await fs.promises.stat(path);
if (
stats.isDirectory() &&
fileName !== 'api' &&
fileName !== 'deps' &&
fileName !== 'node_modules'
) {
yield* findMarkdownFilesRecursively(path);
} else if (extname(fileName) === '.md') {
yield path;
}
}
}
function errorHandler(error) {
console.error(error);
process.exitCode = 1;
}
setImmediate(async () => {
for await (const path of findMarkdownFilesRecursively(DIR)) {
new Worker(__filename, { workerData: path }).on('error', errorHandler);
}
});
} else {
const unified = require('unified');
const { pathToFileURL } = require('url');
const tree = unified()
.use(require('remark-parse'))
.parse(fs.readFileSync(path));
const base = pathToFileURL(path);
for (const node of getLinksRecursively(tree)) {
const targetURL = new URL(node.url, base);
if (targetURL.protocol === 'file:' && !fs.existsSync(targetURL)) {
const error = new Error('Broken link in a Markdown document.');
const { start } = node.position;
error.stack =
error.stack.substring(0, error.stack.indexOf('\n') + 5) +
`at ${node.type} (${path}:${start.line}:${start.column})`;
throw error;
}
}
}