pahvalentines/documentation/build_pdf.py
michael 7288d854c8 docs: add PDF version of architecture doc with rendered Mermaid diagrams
Pipeline: Mermaid CLI (mmdc) renders diagrams directly to PDF via
Puppeteer, pdfcrop trims whitespace, pandoc + xelatex produces the
final 20-page document with vector diagrams, syntax-highlighted code,
styled headers/footers, and table of contents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 09:57:16 -06:00

65 lines
1.7 KiB
Python

#!/usr/bin/env python3
"""Extract Mermaid diagrams from markdown, render to SVG, produce PDF-ready markdown."""
import re
import subprocess
import sys
from pathlib import Path
DOC_DIR = Path(__file__).parent
SRC = DOC_DIR / "architecture.md"
DIAGRAMS_DIR = DOC_DIR / "diagrams"
OUTPUT_MD = DOC_DIR / "architecture_pdf.md"
DIAGRAMS_DIR.mkdir(exist_ok=True)
# Mermaid rendering config for clean SVGs
MMDC_CONFIG = DOC_DIR / "mermaid_config.json"
content = SRC.read_text()
# Find all mermaid code blocks
pattern = re.compile(r"```mermaid\n(.*?)```", re.DOTALL)
matches = list(pattern.finditer(content))
print(f"Found {len(matches)} Mermaid diagrams")
for i, match in enumerate(matches, 1):
mermaid_code = match.group(1).strip()
mmd_file = DIAGRAMS_DIR / f"diagram_{i}.mmd"
svg_file = DIAGRAMS_DIR / f"diagram_{i}.svg"
mmd_file.write_text(mermaid_code)
print(f"Rendering diagram {i}...")
result = subprocess.run(
[
"mmdc",
"-i", str(mmd_file),
"-o", str(svg_file),
"-t", "neutral",
"-b", "transparent",
"-c", str(MMDC_CONFIG),
],
capture_output=True,
text=True,
)
if result.returncode != 0:
print(f" ERROR: {result.stderr}")
sys.exit(1)
print(f" -> {svg_file.name} ({svg_file.stat().st_size} bytes)")
# Replace mermaid blocks with image references
def replace_mermaid(match):
replace_mermaid.counter += 1
n = replace_mermaid.counter
return f"![](diagrams/diagram_{n}.svg)"
replace_mermaid.counter = 0
output = pattern.sub(replace_mermaid, content)
OUTPUT_MD.write_text(output)
print(f"\nWrote {OUTPUT_MD.name} with {replace_mermaid.counter} diagram references")