Files
Vijay Janapa Reddi 7d81b501a1 Fix index audit detectors: HTML comments, YAML scope, bold spans
format_audit.py:
  - V7 (YAML frontmatter) was toggling on every thematic-break `---`,
    misclassifying mid-chapter prose as YAML. Restrict to the opening
    metadata block only (first-line `---` opens; next `---` closes).
  - Skip `<!-- ... -->` HTML comments so retired figure source doesn't
    register false V1/V2 hits.
  - Factor V1 (\\index{} inside bold) and V2 (inside italic) detection
    into bold_spans() and text_before_for_italic_scan() helpers; the
    inline ad-hoc star-counting was hard to follow and brittle.
  - Ensure OUTDIR exists before writing the CSV.

check_anti_patterns.py / check_tag_placement.py / check_xref_resolves.py:
  - Convert module docstrings to raw strings — they contain literal
    \\index{} examples that the cooked form was misreading.
2026-05-23 11:40:30 -04:00

53 lines
1.7 KiB
Python

#!/usr/bin/env python3
r"""
book-index-xref-resolves hook.
Fails if any \index{X|see{Y}} or \index{X|seealso{Y}} target Y doesn't
resolve to a real main entry in the corpus.
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
ROOT = Path.cwd()
CONTENT = ROOT / "book" / "quarto" / "contents"
INDEX_RE = re.compile(r"\\index\{([^{}]*(?:\{[^{}]*\}[^{}]*)?)\}")
SEEREF_RE = re.compile(r"^([^|]+)\|see(?:also)?\{([^}]+)\}$")
def main():
main_heads = set()
see_refs = []
for f in sorted(CONTENT.rglob("*.qmd")):
s = str(f)
if any(x in s for x in ("frontmatter/", "backmatter/", "/parts/",
"/glossary/", "/appendix", "_shelved")):
continue
text = f.read_text(errors="replace")
for m in INDEX_RE.finditer(text):
k = m.group(1)
sm = SEEREF_RE.match(k)
if sm:
see_refs.append((f.relative_to(ROOT), sm.group(1).strip(),
sm.group(2).strip()))
else:
# Main entry — record headword
h = k.split("!", 1)[0]
if "@" in h:
h = h.split("@", 1)[1]
main_heads.add(h)
broken = [(rel, src, tgt) for rel, src, tgt in see_refs if tgt not in main_heads]
if broken:
print(f"Index cross-reference audit FAILED: {len(broken)} unresolved targets")
for rel, src, tgt in broken[:15]:
print(f" {rel}: '{src}' -> '{tgt}' (target not found)")
return 1
print(f"Index cross-reference audit PASSED ({len(see_refs)} cross-refs, all resolve)")
return 0
if __name__ == "__main__":
sys.exit(main())