PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
check_markdown_links.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2"""Basic local markdown link checker for README + authored docs pages."""
3
4import re
5import sys
6from pathlib import Path
7
8
9LINK_PATTERN = re.compile(r"!\[[^\]]*\]\‍(([^)\s]+)(?:\s+\"[^\"]*\")?\‍)|\[[^\]]*\]\‍(([^)\s]+)(?:\s+\"[^\"]*\")?\‍)")
10
11
12def iter_markdown_files(repo_root: Path):
13 yield repo_root / "README.md"
14 for md in sorted((repo_root / "docs").rglob("*.md")):
15 if "docs_build" in md.parts:
16 continue
17 yield md
18
19
20def should_skip_link(target: str) -> bool:
21 lower = target.lower()
22 return (
23 lower.startswith("http://")
24 or lower.startswith("https://")
25 or lower.startswith("mailto:")
26 or lower.startswith("#")
27 )
28
29
30def normalize_target(raw_target: str) -> str:
31 cleaned = raw_target.strip().strip("<>").split("#", 1)[0].split("?", 1)[0]
32 return cleaned
33
34
35def main() -> int:
36 repo_root = Path(__file__).resolve().parents[1]
37 failures = []
38
39 for md_file in iter_markdown_files(repo_root):
40 if not md_file.is_file():
41 failures.append((str(md_file), "<file>", "Markdown file not found"))
42 continue
43 content = md_file.read_text(encoding="utf-8", errors="replace")
44 for match in LINK_PATTERN.findall(content):
45 target = match[0] or match[1]
46 if should_skip_link(target):
47 continue
48 normalized = normalize_target(target)
49 if not normalized:
50 continue
51 resolved = (md_file.parent / normalized).resolve()
52 if not resolved.exists():
53 failures.append((str(md_file.relative_to(repo_root)), target, str(resolved)))
54
55 if failures:
56 print("Broken markdown links detected:")
57 for src, target, resolved in failures:
58 print(f" - {src}: '{target}' -> missing '{resolved}'")
59 return 1
60
61 print("Markdown link check passed for README.md and docs/**/*.md")
62 return 0
63
64
65if __name__ == "__main__":
66 sys.exit(main())