Fix aser server-affinity expansion: keyword values, OOB wrapper, page helpers
Three bugs in aser-expand-component (adapter-sx.sx):
- Keyword values were eval'd (eval-expr can't handle <>, HTML tags);
now asered, matching the aser's rendering capabilities
- Missing default nil binding for unset &key params (caused
"Undefined symbol" errors for optional params like header-rows)
- aserCall string-quoted keyword values that were already serialized
SX — now inlines values starting with "(" directly
Server-affinity annotations for layout/nav shells:
- ~shared:layout/app-body, ~shared:layout/oob-sx — page structure
- ~layouts/nav-sibling-row, ~layouts/nav-children — server-side data
- ~layouts/doc already had :affinity :server
- ~cssx/flush marked :affinity :client (browser-only state)
Navigation fix: restore oob_page_sx wrapper for HTMX responses
so #main-panel section exists for sx-select/sx-swap targeting.
OCaml bridge: lazy page helper injection into kernel via IO proxy
(define name (fn (...) (helper "name" ...))) — enables aser_slot
to evaluate highlight/component-source etc. via coroutine bridge.
Playwright tests: added pageerror listener to test_no_console_errors,
new test_navigate_from_home_to_geography for HTMX nav regression.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// =========================================================================
|
||||
|
||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||
var SX_VERSION = "2026-03-18T20:14:01Z";
|
||||
var SX_VERSION = "2026-03-19T11:12:01Z";
|
||||
|
||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||
@@ -1460,6 +1460,9 @@ PRIMITIVES["cek-step"] = cekStep;
|
||||
var name = symbolName(expr);
|
||||
return (function() {
|
||||
var val = (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : error((String("Undefined symbol: ") + String(name))))))));
|
||||
if (isSxTruthy((isSxTruthy(isNil(val)) && startsWith(name, "~")))) {
|
||||
debugLog("Component not found:", name);
|
||||
}
|
||||
return makeCekValue(val, env, kont);
|
||||
})();
|
||||
})(); if (_m == "keyword") return makeCekValue(keywordName(expr), env, kont); if (_m == "dict") return (function() {
|
||||
@@ -2673,14 +2676,15 @@ PRIMITIVES["aser"] = aser;
|
||||
var args = rest(expr);
|
||||
return (isSxTruthy(!isSxTruthy((typeOf(head) == "symbol"))) ? map(function(x) { return aser(x, env); }, expr) : (function() {
|
||||
var name = symbolName(head);
|
||||
return (isSxTruthy((name == "<>")) ? aserFragment(args, env) : (isSxTruthy(startsWith(name, "~")) ? (function() {
|
||||
return (isSxTruthy((name == "<>")) ? aserFragment(args, env) : (isSxTruthy((name == "raw!")) ? aserCall("raw!", args, env) : (isSxTruthy(startsWith(name, "~")) ? (function() {
|
||||
var comp = (isSxTruthy(envHas(env, name)) ? envGet(env, name) : NIL);
|
||||
return (isSxTruthy((isSxTruthy(comp) && isSxTruthy(isComponent(comp)) && (componentAffinity(comp) == "server"))) ? aserExpandComponent(comp, args, env) : aserCall(name, args, env));
|
||||
var expandAll = (isSxTruthy(envHas(env, "expand-components?")) ? expandComponents_p() : false);
|
||||
return (isSxTruthy((isSxTruthy(comp) && isMacro(comp))) ? aser(expandMacro(comp, args, env), env) : (isSxTruthy((isSxTruthy(comp) && isSxTruthy(isComponent(comp)) && isSxTruthy(sxOr(expandAll, (componentAffinity(comp) == "server"))) && !isSxTruthy((componentAffinity(comp) == "client")))) ? aserExpandComponent(comp, args, env) : aserCall(name, args, env)));
|
||||
})() : (isSxTruthy((name == "lake")) ? aserCall(name, args, env) : (isSxTruthy((name == "marsh")) ? aserCall(name, args, env) : (isSxTruthy(contains(HTML_TAGS, name)) ? aserCall(name, args, env) : (isSxTruthy(sxOr(isSpecialForm(name), isHoForm(name))) ? aserSpecial(name, expr, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? aser(expandMacro(envGet(env, name), args, env), env) : (function() {
|
||||
var f = trampoline(evalExpr(head, env));
|
||||
var evaledArgs = map(function(a) { return trampoline(evalExpr(a, env)); }, args);
|
||||
return (isSxTruthy((isSxTruthy(isCallable(f)) && isSxTruthy(!isSxTruthy(isLambda(f))) && isSxTruthy(!isSxTruthy(isComponent(f))) && !isSxTruthy(isIsland(f)))) ? apply(f, evaledArgs) : (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, evaledArgs, env)) : (isSxTruthy(isComponent(f)) ? aserCall((String("~") + String(componentName(f))), args, env) : (isSxTruthy(isIsland(f)) ? aserCall((String("~") + String(componentName(f))), args, env) : error((String("Not callable: ") + String(inspect(f))))))));
|
||||
})())))))));
|
||||
})()))))))));
|
||||
})());
|
||||
})(); };
|
||||
PRIMITIVES["aser-list"] = aserList;
|
||||
@@ -2707,7 +2711,7 @@ PRIMITIVES["aser-fragment"] = aserFragment;
|
||||
var val = aser(nth(args, (i + 1)), env);
|
||||
if (isSxTruthy(!isSxTruthy(isNil(val)))) {
|
||||
attrParts.push((String(":") + String(keywordName(arg))));
|
||||
attrParts.push(serialize(val));
|
||||
(isSxTruthy((isSxTruthy((typeOf(val) == "string")) && isSxTruthy((stringLength(val) > 0)) && startsWith(val, "("))) ? append_b(attrParts, val) : append_b(attrParts, serialize(val)));
|
||||
}
|
||||
skip = true;
|
||||
return (i = (i + 1));
|
||||
@@ -2738,7 +2742,8 @@ PRIMITIVES["aser-call"] = aserCall;
|
||||
var i = 0;
|
||||
var skip = false;
|
||||
var children = [];
|
||||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var arg = _c[_i]; (isSxTruthy(skip) ? ((skip = false), (i = (i + 1))) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((i + 1) < len(args)))) ? (envBind(local, keywordName(arg), trampoline(evalExpr(nth(args, (i + 1)), env))), (skip = true), (i = (i + 1))) : (append_b(children, arg), (i = (i + 1))))); } }
|
||||
{ var _c = params; for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envBind(local, p, NIL); } }
|
||||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var arg = _c[_i]; (isSxTruthy(skip) ? ((skip = false), (i = (i + 1))) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((i + 1) < len(args)))) ? (envBind(local, keywordName(arg), aser(nth(args, (i + 1)), env)), (skip = true), (i = (i + 1))) : (append_b(children, arg), (i = (i + 1))))); } }
|
||||
if (isSxTruthy(componentHasChildren(comp))) {
|
||||
(function() {
|
||||
var aseredChildren = map(function(c) { return aser(c, env); }, children);
|
||||
|
||||
Reference in New Issue
Block a user