Files
2025-10-23 19:29:26 +02:00

86 lines
3.0 KiB
Python

"""
Frontmatter rules engine
"""
import json
import re
from pathlib import Path
from typing import List, Tuple
class RulesEngine:
def __init__(self, rules_dir: Path):
self.rules_dir = rules_dir
self.rules = self._load_rules()
def _load_rules(self) -> List[dict]:
"""Load all rule files"""
rules = []
if self.rules_dir.exists():
for rule_file in self.rules_dir.glob('*.json'):
with open(rule_file, 'r', encoding='utf-8') as f:
rules.append(json.load(f))
return rules
def apply_rules(self, frontmatter: dict) -> Tuple[dict, bool]:
"""Apply all rules to frontmatter, return (modified_fm, is_conformant)"""
if not frontmatter:
return frontmatter, True
modified = dict(frontmatter)
violations = []
# Rule: lowercase keys (run first so we can check other rules)
key_changes = {}
for key in list(modified.keys()):
lower_key = key.lower()
if lower_key != key:
key_changes[key] = lower_key
violations.append('lowercase_keys')
for old_key, new_key in key_changes.items():
modified[new_key] = modified.pop(old_key)
# Rule: tag -> tags (after lowercase conversion)
if 'tag' in modified:
modified['tags'] = modified.pop('tag')
violations.append('tag_to_tags')
# Rule: summary -> description (after lowercase conversion)
if 'summary' in modified:
modified['description'] = modified.pop('summary')
violations.append('summary_to_description')
# Rule: normalize tags
if 'tags' in modified:
original_tags = modified['tags']
# Convert to list if comma-separated string
if isinstance(original_tags, str):
tags_list = [t.strip() for t in original_tags.split(',')]
violations.append('tags_format')
else:
tags_list = original_tags if isinstance(original_tags, list) else [str(original_tags)]
# Normalize each tag
normalized_tags = []
for tag in tags_list:
tag_str = str(tag)
# Replace spaces and hyphens with underscores
normalized = tag_str.replace(' ', '_').replace('-', '_')
# Convert to lowercase
normalized = normalized.lower()
# Remove invalid characters (keep only alphanumeric and underscore)
normalized = re.sub(r'[^a-z0-9_]', '', normalized)
if normalized and normalized != tag_str:
violations.append('tags_normalized')
if normalized:
normalized_tags.append(normalized)
modified['tags'] = normalized_tags
is_conformant = len(violations) == 0
return modified, is_conformant