221 lines
8.2 KiB
Python
221 lines
8.2 KiB
Python
"""
|
|
Smart Template Discovery System - Grug-approved simplification
|
|
Replaces the complex nested template discovery with simple, debuggable logic
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional, List
|
|
|
|
|
|
class TemplateDiscovery:
|
|
"""
|
|
Simple template discovery that maintains all current functionality
|
|
Following grug principles: clear priority order, easy to debug
|
|
"""
|
|
|
|
def __init__(self, template_root: Path):
|
|
self.template_root = Path(template_root)
|
|
self._last_search_candidates = []
|
|
|
|
def find_template(self, content_path: Path, file_type: str, categories: List[str], extension: str) -> Optional[Path]:
|
|
"""
|
|
Find the best template for the given content
|
|
Uses simple priority list instead of complex nested loops
|
|
"""
|
|
# Build candidate template names in priority order
|
|
candidates = self._build_candidate_list(content_path, file_type, categories, extension)
|
|
self._last_search_candidates = candidates.copy() # Store for debugging
|
|
|
|
# Search from current directory up to template root (preserve hierarchy)
|
|
search_path = self.template_root / content_path.parent
|
|
while search_path >= self.template_root:
|
|
for candidate in candidates:
|
|
template_path = search_path / candidate
|
|
if template_path.exists():
|
|
return template_path
|
|
search_path = search_path.parent
|
|
|
|
return None
|
|
|
|
def get_last_search_candidates(self) -> List[str]:
|
|
"""Get the candidates from the last template search - for debugging"""
|
|
return self._last_search_candidates.copy()
|
|
|
|
def _build_candidate_list(self, content_path: Path, file_type: str, categories: List[str], extension: str) -> List[str]:
|
|
"""
|
|
Build list of template candidates in priority order
|
|
This replaces the complex nested loop logic with simple, clear ordering
|
|
"""
|
|
candidates = []
|
|
|
|
# 1. Specific file template (highest priority)
|
|
candidates.append(f"{content_path.stem}.html")
|
|
|
|
# 2. Type + extension templates
|
|
if extension:
|
|
candidates.append(f"__{file_type}.{extension}.html")
|
|
|
|
# 3. Type + category templates (preserve current category system)
|
|
for category in reversed(categories): # Most specific categories first
|
|
candidates.append(f"__{file_type}.{category}.html")
|
|
|
|
# 4. Generic type template
|
|
candidates.append(f"__{file_type}.html")
|
|
|
|
# 5. Default template (for ultimate fallback)
|
|
candidates.append("default.html")
|
|
|
|
return candidates
|
|
|
|
def find_style_candidates(self, content_path: Path, file_type: str, categories: List[str], extension: str) -> List[str]:
|
|
"""
|
|
Find CSS style candidates - similar logic to templates but for styles
|
|
Returns list of potential style paths in priority order
|
|
"""
|
|
candidates = []
|
|
|
|
# 1. Specific style for the content path
|
|
candidates.append(f"/{content_path}.css")
|
|
|
|
# 2. Type + extension styles in current and parent directories
|
|
search_path = content_path.parent
|
|
while True:
|
|
if extension:
|
|
candidates.append(f"/{search_path}/__{file_type}.{extension}.css")
|
|
|
|
# 3. Type + category styles
|
|
for category in reversed(categories):
|
|
candidates.append(f"/{search_path}/__{file_type}.{category}.css")
|
|
|
|
if search_path == Path('.'):
|
|
break
|
|
search_path = search_path.parent
|
|
|
|
# 4. Base style (always included)
|
|
candidates.append("/base.css")
|
|
|
|
return candidates
|
|
|
|
def debug_template_discovery(self, content_path: Path, file_type: str, categories: List[str], extension: str) -> dict:
|
|
"""
|
|
Debug information for template discovery - helps with troubleshooting
|
|
Grug-approved: when things break, need easy way to see what's happening
|
|
"""
|
|
candidates = self._build_candidate_list(content_path, file_type, categories, extension)
|
|
|
|
debug_info = {
|
|
'content_path': str(content_path),
|
|
'file_type': file_type,
|
|
'categories': categories,
|
|
'extension': extension,
|
|
'candidates': candidates,
|
|
'search_paths': [],
|
|
'found_templates': [],
|
|
'chosen_template': None
|
|
}
|
|
|
|
# Check each search path
|
|
search_path = self.template_root / content_path.parent
|
|
while search_path >= self.template_root:
|
|
debug_info['search_paths'].append(str(search_path))
|
|
|
|
for candidate in candidates:
|
|
template_path = search_path / candidate
|
|
if template_path.exists():
|
|
debug_info['found_templates'].append(str(template_path))
|
|
if debug_info['chosen_template'] is None:
|
|
debug_info['chosen_template'] = str(template_path)
|
|
|
|
search_path = search_path.parent
|
|
|
|
return debug_info
|
|
|
|
|
|
class LegacyTemplateDiscovery:
|
|
"""
|
|
Wrapper around the original complex template discovery for comparison
|
|
Helps ensure we don't break anything during migration
|
|
"""
|
|
|
|
def __init__(self, template_root: Path):
|
|
self.template_root = Path(template_root)
|
|
|
|
def find_template_legacy(self, content_path: Path, file_type: str, categories: List[str], extension: str) -> Optional[Path]:
|
|
"""
|
|
Original complex template discovery logic (from renderer.py)
|
|
Kept for comparison and gradual migration
|
|
"""
|
|
templates = []
|
|
|
|
# Check for folder template
|
|
if file_type == "folder":
|
|
folder_template = self.template_root / content_path / "__folder.html"
|
|
if folder_template.exists():
|
|
templates.append(folder_template)
|
|
else:
|
|
# Check for specific file template
|
|
specific_template = self.template_root / f"{content_path}.html"
|
|
if specific_template.exists():
|
|
templates.append(specific_template)
|
|
|
|
# If no specific template found, search with complex nested logic
|
|
if len(templates) == 0:
|
|
search_path = self.template_root / content_path.parent
|
|
while search_path >= self.template_root:
|
|
# Check type + extension
|
|
type_ext_template = search_path / f"__{file_type}.{extension}.html"
|
|
if type_ext_template.exists():
|
|
templates.append(type_ext_template)
|
|
break
|
|
|
|
# Check type + categories
|
|
for category in reversed(categories):
|
|
type_cat_template = search_path / f"__{file_type}.{category}.html"
|
|
if type_cat_template.exists():
|
|
templates.append(type_cat_template)
|
|
break
|
|
|
|
search_path = search_path.parent
|
|
|
|
return templates[0] if templates else None
|
|
|
|
|
|
def migrate_template_discovery(old_discovery: LegacyTemplateDiscovery, new_discovery: TemplateDiscovery) -> dict:
|
|
"""
|
|
Migration helper to compare old vs new template discovery
|
|
Helps ensure we don't break anything
|
|
"""
|
|
test_cases = [
|
|
# Common test cases
|
|
(Path("index.md"), "file", ["document"], "md"),
|
|
(Path("posts/my-post.md"), "file", ["document"], "md"),
|
|
(Path("images/gallery"), "folder", ["image"], None),
|
|
(Path("about.md"), "file", ["document"], "md"),
|
|
]
|
|
|
|
results = {
|
|
'total_tests': len(test_cases),
|
|
'matching': 0,
|
|
'differences': [],
|
|
'test_details': []
|
|
}
|
|
|
|
for content_path, file_type, categories, extension in test_cases:
|
|
old_result = old_discovery.find_template_legacy(content_path, file_type, categories, extension)
|
|
new_result = new_discovery.find_template(content_path, file_type, categories, extension)
|
|
|
|
test_detail = {
|
|
'content_path': str(content_path),
|
|
'old_result': str(old_result) if old_result else None,
|
|
'new_result': str(new_result) if new_result else None,
|
|
'matches': old_result == new_result
|
|
}
|
|
|
|
results['test_details'].append(test_detail)
|
|
|
|
if old_result == new_result:
|
|
results['matching'] += 1
|
|
else:
|
|
results['differences'].append(test_detail)
|
|
|
|
return results |