#!/usr/bin/env python3 """Resolves each project's _templates/*.md against its _data.json and overwrites the tracked *.md files with the result. Why this exists: the legal documents repeat the same provider identity, hosting entity, and sub-processor names/countries across several files — each document phrases its surrounding table differently, so it's the *values*, not whole blocks, that repeat. Before this script, changing e.g. the company address meant editing every document by hand and risking them drifting apart. The templates are the edit source; the tracked *.md files are a build output, exactly like dist/legal-manifest.json is a build output of build-manifest.py. Both are committed to git, so build-manifest.py's content_hash/version (which hash the tracked *.md, not the template) keep meaning exactly what they did before this script existed — and downstream consumers that read the tracked H2W-Ticketing/*.md directly are unaffected, since they still see fully resolved text, never a placeholder. Placeholder syntax: {{ dotted.path }}, resolved against _data.json. Missing data: a value of "-", "—" or "" in _data.json means "nincs ilyen adat" (pl. egyéni vállalkozónak nincs cégjegyzékszáma). Such a value is never printed: - a markdown table row ("| ... |") containing such a token is dropped entirely; - an optional inline segment [[ ... ]] containing such a token is dropped (otherwise only its brackets are removed), e.g. "[[, nyilvántartási szám: {{ provider.registration_number }}]]". Deliberately NOT used for numeric periods (30 nap, 8 nap, 99%, ...) that happen to repeat — those repeat by coincidence of value, not by shared identity, and collapsing them would risk an edit to one clause silently changing an unrelated one. Usage: python3 scripts/render-templates.py # resolve and overwrite python3 scripts/render-templates.py --check # exit 1 on drift, write nothing """ import json import re import sys from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent TOKEN_RE = re.compile(r"\{\{\s*([\w.]+)\s*\}\}") def resolve_token(data: dict, dotted_path: str) -> str: value = data for part in dotted_path.split("."): value = value[part] return value MISSING_VALUES = {"", "-", "—"} OPTIONAL_RE = re.compile(r"\[\[(.*?)\]\]", re.DOTALL) def _has_missing(text: str, data: dict) -> bool: return any(str(resolve_token(data, m.group(1))).strip() in MISSING_VALUES for m in TOKEN_RE.finditer(text)) def render(template: str, data: dict) -> str: # 1) opcionális szakaszok: hiányzó adattal együtt kimaradnak template = OPTIONAL_RE.sub(lambda m: "" if _has_missing(m.group(1), data) else m.group(1), template) # 2) táblázatsor hiányzó adattal: az egész sor kimarad lines = [ line for line in template.split("\n") if not (line.lstrip().startswith("|") and _has_missing(line, data)) ] return TOKEN_RE.sub(lambda m: resolve_token(data, m.group(1)), "\n".join(lines)) def main() -> None: check_only = "--check" in sys.argv drift = False for project_dir in sorted(REPO_ROOT.iterdir()): templates_dir = project_dir / "_templates" if not templates_dir.is_dir(): continue data_path = project_dir / "_data.json" data = json.loads(data_path.read_text(encoding="utf-8")) for template_path in sorted(templates_dir.glob("*.md")): target_path = project_dir / template_path.name resolved = render(template_path.read_text(encoding="utf-8"), data) if check_only: current = target_path.read_text(encoding="utf-8") if target_path.exists() else None if current != resolved: print(f"ELTÉRÉS: {target_path.relative_to(REPO_ROOT)}") drift = True continue target_path.write_text(resolved, encoding="utf-8") print(f"Feloldva: {target_path.relative_to(REPO_ROOT)}") if check_only and drift: print("A sablonokból generált tartalom eltér a commitolt fájloktól — futtasd: python3 scripts/render-templates.py") sys.exit(1) if __name__ == "__main__": main()