104 index.setdefault(os.path.basename(fp).lower(), []).append(os.path.relpath(fp, REPO))
106 dead, checked = [], 0
108 d = os.path.dirname(fp)
109 text = open(fp, encoding=
"utf-8", errors=
"replace").read()
111 for m
in _code_span.finditer(text):
112 src[m.group(1)] =
"code-span"
113 for m
in _md_link.finditer(text):
114 src[m.group(1)] =
"LINK"
115 for raw, s
in src.items():
121 dead.append((os.path.relpath(fp, REPO), t,
bucket(fp), s))
124 base = t.rstrip(
"/").split(
"/")[-1].lower()
125 return [c
for c
in index.get(base, [])
if c.replace(
"\\",
"/") != t]
127 core = sorted(set((d[0], d[1], d[3])
for d
in dead
if d[2] ==
"CORE"))
128 nav_moved = [(fp, t, cands(t))
for fp, t, s
in core
if s ==
"LINK" and cands(t)]
129 print(f
"scanned {len(files)} .md files; checked {checked} .md nav-links")
130 print(f
"\nA. GENUINE BROKEN NAV LINKS (markdown [](...) links in active docs, target moved): {len(nav_moved)}")
131 for fp, t, c
in nav_moved:
132 print(f
" {fp}\n [](link): {t}\n now at: {', '.join(c[:2])}")
135 print(
"\n(CONTEXT / EXEMPT / never-existed buckets suppressed -- tweak the script to surface them.)")