#!/usr/bin/env python3 """Check every `foo.rs:N` / `foo.rs:N-M` / `web/config.js:N` line anchor in the docs. Paths may be bare (`notify.rs:320`, resolved under `src/`), prefixed with a directory (`src/domain/jmap/client.rs:108`, `cloudflare-worker/src/backends.js:9`, `web/config.js:585`), or unprefixed JavaScript (`config.js:585`, resolved under `web/` or the Worker). LIMITATION: this only proves the cited line *exists and is not blank*. It does not prove the line contains what the prose claims about it. A doc can pass this audit with anchors that point at the wrong line -- a human must read the target line to catch that. Keep this in mind when quoting "0 errors" as proof of accuracy: it proves reachability, not correctness. The one exception is a *phantom identifier*: if a backticked name sits right next to an anchor (the common "`foo` ... `bar.rs:N`" phrasing) and that name appears nowhere in bar.rs, the anchor is reported. Existence, not position -- the symbol may still be on the wrong line. """ import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] DOCS = ['AGENTS.md', 'README.md', 'README.zh-CN.md', 'docs/design.md', 'docs/deployment.md', 'docs/reference.md', 'docs/retired.md', 'docs/roadmap.md', 'docs/charter.md', 'cloudflare-worker/README.md'] IDENT = r'[A-Za-z_][A-Za-z0-9_]*(?:::[A-Za-z_][A-Za-z0-9_]*)?' FILE = r'((?:[A-Za-z0-9_.-]+/)?[A-Za-z0-9_-]+)' EXT = r'\.(rs|js):(\d+)' # A directory part is zero or more full segments (`/seg`), so the regex can never # split a file name like `debug.rs` into a "directory" plus a stray base. REF = re.compile( r'((?:src|cloudflare-worker/src|web)(?:/[A-Za-z0-9_.-]+)*/)?' + FILE + EXT + r'(?:\s*[,–\-]\s*(\d+))?' ) # A backticked identifier sitting right next to an anchor is an implicit claim: # "`foo` ... `bar.rs:N`". If `foo` never appears in bar.rs the anchor is a phantom. # The gap may not cross more than one backtick boundary and is capped at 40 # characters on each side, so only a genuinely coupled identifier/anchor pair # matches. An optional `()` after the identifier is tolerated, since prose often # writes function names that way. PAIR = re.compile( r'`(' + IDENT + r')(?:\(\))?`' r'[^`\n|]{0,40}?`?[^`\n|]{0,40}?' r'(? len(src): errors.append(f'{d}:{i} {p.name}:{a}-{b} out of range (file has {len(src)} lines)') continue lo = int(a) targets = {lo} | ({hi} if b else set()) for n in sorted(targets): checked += 1 if not src[n - 1].strip(): errors.append(f'{d}:{i} {p.name}:{a}{"-" + b if b else ""} -> line {n} is blank') print(f'=== ANCHOR AUDIT ({checked} line-refs checked, {len(errors)} errors) ===') for e in errors: print(e) sys.exit(1 if errors else 0)