Skip to content

Commit 0013daa

Browse files
bfopsmamcx
authored andcommitted
Docs CI - Check that nav.js matches the .md files list (#2984)
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
1 parent 116b4a6 commit 0013daa

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

.github/workflows/docs-validate-nav-build.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ jobs:
4040
run: |
4141
diff -q docs/nav.js docs/nav.js.original || (echo "Generated nav.js differs from committed version. Run 'npm run build' and commit the updated file." && exit 1)
4242
43+
# We do this after checking that nav.js matches nav.ts, to avoid confusing error messages if an author updates one but not the other.
44+
# If the .ts and .js are in sync, it doesn't matter which one we check against here.
45+
- name: Check that all files are listed in nav.js
46+
working-directory: docs
47+
run: |
48+
cp docs/nav.js docs/nav.mjs
49+
find docs -name '*.md' | sed 's!^docs/!!' > scripts/docs-files.txt
50+
node scripts/checkNav.mjs docs-files.txt
51+
4352
- name: Restore original nav.js
4453
working-directory: docs
4554
if: success() || failure()

docs/scripts/checkNav.mjs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env node
2+
3+
import fs from 'fs';
4+
import path from 'path';
5+
import { fileURLToPath, pathToFileURL } from 'url';
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
10+
const navPath = '../docs/nav.mjs';
11+
12+
const mdListPath = process.argv[2];
13+
if (!mdListPath) {
14+
console.error('Usage: node checkNav.mjs <md-list-file>');
15+
process.exit(1);
16+
}
17+
18+
const navFile = path.resolve(__dirname, navPath);
19+
const nav = await import(pathToFileURL(navFile).href).then(mod => mod.default);
20+
21+
const extractPathsFromNav = (items) =>
22+
items.filter(item => item.type === 'page').map(page => page.path);
23+
24+
const navPaths = extractPathsFromNav(nav.items);
25+
const navPathSet = new Set(navPaths);
26+
27+
const expectedMdPaths = fs.readFileSync(path.resolve(__dirname, mdListPath), 'utf8')
28+
.split('\n')
29+
.map(line => line.trim())
30+
.filter(Boolean);
31+
const expectedPathSet = new Set(expectedMdPaths);
32+
33+
const missingInNav = expectedMdPaths.filter(p => !navPathSet.has(p));
34+
const extraInNav = navPaths.filter(p => !expectedPathSet.has(p));
35+
36+
let failed = false;
37+
38+
if (missingInNav.length > 0) {
39+
console.error('❌ These docs are missing from nav:');
40+
missingInNav.forEach(p => console.error(`- ${p}`));
41+
failed = true;
42+
}
43+
44+
if (extraInNav.length > 0) {
45+
console.error('❌ These docs are listed in nav but not found under docs/:');
46+
extraInNav.forEach(p => console.error(`- ${p}`));
47+
failed = true;
48+
}
49+
50+
if (!failed) {
51+
console.log('✅ nav list matches filesystem.');
52+
} else {
53+
process.exit(1);
54+
}

0 commit comments

Comments
 (0)