Skip to content

Commit bcf88dc

Browse files
authored
v3 docs: bump & cleanup node modules (#4052)
The node modules for the v3 docs are outdated which includes potential security issues. This change bumps all node modules and removes unused ones. Additionally the 'check-pages' module was replaced with 'linkinator' due to regular updates.
1 parent 245715a commit bcf88dc

File tree

4 files changed

+1034
-4455
lines changed

4 files changed

+1034
-4455
lines changed

docs/v3/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Built with [Slate](https://github.com/lord/slate).
66
Getting Started
77
---------------
88

9-
- Ensure you have Ruby 2.4.x installed
9+
- Ensure you have Ruby 3.2.x installed
1010
- Ensure you have Bundler installed and have run `bundle install` in this directory
1111
- Ensure you have the latest version of NodeJS installed
1212
- Get the npm dependencies: `npm install`

docs/v3/gulpfile.js

Lines changed: 86 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
const fs = require('fs');
2-
const gulp = require('gulp');
3-
const {exec} = require('child_process');
4-
const express = require('express');
5-
const checkPages = require('check-pages');
6-
const { glob } = require('glob');
7-
const cheerio = require('cheerio');
1+
import { exec } from 'child_process';
2+
import { readFileSync } from 'fs';
3+
import gulp from 'gulp';
4+
import express from 'express';
5+
import { glob } from 'glob';
6+
import { LinkChecker } from 'linkinator';
7+
8+
const cheerio = await import('cheerio');
89

910
function displayErrors(err, stdout, stderr) {
1011
if (err) {
@@ -19,7 +20,7 @@ function checkInternalLinksAndExit(htmlPath) {
1920
const duplicateHeadingIds = [];
2021
const seenHeadingIds = new Set();
2122
const badLinks = [];
22-
const $ = cheerio.load(fs.readFileSync(htmlPath, 'utf8'));
23+
const $ = cheerio.load(readFileSync(htmlPath, 'utf8'));
2324

2425
$('a').each((index, anchor) => {
2526
const href = $(anchor).attr('href') || '';
@@ -32,13 +33,12 @@ function checkInternalLinksAndExit(htmlPath) {
3233
if (foundElementByName) return;
3334

3435
const text = $(anchor).text();
35-
badLinks.push({text, href});
36+
badLinks.push({ text, href });
3637
}
3738
});
3839

3940
$('h1,h2,h3').each((index, element) => {
4041
const id = $(element).attr('id');
41-
4242
if (id) {
4343
if (seenHeadingIds.has(id)) duplicateHeadingIds.push(id);
4444
else seenHeadingIds.add(id);
@@ -48,7 +48,7 @@ function checkInternalLinksAndExit(htmlPath) {
4848
if (badLinks.length) {
4949
console.error('v3 docs error: Found invalid internal links');
5050
console.error('Make sure these `href`s correspond to the `id`s of real headings in the HTML:');
51-
console.error(badLinks.map(({text, href}) => ` - [${text}](${href})`).join('\n'));
51+
console.error(badLinks.map(({ text, href }) => ` - [${text}](${href})`).join('\n'));
5252
}
5353

5454
if (duplicateHeadingIds.length) {
@@ -63,8 +63,9 @@ function checkInternalLinksAndExit(htmlPath) {
6363
}
6464

6565
function checkSyntaxErrorsAndExit(htmlPath) {
66-
const $ = cheerio.load(fs.readFileSync(htmlPath, 'utf8'));
66+
const $ = cheerio.load(readFileSync(htmlPath, 'utf8'));
6767
const syntaxErrors = $('code .err');
68+
6869
if (syntaxErrors.length) {
6970
syntaxErrors.each((_index, errorElement) => {
7071
console.error('⚠️ v3 docs error: Found syntax error');
@@ -73,25 +74,66 @@ function checkSyntaxErrorsAndExit(htmlPath) {
7374
console.error('👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆\n')
7475
});
7576

76-
process.exit(1)
77+
process.exit(1);
7778
}
7879
}
7980

80-
function checkPathAndExit(path, options, done) {
81+
async function checkPathAndExit(path, options, done) {
8182
const app = express();
8283
app.use(express.static(path));
83-
const server = app.listen({port: 8001});
84+
const server = app.listen({ port: 8001 });
85+
86+
const url = 'http://localhost:8001/';
87+
88+
const config = {
89+
path: url,
90+
linksToSkip: options.linksToSkip || [],
91+
recurse: options.recurse,
92+
silent: options.silent,
93+
markdown: options.markdown,
94+
};
95+
96+
try {
97+
const checker = new LinkChecker();
98+
99+
if (path === '../v2') {
100+
const htmlFiles = await glob(path + '/**/*.html');
101+
let allResults = { links: [] };
102+
for (let file of htmlFiles) {
103+
const fileUrl = url + file.substr(path.length);
104+
const fileConfig = { ...config, path: fileUrl };
105+
const results = await checker.check(fileConfig);
106+
allResults.links = allResults.links.concat(results.links);
107+
}
108+
displayResults(allResults);
109+
} else {
110+
const results = await checker.check(config);
111+
displayResults(results);
112+
}
84113

85-
return checkPages(console, options, (err, stdout, stderr) => {
86114
server.close();
87115
done();
88116

89-
if (err) {
90-
return displayErrors(err, stdout, stderr);
91-
}
117+
} catch (err) {
118+
server.close();
119+
done(err);
120+
process.exit(1);
121+
}
122+
}
92123

93-
return true;
94-
});
124+
function displayResults(results) {
125+
const totalLinks = results.links.length;
126+
const brokenLinks = results.links.filter(link => link.state === 'BROKEN');
127+
128+
console.log(`Total Links Checked: ${totalLinks}`);
129+
console.log(`Broken Links Found: ${brokenLinks.length}`);
130+
if (brokenLinks.length > 0) {
131+
console.log('Broken Links:');
132+
brokenLinks.forEach(link => {
133+
console.log(` - ${link.url} (status: ${link.status})`);
134+
});
135+
process.exitCode = 1;
136+
}
95137
}
96138

97139
gulp.task('build', cb => {
@@ -110,7 +152,7 @@ gulp.task('webserver', cb => {
110152
}
111153
cb();
112154
});
113-
console.log('Your docs are waiting for you at http://localhost:8000')
155+
console.log('Your docs are waiting for you at http://localhost:8000');
114156
});
115157

116158
gulp.task('default', gulp.series('webserver'));
@@ -119,29 +161,29 @@ gulp.task('checkV3docs', gulp.series('build', done => {
119161
checkInternalLinksAndExit('build/index.html');
120162
checkSyntaxErrorsAndExit('build/index.html');
121163

122-
checkPathAndExit('build', {
123-
checkLinks: true,
124-
summary: true,
125-
terse: true,
126-
onlySameDomain: true,
127-
pageUrls: ['http://localhost:8001/'],
128-
linksToIgnore: ['http://localhost:8001/version/release-candidate']
129-
}, done);
164+
try {
165+
checkPathAndExit('build', {
166+
linksToSkip: ['http://localhost:8001/version/release-candidate'],
167+
recurse: true,
168+
silent: true,
169+
markdown: true,
170+
}, done);
171+
} catch (err) {
172+
done(err);
173+
}
130174
}));
131175

132-
gulp.task('checkV2docs', async(done) => {
133-
const htmlFiles = await glob('../v2/**/*.html')
134-
const fixedFiles = htmlFiles.map(fname => {
135-
return 'http://localhost:8001' + fname.substr('../v2'.length);
136-
});
137-
138-
checkPathAndExit('../v2', {
139-
checkLinks: true,
140-
summary: true,
141-
terse: true,
142-
onlySameDomain: true,
143-
pageUrls: ['http://localhost:8001/'].concat(fixedFiles)
144-
}, done);
176+
gulp.task('checkV2docs', done => {
177+
try {
178+
checkPathAndExit('../v2', {
179+
linksToSkip: [],
180+
recurse: true,
181+
silent: true,
182+
markdown: true,
183+
}, done);
184+
} catch (err) {
185+
done(err);
186+
}
145187
});
146188

147-
gulp.task('checkdocs', gulp.parallel('checkV2docs', 'checkV3docs'));
189+
gulp.task('checkdocs', gulp.series('checkV2docs', 'checkV3docs'));

0 commit comments

Comments
 (0)