Skip to content

Commit 757669f

Browse files
louis-preclaude
andcommitted
fix: Replace ad-hoc YAML parser with yaml package in redirect validator
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 076e084 commit 757669f

3 files changed

Lines changed: 29 additions & 43 deletions

File tree

codegen/validate-redirects.ts

Lines changed: 11 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,22 @@
11
import { existsSync, readFileSync } from 'node:fs'
22
import { join } from 'node:path'
33

4+
import YAML from 'yaml'
5+
46
import { siteSections } from './lib/config.js'
57

6-
// Parse the redirects section from .gitbook.yaml.
7-
// Each redirect line is: " source-path: target-path"
8-
const gitbookYaml = readFileSync('.gitbook.yaml', 'utf-8')
9-
const lines = gitbookYaml.split('\n')
8+
const gitbookConfig = YAML.parse(readFileSync('.gitbook.yaml', 'utf-8')) as {
9+
redirects?: Record<string, string>
10+
}
1011

1112
interface Redirect {
12-
line: number
1313
source: string
1414
target: string
1515
}
1616

17-
const redirects: Redirect[] = []
18-
let inRedirects = false
19-
20-
for (let i = 0; i < lines.length; i++) {
21-
const line = lines[i] ?? ''
22-
23-
if (line === 'redirects:') {
24-
inRedirects = true
25-
continue
26-
}
27-
28-
// A non-indented, non-empty line ends the redirects section
29-
if (inRedirects && line !== '' && !line.startsWith(' ')) {
30-
break
31-
}
32-
33-
if (!inRedirects) continue
34-
35-
const match = line.match(/^\s+(.+?):\s+(.+)$/)
36-
if (match?.[1] != null && match[2] != null) {
37-
redirects.push({ line: i + 1, source: match[1], target: match[2] })
38-
}
39-
}
17+
const redirects: Redirect[] = Object.entries(
18+
gitbookConfig.redirects ?? {},
19+
).map(([source, target]) => ({ source, target }))
4020

4121
// Check if a path resolves to a page as a file, URL slug, or directory index.
4222
function pageExists(fullPath: string): boolean {
@@ -77,28 +57,16 @@ function resolveTarget(target: string): boolean {
7757
return pageExists(join(guidesSection.root, target))
7858
}
7959

80-
interface BrokenRedirect {
81-
line: number
82-
source: string
83-
target: string
84-
}
85-
86-
const broken: BrokenRedirect[] = []
87-
88-
for (const redirect of redirects) {
89-
if (!resolveTarget(redirect.target)) {
90-
broken.push(redirect)
91-
}
92-
}
60+
const broken: Redirect[] = redirects.filter((r) => !resolveTarget(r.target))
9361

9462
if (broken.length > 0) {
9563
// eslint-disable-next-line no-console
9664
console.error(
9765
`Found ${broken.length} redirect(s) with missing target(s) in .gitbook.yaml:\n`,
9866
)
99-
for (const { line, source, target } of broken) {
67+
for (const { source, target } of broken) {
10068
// eslint-disable-next-line no-console
101-
console.error(` line ${line}: ${source}`)
69+
console.error(` ${source}`)
10270
// eslint-disable-next-line no-console
10371
console.error(` target: ${target}\n`)
10472
}

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"command-exists": "^1.2.9",
4343
"execa": "^9.3.1",
4444
"prettier": "^3.0.0",
45+
"yaml": "^2.8.3",
4546
"zod": "^3.23.8"
4647
}
4748
}

0 commit comments

Comments
 (0)