From 0a5562243b9782545966e4d3582808c6633e591f Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 1 Mar 2026 13:45:43 +0000 Subject: [PATCH] Fix renderComponentDOM: route render-only forms through renderDOM The previous fix eagerly evaluated all kwarg expressions via sxEval, which broke render-only forms (<>, raw!, HTML tags, ~components) that only exist in the render pipeline. Now detect render expressions by checking if the head symbol is an HTML/SVG tag, <>, raw!, or ~component, and route those through renderDOM while data expressions still go through sxEval for correct scope resolution. Co-Authored-By: Claude Opus 4.6 --- shared/static/scripts/sx.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/shared/static/scripts/sx.js b/shared/static/scripts/sx.js index 6b77fd6..83fa866 100644 --- a/shared/static/scripts/sx.js +++ b/shared/static/scripts/sx.js @@ -808,17 +808,32 @@ return renderDOM(fn.body, local); } + /** True when the array expr is a render-only form (HTML tag, <>, raw!, ~comp). */ + function _isRenderExpr(v) { + if (!Array.isArray(v) || !v.length) return false; + var h = v[0]; + if (!isSym(h)) return false; + var n = h.name; + return !!(HTML_TAGS[n] || SVG_TAGS[n] || n === "<>" || n === "raw!" || n.charAt(0) === "~"); + } + function renderComponentDOM(comp, args, env) { var kwargs = {}, children = []; var i = 0; while (i < args.length) { if (isKw(args[i]) && i + 1 < args.length) { - // Evaluate kwarg values eagerly so expressions like (get t "src") - // resolve in the caller's env (where lambda params are bound). + // Evaluate kwarg values eagerly in the caller's env so expressions + // like (get t "src") resolve while lambda params are still bound. + // Render-only forms (HTML tags, <>, ~comp) go through renderDOM instead. var v = args[i + 1]; - kwargs[args[i].name] = (typeof v === "string" || typeof v === "number" || - typeof v === "boolean" || isNil(v)) - ? v : sxEval(v, env); + if (typeof v === "string" || typeof v === "number" || + typeof v === "boolean" || isNil(v)) { + kwargs[args[i].name] = v; + } else if (_isRenderExpr(v)) { + kwargs[args[i].name] = renderDOM(v, env); + } else { + kwargs[args[i].name] = sxEval(v, env); + } i += 2; } else { children.push(args[i]);