#!/usr/bin/env python3 """JustAPI docs build — WebTUI terminal static site generator. Reads markdown from ../docs_site/src/content/docs, renders each page with the WebTUI terminal template (navbar + dual sidebars + content), and writes static HTML to dist/. """ import re import shutil import html as html_mod from pathlib import Path import markdown ROOT = Path(__file__).parent CONTENT = Path(__file__).parent.parent / "docs_site/src/content/docs" DIST = ROOT / "dist" # ─── Sidebar structure: (group, [(label, path), ...]) ─── SIDEBAR = [ ("Getting Started", [ ("Overview", "/getting-started/overview/"), ("Installation", "/getting-started/installation/"), ("First Steps", "/getting-started/first-steps/"), ("CLI Scaffolder", "/getting-started/cli-scaffolder/"), ("Migrate from FastAPI", "/getting-started/migrating-from-fastapi/"), ]), ("Tutorials", [ ("Hello World", "/tutorials/hello-world/"), ("Path Parameters", "/tutorials/path-params/"), ("Query Parameters", "/tutorials/query-params/"), ("Request Body", "/tutorials/request-body/"), ("Error Handling", "/tutorials/error-handling/"), ("Dependencies", "/tutorials/dependency-injection/"), ("Middleware", "/tutorials/middleware/"), ("CORS", "/tutorials/cors/"), ("Databases", "/tutorials/database-integration/"), ("Background Tasks", "/tutorials/background-tasks/"), ("Testing", "/tutorials/testing/"), ("Static Files", "/tutorials/static-files/"), ]), ("Advanced", [ ("Zero-GIL", "/advanced/zero-gil-architecture/"), ("Rust Core", "/advanced/rust-core-deep-dive/"), ("Native Fast Path", "/advanced/native-fast-path/"), ("Streaming Output", "/advanced/streaming-output/"), ("WebSockets", "/advanced/websockets-advanced/"), ("Templates", "/advanced/templates/"), ("Performance Tuning", "/advanced/performance-tuning/"), ("Resilience", "/advanced/resilience-patterns/"), ]), ("API Reference", [ ("JustAPIApp", "/api-reference/justapiapp/"), ("Routing", "/api-reference/routing/"), ("Request", "/api-reference/request/"), ("Responses", "/api-reference/responses/"), ("Dependency Injection", "/api-reference/dependency-injection/"), ("Exceptions", "/api-reference/exceptions/"), ("Schema Validation", "/api-reference/schema-validation/"), ("WebSockets", "/api-reference/websockets/"), ("Background Tasks", "/api-reference/background-tasks/"), ("Scheduler", "/api-reference/scheduler/"), ("Database", "/api-reference/database/"), ("Testing Client", "/api-reference/testing-client/"), ("UploadFile", "/api-reference/uploadfile/"), ]), ("Deployment", [ ("Docker", "/deployment/docker/"), ("Kubernetes", "/deployment/kubernetes-helm/"), ("Cloudflare Pages", "/deployment/cloudflare-pages/"), ("Production Checklist", "/deployment/production-checklist/"), ]), ("Security", [ ("Security Policy", "/security/policy/"), ("OWASP", "/security/owasp-compliance/"), ("Secure Config", "/security/secure-configuration/"), ]), ("Observability", [ ("Metrics", "/observability/metrics-monitoring/"), ("OpenTelemetry", "/observability/opentelemetry/"), ("Structured Logging", "/observability/structured-logging/"), ("Health Checks", "/observability/health-checks/"), ]), ("Reference", [ ("CLI", "/reference/cli/"), ("Configuration", "/reference/configuration/"), ("API Stability", "/reference/api-stability/"), ("Release Notes", "/reference/release-notes/"), ("Glossary", "/reference/glossary/"), ]), ] TEMPLATE = (ROOT / "templates/base.html").read_text() def parse_frontmatter(text: str) -> tuple[dict, str]: """Extract YAML-ish frontmatter (title/description) and the body.""" meta: dict = {} if text.startswith("---"): end = text.find("---", 3) if end != -1: raw = text[3:end] for line in raw.strip().splitlines(): if ":" in line: k, v = line.split(":", 1) v = v.strip().strip('"').strip("'") if v.startswith("[") or v.startswith("{"): continue # skip list/dict meta meta[k.strip()] = v text = text[end + 3 :] return meta, text def build_sidebar(active_path: str) -> str: parts = [] for group, items in SIDEBAR: parts.append(f'