#!/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/. The sidebar is auto-discovered from the content directory, so every page is always listed — nothing hardcoded. """ 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" # Section order + display names for top-level groups. SECTION_ORDER = [ "getting-started", "tutorials", "advanced", "how-to", "api-reference", "deployment", "security", "observability", "inference", "resources", "reference", "contributing", "examples", ] SECTION_LABELS = { "getting-started": "Getting Started", "tutorials": "Tutorials", "advanced": "Advanced", "how-to": "How-To", "api-reference": "API Reference", "deployment": "Deployment", "security": "Security", "observability": "Observability", "inference": "Inference", "resources": "Resources", "reference": "Reference", "contributing": "Contributing", "examples": "Examples", } SKIP_STEMS = {"index"} TEMPLATE = (ROOT / "templates/base.html").read_text() def humanize(name: str) -> str: """'path-params-numeric-validations' -> 'Path Params Numeric Validations'.""" return name.replace("-", " ").replace("_", " ").title().replace(" Api ", " API ") def frontmatter_title(text: str, fallback: str) -> str: """Read the `title:` from YAML frontmatter, else humanized filename.""" if text.startswith("---"): end = text.find("---", 3) if end != -1: for line in text[3:end].splitlines(): if line.startswith("title:"): t = line.split(":", 1)[1].strip().strip('"').strip("'") if t: return t return fallback def discover_pages() -> list[tuple[str, list[tuple[str, str]]]]: """Scan CONTENT -> [(group_label, [(page_label, url_path)])] in order.""" groups: dict[str, list[tuple[str, str]]] = {} for md in sorted(CONTENT.rglob("*.md*")): rel = md.relative_to(CONTENT) parts = rel.parts if len(parts) < 2: continue section = parts[0] stem = rel.stem if len(parts) == 2 and stem in SKIP_STEMS: continue # section index pages (how-to/index.md) ARE built label = frontmatter_title(md.read_text(errors="ignore"), humanize(stem)) url = "/" + str(rel.with_suffix("")).replace(chr(92), "/") + "/" groups.setdefault(section, []).append((label, url)) ordered = [] for sec in SECTION_ORDER: if sec in groups: ordered.append((SECTION_LABELS.get(sec, humanize(sec)), groups[sec])) for sec in groups: if sec not in SECTION_ORDER: ordered.append((SECTION_LABELS.get(sec, humanize(sec)), groups[sec])) return ordered 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 meta[k.strip()] = v text = text[end + 3 :] return meta, text def build_sidebar(active_path: str) -> str: """Render the sidebar: group headings + links from auto-discovery.""" parts = [] for group, items in discover_pages(): parts.append(f'