Fix renderComponentDOM: route render-only forms through renderDOM
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m19s

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 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 13:45:43 +00:00
parent 2b41aaa6ce
commit 0a5562243b

View File

@@ -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]);