Files
rose-ash/sx/sxc/pages/helpers.py
giles 04366990ec
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m33s
Enforce SX boundary contract via boundary.sx spec + runtime validation
Add boundary.sx declaring all 34 I/O primitives, 32 page helpers, and 9
allowed boundary types. Runtime validation in boundary.py checks every
registration against the spec — undeclared primitives/helpers crash at
startup with SX_BOUNDARY_STRICT=1 (now set in both dev and prod).

Key changes:
- Move 5 I/O-in-disguise primitives (app-url, asset-url, config,
  jinja-global, relations-from) from primitives.py to primitives_io.py
- Remove duplicate url-for/route-prefix from primitives.py (already in IO)
- Fix parse-datetime to return ISO string instead of raw datetime
- Add datetime→isoformat conversion in _convert_result at the edge
- Wrap page helper return values with boundary type validation
- Replace all SxExpr(f"...") patterns with sx_call() or _sx_fragment()
- Add assert declaration to primitives.sx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:50:02 +00:00

253 lines
8.5 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,
"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 _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,
}