All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m54s
Parses special-forms.sx spec into categorized form cards with syntax, description, tail-position info, and highlighted examples. Follows the same pattern as the Primitives page: Python helper returns structured data, .sx components render it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
337 lines
12 KiB
Python
337 lines
12 KiB
Python
"""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,
|
|
}
|