"""Page helper registration for sx docs. All helpers return data values (dicts, lists) — no sx_call(), no SxExpr. Markup composition lives entirely in .sx files. """ from __future__ import annotations def _register_sx_helpers() -> None: """Register Python data helpers as page helpers.""" from shared.sx.pages import register_page_helpers from content.highlight import highlight as _highlight register_page_helpers("sx", { "highlight": _highlight, "primitives-data": _primitives_data, "special-forms-data": _special_forms_data, "reference-data": _reference_data, "attr-detail-data": _attr_detail_data, "header-detail-data": _header_detail_data, "event-detail-data": _event_detail_data, "read-spec-file": _read_spec_file, "bootstrapper-data": _bootstrapper_data, }) def _primitives_data() -> dict: """Return the PRIMITIVES dict for the primitives docs page.""" from content.pages import PRIMITIVES return PRIMITIVES def _special_forms_data() -> dict: """Parse special-forms.sx and return categorized form data. Returns a dict of category → list of form dicts, each with: name, syntax, doc, tail_position, example """ import os from shared.sx.parser import parse_all, serialize from shared.sx.types import Symbol, Keyword spec_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "..", "..", "shared", "sx", "ref", "special-forms.sx", ) with open(spec_path) as f: exprs = parse_all(f.read()) # Categories inferred from comment sections in the file. # We assign forms to categories based on their order in the spec. categories: dict[str, list[dict]] = {} current_category = "Other" # Map form names to categories category_map = { "if": "Control Flow", "when": "Control Flow", "cond": "Control Flow", "case": "Control Flow", "and": "Control Flow", "or": "Control Flow", "let": "Binding", "let*": "Binding", "letrec": "Binding", "define": "Binding", "set!": "Binding", "lambda": "Functions & Components", "fn": "Functions & Components", "defcomp": "Functions & Components", "defmacro": "Functions & Components", "begin": "Sequencing & Threading", "do": "Sequencing & Threading", "->": "Sequencing & Threading", "quote": "Quoting", "quasiquote": "Quoting", "reset": "Continuations", "shift": "Continuations", "dynamic-wind": "Guards", "map": "Higher-Order Forms", "map-indexed": "Higher-Order Forms", "filter": "Higher-Order Forms", "reduce": "Higher-Order Forms", "some": "Higher-Order Forms", "every?": "Higher-Order Forms", "for-each": "Higher-Order Forms", "defstyle": "Domain Definitions", "defkeyframes": "Domain Definitions", "defhandler": "Domain Definitions", "defpage": "Domain Definitions", "defquery": "Domain Definitions", "defaction": "Domain Definitions", } for expr in exprs: if not isinstance(expr, list) or len(expr) < 2: continue head = expr[0] if not isinstance(head, Symbol) or head.name != "define-special-form": continue name = expr[1] # Extract keyword args kwargs: dict[str, str] = {} i = 2 while i < len(expr) - 1: if isinstance(expr[i], Keyword): key = expr[i].name val = expr[i + 1] if isinstance(val, list): # For :syntax, avoid quote sugar (quasiquote → `x) items = [serialize(item) for item in val] kwargs[key] = "(" + " ".join(items) + ")" else: kwargs[key] = str(val) i += 2 else: i += 1 category = category_map.get(name, "Other") if category not in categories: categories[category] = [] categories[category].append({ "name": name, "syntax": kwargs.get("syntax", ""), "doc": kwargs.get("doc", ""), "tail-position": kwargs.get("tail-position", ""), "example": kwargs.get("example", ""), }) return categories def _reference_data(slug: str) -> dict: """Return reference table data for a given slug. Returns a dict whose keys become SX env bindings: - attributes: req-attrs, beh-attrs, uniq-attrs - headers: req-headers, resp-headers - events: events-list - js-api: js-api-list """ from content.pages import ( REQUEST_ATTRS, BEHAVIOR_ATTRS, SX_UNIQUE_ATTRS, REQUEST_HEADERS, RESPONSE_HEADERS, EVENTS, JS_API, ATTR_DETAILS, HEADER_DETAILS, ) if slug == "attributes": return { "req-attrs": [ {"name": a, "desc": d, "exists": e, "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None} for a, d, e in REQUEST_ATTRS ], "beh-attrs": [ {"name": a, "desc": d, "exists": e, "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None} for a, d, e in BEHAVIOR_ATTRS ], "uniq-attrs": [ {"name": a, "desc": d, "exists": e, "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None} for a, d, e in SX_UNIQUE_ATTRS ], } elif slug == "headers": return { "req-headers": [ {"name": n, "value": v, "desc": d, "href": f"/reference/headers/{n}" if n in HEADER_DETAILS else None} for n, v, d in REQUEST_HEADERS ], "resp-headers": [ {"name": n, "value": v, "desc": d, "href": f"/reference/headers/{n}" if n in HEADER_DETAILS else None} for n, v, d in RESPONSE_HEADERS ], } elif slug == "events": from content.pages import EVENT_DETAILS return { "events-list": [ {"name": n, "desc": d, "href": f"/reference/events/{n}" if n in EVENT_DETAILS else None} for n, d in EVENTS ], } elif slug == "js-api": return { "js-api-list": [ {"name": n, "desc": d} for n, d in JS_API ], } # Default — return attrs data for fallback return { "req-attrs": [ {"name": a, "desc": d, "exists": e, "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None} for a, d, e in REQUEST_ATTRS ], "beh-attrs": [ {"name": a, "desc": d, "exists": e, "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None} for a, d, e in BEHAVIOR_ATTRS ], "uniq-attrs": [ {"name": a, "desc": d, "exists": e, "href": f"/reference/attributes/{a}" if e and a in ATTR_DETAILS else None} for a, d, e in SX_UNIQUE_ATTRS ], } def _read_spec_file(filename: str) -> str: """Read a spec .sx file from the ref directory. Pure I/O — metadata lives in .sx.""" import os ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref") if not os.path.isdir(ref_dir): ref_dir = "/app/shared/sx/ref" filepath = os.path.join(ref_dir, filename) try: with open(filepath, encoding="utf-8") as f: return f.read() except FileNotFoundError: return ";; spec file not found" def _bootstrapper_data(target: str) -> dict: """Return bootstrapper source and generated output for a target. Returns a dict whose keys become SX env bindings: - bootstrapper-source: the Python bootstrapper source code - bootstrapped-output: the generated JavaScript - bootstrapper-not-found: truthy if target unknown """ import os if target not in ("javascript", "python"): return {"bootstrapper-not-found": True} ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref") if not os.path.isdir(ref_dir): ref_dir = "/app/shared/sx/ref" if target == "javascript": # Read bootstrapper source bs_path = os.path.join(ref_dir, "bootstrap_js.py") try: with open(bs_path, encoding="utf-8") as f: bootstrapper_source = f.read() except FileNotFoundError: bootstrapper_source = "# bootstrapper source not found" # Run the bootstrap to generate JS from shared.sx.ref.bootstrap_js import compile_ref_to_js try: bootstrapped_output = compile_ref_to_js( adapters=["dom", "engine", "orchestration", "boot", "cssx"] ) except Exception as e: bootstrapped_output = f"// bootstrap error: {e}" elif target == "python": bs_path = os.path.join(ref_dir, "bootstrap_py.py") try: with open(bs_path, encoding="utf-8") as f: bootstrapper_source = f.read() except FileNotFoundError: bootstrapper_source = "# bootstrapper source not found" from shared.sx.ref.bootstrap_py import compile_ref_to_py try: bootstrapped_output = compile_ref_to_py() except Exception as e: bootstrapped_output = f"# bootstrap error: {e}" return { "bootstrapper-not-found": None, "bootstrapper-source": bootstrapper_source, "bootstrapped-output": bootstrapped_output, } def _attr_detail_data(slug: str) -> dict: """Return attribute detail data for a specific attribute slug. Returns a dict whose keys become SX env bindings: - attr-title, attr-description, attr-example, attr-handler - attr-demo (component call or None) - attr-wire-id (wire placeholder id or None) - attr-not-found (truthy if not found) """ from content.pages import ATTR_DETAILS from shared.sx.helpers import sx_call detail = ATTR_DETAILS.get(slug) if not detail: return {"attr-not-found": True} demo_name = detail.get("demo") wire_id = None if "handler" in detail: wire_id = f"ref-wire-{slug.replace(':', '-').replace('*', 'star')}" return { "attr-not-found": None, "attr-title": slug, "attr-description": detail["description"], "attr-example": detail["example"], "attr-handler": detail.get("handler"), "attr-demo": sx_call(demo_name) if demo_name else None, "attr-wire-id": wire_id, } def _header_detail_data(slug: str) -> dict: """Return header detail data for a specific header slug.""" from content.pages import HEADER_DETAILS from shared.sx.helpers import sx_call detail = HEADER_DETAILS.get(slug) if not detail: return {"header-not-found": True} demo_name = detail.get("demo") return { "header-not-found": None, "header-title": slug, "header-direction": detail["direction"], "header-description": detail["description"], "header-example": detail.get("example"), "header-demo": sx_call(demo_name) if demo_name else None, } def _event_detail_data(slug: str) -> dict: """Return event detail data for a specific event slug.""" from content.pages import EVENT_DETAILS from shared.sx.helpers import sx_call detail = EVENT_DETAILS.get(slug) if not detail: return {"event-not-found": True} demo_name = detail.get("demo") return { "event-not-found": None, "event-title": slug, "event-description": detail["description"], "event-example": detail.get("example"), "event-demo": sx_call(demo_name) if demo_name else None, }