"""Validate contributor-facing Markdown and use-case documentation.""" from __future__ import annotations import re from pathlib import Path SKIP_DIRS = {".git", "node_modules", ".venv", ".uv-cache"} USE_CASE_TABLES = { Path("README.md"): "## Use Cases", Path("use-cases/README.md"): "## Use Cases", } PRIMARY_LINK_RE = re.compile( r"^\[(?:Code|Plugin|Live Demo|Learn more)\]\(([^)]+)\)", flags=re.M, ) def _markdown_files() -> list[Path]: return sorted( path for path in Path(".").rglob("*.md") if not any(part in SKIP_DIRS for part in path.parts) ) def _check_active_relative_links() -> list[str]: missing: list[str] = [] root = Path.cwd().resolve() for path in _markdown_files(): active = re.sub(r"", "", path.read_text(), flags=re.S) for raw in re.findall(r"\[[^\]]*\]\(([^)]+)\)", active): link = raw.split("#", 1)[0] if not link or link.startswith(("http://", "https://", "mailto:")): continue target = (path.parent / link).resolve() try: target.relative_to(root) except ValueError: missing.append(f"{path}: {raw} -> outside repository") continue if not target.exists(): missing.append(f"{path}: {raw} -> missing") return missing def _check_use_case_banner_links() -> tuple[list[str], list[str]]: failures: list[str] = [] warnings: list[str] = [] for path, heading in USE_CASE_TABLES.items(): text = path.read_text() start = text.find(heading) if start == -1: failures.append(f"{path}: missing {heading}") continue table_start = text.find("