Files
H2W-Public-Legal/scripts/render-templates.py
2026-10-04 22:01:14 +02:00

104 lines
4.2 KiB
Python

#!/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()