참고소스 수정본
This commit is contained in:
143
참고/instructor-main/scripts/validate_headings.py
Normal file
143
참고/instructor-main/scripts/validate_headings.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Validate heading structure in documentation files.
|
||||
|
||||
Checks for:
|
||||
- Multiple H1 tags (should only have one)
|
||||
- Heading hierarchy violations (e.g., H1 → H3 skipping H2)
|
||||
- Missing H1 tags
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def find_markdown_files(docs_dir: Path) -> list[Path]:
|
||||
"""Find all markdown files in the docs directory."""
|
||||
return list(docs_dir.rglob("*.md"))
|
||||
|
||||
|
||||
def extract_headings(content: str) -> list[tuple[int, str, int]]:
|
||||
"""
|
||||
Extract all headings from markdown content.
|
||||
|
||||
Returns:
|
||||
List of (level, text, line_number) tuples
|
||||
"""
|
||||
headings = []
|
||||
lines = content.split("\n")
|
||||
|
||||
for line_num, line in enumerate(lines, 1):
|
||||
# Match markdown headings: # Title, ## Title, etc.
|
||||
match = re.match(r"^(#{1,6})\s+(.+)$", line)
|
||||
if match:
|
||||
level = len(match.group(1))
|
||||
text = match.group(2).strip()
|
||||
headings.append((level, text, line_num))
|
||||
|
||||
return headings
|
||||
|
||||
|
||||
def validate_headings(headings: list[tuple[int, str, int]]) -> dict[str, list[str]]:
|
||||
"""Validate heading structure."""
|
||||
issues = {}
|
||||
|
||||
if not headings:
|
||||
issues["no_headings"] = ["No headings found in file"]
|
||||
return issues
|
||||
|
||||
# Check for H1
|
||||
h1_headings = [h for h in headings if h[0] == 1]
|
||||
if not h1_headings:
|
||||
issues["missing_h1"] = ["No H1 heading found"]
|
||||
elif len(h1_headings) > 1:
|
||||
issues["multiple_h1"] = [
|
||||
f"Line {line}: {text}" for level, text, line in h1_headings
|
||||
]
|
||||
|
||||
# Check heading hierarchy
|
||||
prev_level = 0
|
||||
hierarchy_violations = []
|
||||
for level, text, line_num in headings:
|
||||
if prev_level > 0 and level > prev_level + 1:
|
||||
hierarchy_violations.append(
|
||||
f"Line {line_num}: Skipped from H{prev_level} to H{level}: {text[:50]}"
|
||||
)
|
||||
prev_level = level
|
||||
|
||||
if hierarchy_violations:
|
||||
issues["hierarchy_violations"] = hierarchy_violations
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def process_file(file_path: Path) -> dict[str, list[str]]:
|
||||
"""Process a single file and return issues."""
|
||||
try:
|
||||
content = file_path.read_text(encoding="utf-8")
|
||||
headings = extract_headings(content)
|
||||
return validate_headings(headings)
|
||||
except Exception as e:
|
||||
return {"error": [str(e)]}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Validate heading structure in documentation files"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--docs-dir",
|
||||
type=Path,
|
||||
default=Path("docs"),
|
||||
help="Directory containing documentation files (default: docs)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--summary",
|
||||
action="store_true",
|
||||
help="Show only summary statistics",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--file",
|
||||
type=Path,
|
||||
help="Validate a single file instead of all files",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.file:
|
||||
files = [args.file]
|
||||
else:
|
||||
files = find_markdown_files(args.docs_dir)
|
||||
|
||||
all_issues = {}
|
||||
total_counts = defaultdict(int)
|
||||
|
||||
for file_path in files:
|
||||
issues = process_file(file_path)
|
||||
if issues:
|
||||
all_issues[str(file_path)] = issues
|
||||
for issue_type, messages in issues.items():
|
||||
total_counts[issue_type] += len(messages)
|
||||
|
||||
if args.summary:
|
||||
print("Summary Statistics:")
|
||||
print("=" * 60)
|
||||
for issue_type, count in sorted(total_counts.items()):
|
||||
print(f" {issue_type.replace('_', ' ').title()}: {count}")
|
||||
else:
|
||||
# Detailed report
|
||||
for file_path, issues in sorted(all_issues.items()):
|
||||
print(f"\n{file_path}:")
|
||||
for issue_type, messages in issues.items():
|
||||
print(f" {issue_type.replace('_', ' ').title()}:")
|
||||
for message in messages:
|
||||
print(f" {message}")
|
||||
|
||||
print(f"\nTotal files checked: {len(files)}")
|
||||
print(f"Files with issues: {len(all_issues)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user