"""Disk cache for macro expansion results — keyed by content hash.""" from __future__ import annotations import hashlib import json from pathlib import Path CACHE_DIR = Path("data/cache/expansions") class ExpansionCache: def __init__(self, cache_dir: Path | None = None): self.cache_dir = cache_dir or CACHE_DIR self.cache_dir.mkdir(parents=True, exist_ok=True) def _key(self, library: str, macro_name: str, call_form: str) -> str: content = f"{library}:{macro_name}:{call_form}" return hashlib.sha256(content.encode()).hexdigest()[:16] def get(self, library: str, macro_name: str, call_form: str) -> dict | None: key = self._key(library, macro_name, call_form) path = self.cache_dir / f"{key}.json" if path.exists(): try: return json.loads(path.read_text()) except json.JSONDecodeError: return None return None def put(self, library: str, macro_name: str, call_form: str, result: dict) -> None: key = self._key(library, macro_name, call_form) path = self.cache_dir / f"{key}.json" path.write_text(json.dumps(result)) def invalidate_library(self, library: str) -> None: prefix = hashlib.sha256(f"{library}:".encode()).hexdigest()[:8] for p in self.cache_dir.glob(f"{prefix}*.json"): p.unlink(missing_ok=True)