83 lines
2.4 KiB
Python
Executable File
83 lines
2.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Validate frontmatter in markdown content.
|
|
Can be run by Claude during workflow or configured as a hook in settings.json
|
|
"""
|
|
import sys
|
|
import yaml
|
|
|
|
def validate_content(content):
|
|
"""Validate frontmatter in markdown content"""
|
|
if not content.startswith("---"):
|
|
return False, "No frontmatter detected"
|
|
|
|
try:
|
|
# Extract frontmatter
|
|
parts = content.split("---", 2)
|
|
if len(parts) < 3:
|
|
return False, "Malformed frontmatter (missing closing ---)"
|
|
|
|
frontmatter = yaml.safe_load(parts[1])
|
|
|
|
if not frontmatter:
|
|
return False, "Empty frontmatter"
|
|
|
|
# Required fields
|
|
required = ["title", "tags", "date", "type"]
|
|
missing = [f for f in required if f not in frontmatter]
|
|
|
|
if missing:
|
|
return False, f"Missing required fields: {', '.join(missing)}"
|
|
|
|
# Validate tags is a list
|
|
tags = frontmatter.get("tags", [])
|
|
if not isinstance(tags, list):
|
|
return False, "Tags must be a list"
|
|
|
|
if len(tags) == 0:
|
|
return False, "Tags list is empty"
|
|
|
|
# Check for content type tag
|
|
valid_types = ["video", "article", "book", "podcast", "idea", "study-guide", "repository", "reference", "project"]
|
|
has_type = any(tag in valid_types for tag in tags)
|
|
if not has_type:
|
|
return False, f"No content type tag found. Expected one of: {', '.join(valid_types)}"
|
|
|
|
# Check for inbox tag
|
|
if "inbox" not in tags:
|
|
return False, "Warning: 'inbox' tag recommended for new content"
|
|
|
|
return True, "✅ Validation passed"
|
|
|
|
except yaml.YAMLError as e:
|
|
return False, f"Invalid YAML syntax: {e}"
|
|
except Exception as e:
|
|
return False, f"Validation error: {e}"
|
|
|
|
def main():
|
|
"""Main entry point for validation script"""
|
|
if len(sys.argv) > 1:
|
|
# Read from file if provided
|
|
filename = sys.argv[1]
|
|
try:
|
|
with open(filename, 'r') as f:
|
|
content = f.read()
|
|
except FileNotFoundError:
|
|
print(f"❌ Error: File not found: {filename}", file=sys.stderr)
|
|
sys.exit(1)
|
|
else:
|
|
# Read from stdin
|
|
content = sys.stdin.read()
|
|
|
|
valid, message = validate_content(content)
|
|
|
|
if valid:
|
|
print(message)
|
|
sys.exit(0)
|
|
else:
|
|
print(f"❌ {message}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|