Migrate all apps to defpage declarative page routes
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m41s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m41s
Replace Python GET page handlers with declarative defpage definitions in .sx files across all 8 apps (sx docs, orders, account, market, cart, federation, events, blog). Each app now has sxc/pages/ with setup functions, layout registrations, page helpers, and .sx defpage declarations. Core infrastructure: add g I/O primitive, PageDef support for auth/layout/ data/content/filter/aside/menu slots, post_author auth level, and custom layout registration. Remove ~1400 lines of render_*_page/render_*_oob boilerplate. Update all endpoint references in routes, sx_components, and templates to defpage_* naming. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,7 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from .types import Component, HandlerDef, Keyword, Lambda, Macro, NIL, RelationDef, Symbol
|
||||
from .types import Component, HandlerDef, Keyword, Lambda, Macro, NIL, PageDef, RelationDef, Symbol
|
||||
from .primitives import _PRIMITIVES
|
||||
|
||||
|
||||
@@ -635,6 +635,85 @@ def _sf_defrelation(expr: list, env: dict) -> RelationDef:
|
||||
return defn
|
||||
|
||||
|
||||
def _sf_defpage(expr: list, env: dict) -> PageDef:
|
||||
"""``(defpage name :path "/..." :auth :public :content expr ...)``
|
||||
|
||||
Parses keyword args from the expression. All slot values are stored
|
||||
as unevaluated AST — they are resolved at request time by execute_page().
|
||||
"""
|
||||
if len(expr) < 2:
|
||||
raise EvalError("defpage requires a name")
|
||||
name_sym = expr[1]
|
||||
if not isinstance(name_sym, Symbol):
|
||||
raise EvalError(f"defpage name must be symbol, got {type(name_sym).__name__}")
|
||||
|
||||
# Parse keyword args — values are NOT evaluated (stored as AST)
|
||||
slots: dict[str, Any] = {}
|
||||
i = 2
|
||||
while i < len(expr):
|
||||
key = expr[i]
|
||||
if isinstance(key, Keyword) and i + 1 < len(expr):
|
||||
slots[key.name] = expr[i + 1]
|
||||
i += 2
|
||||
else:
|
||||
i += 1
|
||||
|
||||
# Required fields
|
||||
path = slots.get("path")
|
||||
if path is None:
|
||||
raise EvalError(f"defpage {name_sym.name} missing required :path")
|
||||
if not isinstance(path, str):
|
||||
raise EvalError(f"defpage {name_sym.name} :path must be a string")
|
||||
|
||||
auth_val = slots.get("auth", "public")
|
||||
if isinstance(auth_val, Keyword):
|
||||
auth: str | list = auth_val.name
|
||||
elif isinstance(auth_val, list):
|
||||
# (:rights "a" "b") → ["rights", "a", "b"]
|
||||
auth = []
|
||||
for item in auth_val:
|
||||
if isinstance(item, Keyword):
|
||||
auth.append(item.name)
|
||||
elif isinstance(item, str):
|
||||
auth.append(item)
|
||||
else:
|
||||
auth.append(_eval(item, env))
|
||||
else:
|
||||
auth = str(auth_val) if auth_val else "public"
|
||||
|
||||
# Layout — keep unevaluated
|
||||
layout = slots.get("layout")
|
||||
if isinstance(layout, Keyword):
|
||||
layout = layout.name
|
||||
elif isinstance(layout, list):
|
||||
# Keep as unevaluated list for execute_page to resolve at request time
|
||||
pass
|
||||
|
||||
# Cache — evaluate if present (it's a static config dict)
|
||||
cache_val = slots.get("cache")
|
||||
cache = None
|
||||
if cache_val is not None:
|
||||
cache_result = _eval(cache_val, env)
|
||||
if isinstance(cache_result, dict):
|
||||
cache = cache_result
|
||||
|
||||
page = PageDef(
|
||||
name=name_sym.name,
|
||||
path=path,
|
||||
auth=auth,
|
||||
layout=layout,
|
||||
cache=cache,
|
||||
data_expr=slots.get("data"),
|
||||
content_expr=slots.get("content"),
|
||||
filter_expr=slots.get("filter"),
|
||||
aside_expr=slots.get("aside"),
|
||||
menu_expr=slots.get("menu"),
|
||||
closure=dict(env),
|
||||
)
|
||||
env[f"page:{name_sym.name}"] = page
|
||||
return page
|
||||
|
||||
|
||||
_SPECIAL_FORMS: dict[str, Any] = {
|
||||
"if": _sf_if,
|
||||
"when": _sf_when,
|
||||
@@ -657,6 +736,7 @@ _SPECIAL_FORMS: dict[str, Any] = {
|
||||
"defmacro": _sf_defmacro,
|
||||
"quasiquote": _sf_quasiquote,
|
||||
"defhandler": _sf_defhandler,
|
||||
"defpage": _sf_defpage,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user