Download scripts/wiki_check.py from logos42/headless: direct link, hf CLI and curl.
- Browser
- Download file 7.26 kB
-
https://huggingface.co/logos42/headless/resolve/main/scripts/wiki_check.py
- Command line
-
hf download hf://logos42/headless/scripts/wiki_check.py
-
curl -L -o wiki_check.py https://huggingface.co/logos42/headless/resolve/main/scripts/wiki_check.py
7.26 kB
| from __future__ import annotations | |
| # llm-wiki-version: 2.0.0 | |
| # runtime: ci-safe (structural only) | |
| import re | |
| import sys | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| WIKI_ROOT = ROOT / "docs" / "wiki" | |
| REQUIRED_FILES = [ | |
| "README.md", | |
| "SCHEMA.md", | |
| "index.md", | |
| "log.md", | |
| "project-overview.md", | |
| "current-status.md", | |
| "sources-and-data.md", | |
| "github-and-raw-strategy.md", | |
| ] | |
| LOG_HEADER_RE = re.compile(r"^## \[\d{4}-\d{2}-\d{2}\] .+ \| .+$") | |
| FRONTMATTER_RE = re.compile(r"^---\n(.*?)\n---", re.DOTALL) | |
| FRONTMATTER_EXEMPT = {"index.md", "log.md", "README.md", "SCHEMA.md"} | |
| REQUIRED_FRONTMATTER_KEYS = {"title", "source", "created"} | |
| # v2 升级:log.md 支持表格格式("table")或 H2 日期头("header"),默认 "table" | |
| # 表格格式 = 第一行以 "| " 开头(markdown 表格) | |
| LOG_FORMAT = "table" # "table" | "header" | |
| def is_log_table_format(text: str) -> bool: | |
| """log.md 是否用 markdown 表格(≥3 行以 | 开头)。""" | |
| table_lines = [ln for ln in text.splitlines() if ln.startswith("|")] | |
| return len(table_lines) >= 3 | |
| # Don't validate links inside fenced code (```), indented code, or inline code. | |
| FENCE_RE = re.compile(r"^(\s*)(```|~~~)") | |
| INLINE_CODE_RE = re.compile(r"`[^`\n]*`") | |
| LINK_OPEN_RE = re.compile(r"!?\[(?:[^\[\]\\]|\\.)*\]\(") | |
| def strip_inline_code(line: str) -> str: | |
| return INLINE_CODE_RE.sub("", line) | |
| def iter_link_targets(text: str) -> list[str]: | |
| """Return every (link target) found outside fenced/inline code. | |
| Properly handles balanced parens inside the URL portion (rare but legal). | |
| """ | |
| out: list[str] = [] | |
| in_fence = False | |
| fence_marker = "" | |
| for raw_line in text.splitlines(): | |
| m = FENCE_RE.match(raw_line) | |
| if m: | |
| marker = m.group(2) | |
| if not in_fence: | |
| in_fence = True | |
| fence_marker = marker | |
| elif marker == fence_marker: | |
| in_fence = False | |
| fence_marker = "" | |
| continue | |
| if in_fence: | |
| continue | |
| line = strip_inline_code(raw_line) | |
| pos = 0 | |
| while True: | |
| m = LINK_OPEN_RE.search(line, pos) | |
| if not m: | |
| break | |
| start = m.end() | |
| depth = 1 | |
| i = start | |
| while i < len(line) and depth > 0: | |
| ch = line[i] | |
| if ch == "\\" and i + 1 < len(line): | |
| i += 2 | |
| continue | |
| if ch == "(": | |
| depth += 1 | |
| elif ch == ")": | |
| depth -= 1 | |
| if depth == 0: | |
| break | |
| i += 1 | |
| if depth == 0: | |
| target = line[start:i].strip() | |
| if target.startswith("<") and target.endswith(">"): | |
| target = target[1:-1].strip() | |
| title_match = re.search(r'\s+["\'(].*["\')]$', target) | |
| if title_match: | |
| target = target[: title_match.start()].strip() | |
| out.append(target) | |
| pos = i + 1 | |
| else: | |
| pos = len(line) | |
| return out | |
| def check_frontmatter(path: Path, text: str) -> list[str]: | |
| errs: list[str] = [] | |
| if path.name in FRONTMATTER_EXEMPT: | |
| return errs | |
| m = FRONTMATTER_RE.match(text) | |
| if not m: | |
| errs.append(f"missing frontmatter: {path.relative_to(ROOT)}") | |
| return errs | |
| body = m.group(1) | |
| found_keys: set[str] = set() | |
| for line in body.splitlines(): | |
| if ":" in line: | |
| key = line.split(":", 1)[0].strip() | |
| found_keys.add(key) | |
| missing = REQUIRED_FRONTMATTER_KEYS - found_keys | |
| if missing: | |
| errs.append(f"missing frontmatter keys in {path.relative_to(ROOT)}: {', '.join(sorted(missing))}") | |
| return errs | |
| def resolve_link(source_file: Path, target: str) -> Path | None: | |
| if target.startswith(("http://", "https://", "mailto:", "tel:", "ftp://")): | |
| return None | |
| if target.startswith("#"): | |
| return None | |
| target = target.split("#", 1)[0].split("?", 1)[0] | |
| if not target: | |
| return None | |
| return (source_file.parent / target).resolve() | |
| def index_referenced_pages(index_path: Path) -> set[str]: | |
| """Set of wiki-relative posix paths that index.md actually links to. | |
| Uses real link parsing instead of substring matching, so a page named | |
| `policy.md` doesn't accidentally pass because index.md mentions | |
| `pricing-policy.md`. | |
| """ | |
| if not index_path.exists(): | |
| return set() | |
| text = index_path.read_text(encoding="utf-8") | |
| refs: set[str] = set() | |
| for raw_target in iter_link_targets(text): | |
| resolved = resolve_link(index_path, raw_target) | |
| if resolved is None: | |
| continue | |
| try: | |
| rel = resolved.relative_to(WIKI_ROOT.resolve()).as_posix() | |
| except ValueError: | |
| continue | |
| refs.add(rel) | |
| return refs | |
| def main() -> int: | |
| errors: list[str] = [] | |
| if not WIKI_ROOT.exists(): | |
| print("wiki_check: docs/wiki does not exist") | |
| return 1 | |
| for rel in REQUIRED_FILES: | |
| if not (WIKI_ROOT / rel).exists(): | |
| errors.append(f"missing required file: docs/wiki/{rel}") | |
| md_files = sorted(WIKI_ROOT.rglob("*.md")) | |
| index_refs = index_referenced_pages(WIKI_ROOT / "index.md") | |
| EXEMPT_FROM_INDEX = {"README.md", "SCHEMA.md", "log.md", "index.md"} | |
| fm_ok = 0 | |
| for path in md_files: | |
| text = path.read_text(encoding="utf-8") | |
| fm_errors = check_frontmatter(path, text) | |
| errors.extend(fm_errors) | |
| if not fm_errors and path.name not in FRONTMATTER_EXEMPT: | |
| fm_ok += 1 | |
| if path.name == "log.md": | |
| # v2 升级:表格格式下跳过 H2 日期头校验 | |
| if LOG_FORMAT == "header": | |
| for line in text.splitlines(): | |
| if line.startswith("## ") and not LOG_HEADER_RE.match(line): | |
| errors.append(f"bad log header format in {path.relative_to(ROOT)}: {line}") | |
| elif LOG_FORMAT == "table": | |
| if not is_log_table_format(text): | |
| errors.append(f"log.md not in table format (LOG_FORMAT=table) in {path.relative_to(ROOT)}") | |
| rel = path.relative_to(WIKI_ROOT).as_posix() | |
| if rel not in EXEMPT_FROM_INDEX and rel not in index_refs: | |
| errors.append(f"index.md does not reference docs/wiki/{rel}") | |
| for raw_target in iter_link_targets(text): | |
| resolved = resolve_link(path, raw_target) | |
| if resolved is None: | |
| continue | |
| if not resolved.exists(): | |
| errors.append(f"broken link in {path.relative_to(ROOT)} -> {raw_target}") | |
| if errors: | |
| print("wiki_check: FAILED") | |
| for item in errors: | |
| print(f"- {item}") | |
| return 1 | |
| print("wiki_check: OK") | |
| print(f"- markdown files: {len(md_files)}") | |
| print(f"- required files: {len(REQUIRED_FILES)}") | |
| print(f"- frontmatter valid: {fm_ok}") | |
| print(f"- index.md links: {len(index_refs)}") | |
| print(f"- wiki root: {WIKI_ROOT}") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |