From 57e0d0c341e8f0de29b800c95a4aaa5b8b383373 Mon Sep 17 00:00:00 2001 From: giles Date: Wed, 4 Mar 2026 18:29:14 +0000 Subject: [PATCH] Fix defmacro expansion in _aser: check for macros before serializing ~components The ~component check in _aser immediately serialized all names starting with ~ as unexpanded component calls. This meant defmacro definitions like ~root-header-auto were sent to the client unexpanded, causing "Undefined symbol: root-header-ctx" errors since IO primitives only exist server-side. Now checks env for Macro instances first. Co-Authored-By: Claude Opus 4.6 --- shared/sx/async_eval.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shared/sx/async_eval.py b/shared/sx/async_eval.py index 86856f6..9c25fbf 100644 --- a/shared/sx/async_eval.py +++ b/shared/sx/async_eval.py @@ -1127,8 +1127,12 @@ async def _aser(expr: Any, env: dict[str, Any], ctx: RequestContext) -> Any: if name.startswith("html:"): return await _aser_call(name[5:], expr[1:], env, ctx) - # Component call — serialize (don't expand) + # Component call — expand macros, serialize regular components if name.startswith("~"): + val = env.get(name) + if isinstance(val, Macro): + expanded = _expand_macro(val, expr[1:], env) + return await _aser(expanded, env, ctx) return await _aser_call(name, expr[1:], env, ctx) # Serialize-mode special/HO forms (checked BEFORE HTML_TAGS