From 97aefb69923aa2bb7f879f7457db2eb74b84bb00 Mon Sep 17 00:00:00 2001 From: stacknil Date: Sun, 31 May 2026 12:35:42 +0800 Subject: [PATCH 1/2] test(review): check markdown link integrity --- tests/test_markdown_links.py | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/test_markdown_links.py diff --git a/tests/test_markdown_links.py b/tests/test_markdown_links.py new file mode 100644 index 0000000..e7d74da --- /dev/null +++ b/tests/test_markdown_links.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import re +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +MARKDOWN_LINK_RE = re.compile(r"!?\[[^\]]*\]\(([^)]+)\)") + + +def _markdown_files() -> list[Path]: + return [ + REPO_ROOT / "README.md", + *sorted((REPO_ROOT / "docs").glob("*.md")), + *sorted((REPO_ROOT / "demos").glob("*/README.md")), + ] + + +def _local_target(raw_target: str) -> str | None: + target = raw_target.strip() + if not target or target.startswith("#"): + return None + if target.startswith(("http://", "https://", "mailto:")): + return None + if " " in target: + target = target.split(" ", 1)[0] + return target.split("#", 1)[0] + + +def test_public_markdown_local_links_point_to_existing_paths() -> None: + missing_links: list[str] = [] + + for markdown_path in _markdown_files(): + text = markdown_path.read_text(encoding="utf-8") + for match in MARKDOWN_LINK_RE.finditer(text): + target = _local_target(match.group(1)) + if target is None: + continue + + resolved = (markdown_path.parent / target).resolve() + try: + resolved.relative_to(REPO_ROOT.resolve()) + except ValueError: + missing_links.append( + f"{markdown_path.relative_to(REPO_ROOT)} links outside repo: {target}" + ) + continue + + if not resolved.exists(): + missing_links.append( + f"{markdown_path.relative_to(REPO_ROOT)} -> {target}" + ) + + assert missing_links == [] From 7479bb82d61eeaf729ebf9a5a2adab51ae5fbfb9 Mon Sep 17 00:00:00 2001 From: stacknil Date: Sun, 31 May 2026 14:13:37 +0800 Subject: [PATCH 2/2] test(review): scan nested markdown links --- tests/test_markdown_links.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_markdown_links.py b/tests/test_markdown_links.py index e7d74da..1e7fb59 100644 --- a/tests/test_markdown_links.py +++ b/tests/test_markdown_links.py @@ -11,8 +11,8 @@ def _markdown_files() -> list[Path]: return [ REPO_ROOT / "README.md", - *sorted((REPO_ROOT / "docs").glob("*.md")), - *sorted((REPO_ROOT / "demos").glob("*/README.md")), + *sorted((REPO_ROOT / "docs").rglob("*.md")), + *sorted((REPO_ROOT / "demos").rglob("*.md")), ]