-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathverify_links.py
More file actions
123 lines (104 loc) · 4.29 KB
/
verify_links.py
File metadata and controls
123 lines (104 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python3
"""Verify all cross-reference links in documentation."""
import re
from pathlib import Path
def extract_markdown_links(content):
"""Extract all markdown links from content."""
# Match [text](link) format
pattern = r'\[([^\]]+)\]\(([^\)]+)\)'
return re.findall(pattern, content)
def verify_links(base_path):
"""Verify all links in documentation files."""
docs_to_check = [
"README.md",
"docs/MIGRATION.md",
"docs/API_REFERENCE.md",
"QUICKSTART.md",
"CHANGELOG.md"
]
all_links = {}
errors = []
print("Checking documentation files for links...\n")
for doc_file in docs_to_check:
doc_path = base_path / doc_file
if not doc_path.exists():
errors.append(f"❌ {doc_file} does not exist")
continue
content = doc_path.read_text()
links = extract_markdown_links(content)
all_links[doc_file] = links
print(f"📄 {doc_file}: {len(links)} links found")
# Verify each link
for text, link in links:
# Skip external links (http/https)
if link.startswith('http://') or link.startswith('https://'):
continue
# Skip anchors within the same file
if link.startswith('#'):
continue
# Handle relative paths
if '/' in link or link.endswith('.md'):
# Remove anchor if present
link_path = link.split('#')[0]
# Resolve relative to document location
if doc_file.startswith('docs/'):
# Link from docs/ directory
if link_path.startswith('../'):
# Link to parent directory
target_path = base_path / link_path.replace('../', '')
elif link_path.startswith('./'):
# Link within docs/
target_path = base_path / 'docs' / link_path.replace('./', '')
else:
# Link within docs/
target_path = base_path / 'docs' / link_path
else:
# Link from root directory
if link_path.startswith('./'):
target_path = base_path / link_path.replace('./', '')
else:
target_path = base_path / link_path
# Check if target exists
if not target_path.exists():
errors.append(f"❌ {doc_file}: Broken link [{text}]({link}) -> {target_path}")
print(f"\n{'='*60}")
if errors:
print(f"\n❌ Found {len(errors)} broken links:\n")
for error in errors:
print(f" {error}")
return False
else:
print("\n✅ All cross-reference links are valid!")
# Print summary
print(f"\nSummary:")
total_links = sum(len(links) for links in all_links.values())
print(f" Total links checked: {total_links}")
print(f" Files checked: {len(docs_to_check)}")
# Print key cross-references
print(f"\nKey v0.3.0 cross-references:")
key_links = [
("README.md → MIGRATION.md", "docs/MIGRATION.md"),
("README.md → API_REFERENCE.md", "docs/API_REFERENCE.md"),
("README.md → HOOKS_GUIDE.md", ".claude-plugin/HOOKS_GUIDE.md"),
("MIGRATION.md → API_REFERENCE.md", "API_REFERENCE.md"),
("MIGRATION.md → HOOKS_GUIDE.md", "../.claude-plugin/HOOKS_GUIDE.md"),
("API_REFERENCE.md → MIGRATION.md", "MIGRATION.md"),
("QUICKSTART.md → MIGRATION.md", "docs/MIGRATION.md"),
]
for desc, link_target in key_links:
found = False
for doc, links in all_links.items():
for text, link in links:
if link_target in link:
found = True
print(f" ✓ {desc}")
break
if found:
break
if not found:
print(f" ⚠️ {desc} - NOT FOUND (may need to add)")
return True
if __name__ == "__main__":
base_path = Path(__file__).parent
success = verify_links(base_path)
exit(0 if success else 1)