@barefootjs/vite 0.33.6 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +412 -264
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -10,6 +10,38 @@ import ts10 from "typescript";
10
10
 
11
11
  // ../jsx/src/expression-parser.ts
12
12
  import ts from "typescript";
13
+
14
+ // ../jsx/src/lowering-registry.ts
15
+ var plugins = [];
16
+ function registerLoweringPlugin(plugin) {
17
+ const existing = plugins.findIndex((p) => p.name === plugin.name);
18
+ if (existing >= 0)
19
+ plugins[existing] = plugin;
20
+ else
21
+ plugins.push(plugin);
22
+ }
23
+ function prepareLoweringMatchers(metadata) {
24
+ const matchers = [];
25
+ for (const plugin of plugins) {
26
+ const matcher = plugin.prepare(metadata);
27
+ if (matcher)
28
+ matchers.push(matcher);
29
+ }
30
+ return matchers;
31
+ }
32
+ function loweringNodeChildren(node) {
33
+ if (node.kind === "helper-call")
34
+ return [...node.args];
35
+ const children = [node.base];
36
+ for (const t of node.triples) {
37
+ if (t.guard)
38
+ children.push(t.guard);
39
+ children.push(t.value);
40
+ }
41
+ return children;
42
+ }
43
+
44
+ // ../jsx/src/expression-parser.ts
13
45
  var UNSUPPORTED_METHODS = new Set([
14
46
  "filter",
15
47
  "map",
@@ -183,7 +215,7 @@ function convertNode(node, raw) {
183
215
  }
184
216
  if (n === undefined || Number.isNaN(n)) {
185
217
  const parsedDepth = convertNode(depthNode, raw);
186
- if (checkSupport(parsedDepth, "rendered").supported) {
218
+ if (checkSupport(parsedDepth, "rendered", []).supported) {
187
219
  depthExpr = parsedDepth;
188
220
  flatDepth = 1;
189
221
  } else {
@@ -961,13 +993,13 @@ function getUnaryOperatorString(op) {
961
993
  return "unknown";
962
994
  }
963
995
  }
964
- function isSupported(expr) {
965
- return checkSupport(expr, "rendered");
996
+ function isSupported(expr, opts) {
997
+ return checkSupport(expr, "rendered", opts?.loweringMatchers ?? []);
966
998
  }
967
- function isSupportedValue(expr) {
968
- return checkSupport(expr, "value");
999
+ function isSupportedValue(expr, opts) {
1000
+ return checkSupport(expr, "value", opts?.loweringMatchers ?? []);
969
1001
  }
970
- function checkSupport(expr, pos) {
1002
+ function checkSupport(expr, pos, matchers) {
971
1003
  switch (expr.kind) {
972
1004
  case "unsupported":
973
1005
  return { supported: false, reason: expr.reason };
@@ -976,7 +1008,7 @@ function checkSupport(expr, pos) {
976
1008
  return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
977
1009
  }
978
1010
  for (const prop of expr.properties) {
979
- const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos);
1011
+ const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos, matchers);
980
1012
  if (!propSupport.supported)
981
1013
  return propSupport;
982
1014
  }
@@ -991,7 +1023,7 @@ function checkSupport(expr, pos) {
991
1023
  return { supported: false, reason: "Standalone arrow functions / regex literals are not supported" };
992
1024
  case "array-literal": {
993
1025
  for (const el of expr.elements) {
994
- const elSupport = checkSupport(el, pos);
1026
+ const elSupport = checkSupport(el, pos, matchers);
995
1027
  if (!elSupport.supported)
996
1028
  return elSupport;
997
1029
  }
@@ -1004,28 +1036,39 @@ function checkSupport(expr, pos) {
1004
1036
  reason: `String.prototype.${expr.method} supports only a string pattern + string replacement (the regex form is deferred); use a string pattern or wrap the expression in /* @client */`
1005
1037
  };
1006
1038
  }
1007
- const objSupport = checkSupport(expr.object, pos);
1039
+ const objSupport = checkSupport(expr.object, pos, matchers);
1008
1040
  if (!objSupport.supported)
1009
1041
  return objSupport;
1010
1042
  for (const arg of expr.args) {
1011
- const argSupport = checkSupport(arg, pos);
1043
+ const argSupport = checkSupport(arg, pos, matchers);
1012
1044
  if (!argSupport.supported)
1013
1045
  return argSupport;
1014
1046
  }
1015
1047
  if (expr.method === "flat" && expr.depthExpr) {
1016
- const depthSupport = checkSupport(expr.depthExpr, pos);
1048
+ const depthSupport = checkSupport(expr.depthExpr, pos, matchers);
1017
1049
  if (!depthSupport.supported)
1018
1050
  return depthSupport;
1019
1051
  }
1020
1052
  return { supported: true, level: "L2" };
1021
1053
  }
1022
1054
  case "call": {
1055
+ for (const matcher of matchers) {
1056
+ const node = matcher(expr.callee, expr.args);
1057
+ if (!node)
1058
+ continue;
1059
+ for (const child of loweringNodeChildren(node)) {
1060
+ const childSupport = checkSupport(child, pos, matchers);
1061
+ if (!childSupport.supported)
1062
+ return childSupport;
1063
+ }
1064
+ return { supported: true, level: "L2" };
1065
+ }
1023
1066
  const cb = asCallbackMethodCall(expr);
1024
1067
  if (cb) {
1025
- const objSupport = checkSupport(cb.object, pos);
1068
+ const objSupport = checkSupport(cb.object, pos, matchers);
1026
1069
  if (!objSupport.supported)
1027
1070
  return objSupport;
1028
- const bodySupport = checkSupport(cb.arrow.body, pos);
1071
+ const bodySupport = checkSupport(cb.arrow.body, pos, matchers);
1029
1072
  if (!bodySupport.supported) {
1030
1073
  return {
1031
1074
  supported: false,
@@ -1034,13 +1077,13 @@ function checkSupport(expr, pos) {
1034
1077
  };
1035
1078
  }
1036
1079
  for (const rest of cb.args) {
1037
- const restSupport = checkSupport(rest, pos);
1080
+ const restSupport = checkSupport(rest, pos, matchers);
1038
1081
  if (!restSupport.supported)
1039
1082
  return restSupport;
1040
1083
  }
1041
1084
  return { supported: true, level: "L5" };
1042
1085
  }
1043
- const calleeSupport = checkSupport(expr.callee, pos);
1086
+ const calleeSupport = checkSupport(expr.callee, pos, matchers);
1044
1087
  if (!calleeSupport.supported) {
1045
1088
  return calleeSupport;
1046
1089
  }
@@ -1059,7 +1102,7 @@ function checkSupport(expr, pos) {
1059
1102
  return { supported: true, level: "L1" };
1060
1103
  }
1061
1104
  for (const arg of expr.args) {
1062
- const argSupport = checkSupport(arg, pos);
1105
+ const argSupport = checkSupport(arg, pos, matchers);
1063
1106
  if (!argSupport.supported) {
1064
1107
  return argSupport;
1065
1108
  }
@@ -1067,7 +1110,7 @@ function checkSupport(expr, pos) {
1067
1110
  return { supported: true, level: "L2" };
1068
1111
  }
1069
1112
  case "member": {
1070
- const objSupport = checkSupport(expr.object, pos);
1113
+ const objSupport = checkSupport(expr.object, pos, matchers);
1071
1114
  if (!objSupport.supported) {
1072
1115
  return objSupport;
1073
1116
  }
@@ -1077,19 +1120,19 @@ function checkSupport(expr, pos) {
1077
1120
  return { supported: true, level: "L2" };
1078
1121
  }
1079
1122
  case "index-access": {
1080
- const objSupport = checkSupport(expr.object, pos);
1123
+ const objSupport = checkSupport(expr.object, pos, matchers);
1081
1124
  if (!objSupport.supported)
1082
1125
  return objSupport;
1083
- const indexSupport = checkSupport(expr.index, pos);
1126
+ const indexSupport = checkSupport(expr.index, pos, matchers);
1084
1127
  if (!indexSupport.supported)
1085
1128
  return indexSupport;
1086
1129
  return { supported: true, level: "L2" };
1087
1130
  }
1088
1131
  case "binary": {
1089
- const leftSupport = checkSupport(expr.left, pos);
1132
+ const leftSupport = checkSupport(expr.left, pos, matchers);
1090
1133
  if (!leftSupport.supported)
1091
1134
  return leftSupport;
1092
- const rightSupport = checkSupport(expr.right, pos);
1135
+ const rightSupport = checkSupport(expr.right, pos, matchers);
1093
1136
  if (!rightSupport.supported)
1094
1137
  return rightSupport;
1095
1138
  if (["===", "==", "!==", "!=", ">", "<", ">=", "<="].includes(expr.op)) {
@@ -1101,7 +1144,7 @@ function checkSupport(expr, pos) {
1101
1144
  return { supported: false, reason: `Unknown operator: ${expr.op}` };
1102
1145
  }
1103
1146
  case "unary": {
1104
- const argSupport = checkSupport(expr.argument, pos);
1147
+ const argSupport = checkSupport(expr.argument, pos, matchers);
1105
1148
  if (!argSupport.supported)
1106
1149
  return argSupport;
1107
1150
  if (expr.op === "!") {
@@ -1113,25 +1156,25 @@ function checkSupport(expr, pos) {
1113
1156
  return { supported: false, reason: `Unsupported unary operator: ${expr.op}` };
1114
1157
  }
1115
1158
  case "logical": {
1116
- const leftSupport = checkSupport(expr.left, pos);
1159
+ const leftSupport = checkSupport(expr.left, pos, matchers);
1117
1160
  if (!leftSupport.supported)
1118
1161
  return leftSupport;
1119
1162
  if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
1120
1163
  return { supported: true, level: "L4" };
1121
1164
  }
1122
- const rightSupport = checkSupport(expr.right, pos);
1165
+ const rightSupport = checkSupport(expr.right, pos, matchers);
1123
1166
  if (!rightSupport.supported)
1124
1167
  return rightSupport;
1125
1168
  return { supported: true, level: "L4" };
1126
1169
  }
1127
1170
  case "conditional": {
1128
- const testSupport = checkSupport(expr.test, pos);
1171
+ const testSupport = checkSupport(expr.test, pos, matchers);
1129
1172
  if (!testSupport.supported)
1130
1173
  return testSupport;
1131
- const consSupport = checkSupport(expr.consequent, pos);
1174
+ const consSupport = checkSupport(expr.consequent, pos, matchers);
1132
1175
  if (!consSupport.supported)
1133
1176
  return consSupport;
1134
- const altSupport = checkSupport(expr.alternate, pos);
1177
+ const altSupport = checkSupport(expr.alternate, pos, matchers);
1135
1178
  if (!altSupport.supported)
1136
1179
  return altSupport;
1137
1180
  return { supported: true, level: "L4" };
@@ -1139,7 +1182,7 @@ function checkSupport(expr, pos) {
1139
1182
  case "template-literal": {
1140
1183
  for (const part of expr.parts) {
1141
1184
  if (part.type === "expression") {
1142
- const partSupport = checkSupport(part.expr, pos);
1185
+ const partSupport = checkSupport(part.expr, pos, matchers);
1143
1186
  if (!partSupport.supported)
1144
1187
  return partSupport;
1145
1188
  }
@@ -2430,12 +2473,22 @@ function renderLoopBindingAccess(b, base) {
2430
2473
  }
2431
2474
  return parent;
2432
2475
  }
2433
- function wrapLoopParamAsAccessor(expr, paramName, bindings) {
2476
+ function wrapLoopParamAsAccessor(expr, paramName, bindings, indexParam) {
2477
+ let result;
2434
2478
  if (bindings && bindings.length > 0) {
2435
- return rewriteLoopBindingRefs(expr, bindings, "__bfItem()");
2479
+ result = rewriteLoopBindingRefs(expr, bindings, "__bfItem()");
2480
+ } else {
2481
+ const re = new RegExp(`${ID_BOUNDARY_BEFORE}${escapeIdentifierForRegex(paramName)}(?!\\s*\\()(?!-)${ID_BOUNDARY_AFTER}`, "gu");
2482
+ result = replaceInExprContexts(expr, re, () => `${paramName}()`);
2436
2483
  }
2437
- const re = new RegExp(`${ID_BOUNDARY_BEFORE}${escapeIdentifierForRegex(paramName)}(?!\\s*\\()(?!-)${ID_BOUNDARY_AFTER}`, "gu");
2438
- return replaceInExprContexts(expr, re, () => `${paramName}()`);
2484
+ if (indexParam && indexParam !== paramName) {
2485
+ result = wrapIndexParamAsAccessor(result, indexParam);
2486
+ }
2487
+ return result;
2488
+ }
2489
+ function wrapIndexParamAsAccessor(expr, indexParam) {
2490
+ const re = new RegExp(`${ID_BOUNDARY_BEFORE}${escapeIdentifierForRegex(indexParam)}(?!\\s*\\()(?!-)${ID_BOUNDARY_AFTER}`, "gu");
2491
+ return replaceInExprContexts(expr, re, () => `${indexParam}()`);
2439
2492
  }
2440
2493
  function rewriteLoopBindingRefs(expr, bindings, accessor) {
2441
2494
  const byName = new Map;
@@ -2482,7 +2535,7 @@ function wrapExprWithLoopParams(expr, loopParams) {
2482
2535
  let result = expr;
2483
2536
  for (const p of loopParams) {
2484
2537
  const spec = typeof p === "string" ? { param: p } : p;
2485
- result = wrapLoopParamAsAccessor(result, spec.param, spec.bindings);
2538
+ result = wrapLoopParamAsAccessor(result, spec.param, spec.bindings, spec.index);
2486
2539
  }
2487
2540
  return result;
2488
2541
  }
@@ -2765,6 +2818,20 @@ function buildPropAliasMap(params) {
2765
2818
  }
2766
2819
  return map;
2767
2820
  }
2821
+ function resolveBodyDestructuredPropAliases(localConstants, propsObjectName) {
2822
+ const aliases = new Map;
2823
+ if (propsObjectName === null)
2824
+ return aliases;
2825
+ for (const c of localConstants) {
2826
+ if (c.isModule)
2827
+ continue;
2828
+ const m = c.parsed;
2829
+ if (m?.kind === "member" && !m.computed && m.object.kind === "identifier" && m.object.name === propsObjectName) {
2830
+ aliases.set(c.name, m.property);
2831
+ }
2832
+ }
2833
+ return aliases;
2834
+ }
2768
2835
  function boundPropLocalNames(b) {
2769
2836
  if (b.propsObjectName !== null)
2770
2837
  return EMPTY_SET;
@@ -2997,6 +3064,18 @@ function resolveGetterAliases(localConstants, isGetter) {
2997
3064
  }
2998
3065
  return aliases;
2999
3066
  }
3067
+ function collectAliasableGetterNames(signals, memos) {
3068
+ const getterNames = new Set;
3069
+ for (const sig of signals) {
3070
+ if (sig.getter && !sig.isModule && !sig.envReader)
3071
+ getterNames.add(sig.getter);
3072
+ }
3073
+ for (const memo of memos) {
3074
+ if (!memo.isModule)
3075
+ getterNames.add(memo.name);
3076
+ }
3077
+ return getterNames;
3078
+ }
3000
3079
  function buildSignalMemoEnv(signals, memos, propsObjectName, localConstants = []) {
3001
3080
  const substitutions = new Map;
3002
3081
  for (const s of signals) {
@@ -3173,6 +3252,65 @@ class BindingScope {
3173
3252
  }
3174
3253
  }
3175
3254
 
3255
+ // ../jsx/src/ir-to-client-js/safe-html.ts
3256
+ function safeHtml(expr) {
3257
+ return expr;
3258
+ }
3259
+ function interp(span) {
3260
+ return `\${${span}}`;
3261
+ }
3262
+ function escapedText(expr) {
3263
+ return safeHtml(`escapeText(${expr})`);
3264
+ }
3265
+ function escapedTextOrMarkup(expr) {
3266
+ return safeHtml(`escapeTextOrMarkup(${expr})`);
3267
+ }
3268
+ function branchSlotValue(expr, slotsVar) {
3269
+ return safeHtml(`__bfSlot(${expr}, ${slotsVar})`);
3270
+ }
3271
+ function childrenMarkup(expr) {
3272
+ return safeHtml(`markupOrEmpty(${expr})`);
3273
+ }
3274
+ function joinedMarkup(expr) {
3275
+ return safeHtml(`Array.isArray(${expr}) ? ${expr}.join('') : (${expr} ?? '')`);
3276
+ }
3277
+ function renderChildCall(registryName, propsExpr, tailArgs) {
3278
+ return safeHtml(`renderChild('${registryName}', ${propsExpr}${tailArgs})`);
3279
+ }
3280
+ function dangerousInnerHtml(expr) {
3281
+ return safeHtml(`((${expr}) ?? {}).__html ?? ''`);
3282
+ }
3283
+ function conditionalMarkup(condition, whenTrue, whenFalse) {
3284
+ return safeHtml(`${condition} ? \`${whenTrue}\` : \`${whenFalse}\``);
3285
+ }
3286
+ function mappedRowsMarkup(arrayExpr, method, params, body) {
3287
+ return safeHtml(`${arrayExpr}.${method}(${params} => ${body}).join('')`);
3288
+ }
3289
+ var EMPTY_MARKUP = safeHtml("''");
3290
+ function isChildrenPassthroughExpr(expr) {
3291
+ return /^([A-Za-z_$][\w$]*\.)?children$/.test(expr.trim());
3292
+ }
3293
+ function spliceChildValue(node, valueExpr, cx) {
3294
+ if (node.joinArrayChild)
3295
+ return joinedMarkup(valueExpr);
3296
+ if (cx.branchSlotsVar)
3297
+ return branchSlotValue(valueExpr, cx.branchSlotsVar);
3298
+ if (node.slotId) {
3299
+ return cx.markupSlotIds?.has(node.slotId) ? escapedTextOrMarkup(valueExpr) : escapedText(valueExpr);
3300
+ }
3301
+ const resolved = valueExpr.trim().replace(/^\(+|\)+$/g, "");
3302
+ if (isChildrenPassthroughExpr(node.expr) || isChildrenPassthroughExpr(resolved)) {
3303
+ return childrenMarkup(valueExpr);
3304
+ }
3305
+ return escapedText(valueExpr);
3306
+ }
3307
+
3308
+ // ../jsx/src/ir-to-client-js/markup-slots.ts
3309
+ var DYNAMIC_ELEMENT_WRITER_KIND = "markup";
3310
+ function markupSlotIdsOf(ctx) {
3311
+ return new Set(ctx.dynamicElements.map((e) => e.slotId));
3312
+ }
3313
+
3176
3314
  // ../jsx/src/ir-to-client-js/html-template.ts
3177
3315
  function createStringProtector() {
3178
3316
  const strings = [];
@@ -3342,22 +3480,11 @@ function templateAttrExpr(attrName, valExpr, presenceOrUndefined) {
3342
3480
  function escapeAttrValueExpr(valExpr) {
3343
3481
  return `escapeAttr(${valExpr})`;
3344
3482
  }
3345
- function escapeTextSlotExpr(innerExpr, isMarkup = false) {
3346
- return `${isMarkup ? "escapeTextOrMarkup" : "escapeText"}(${innerExpr})`;
3347
- }
3348
- function isChildrenPassthroughExpr(expr) {
3349
- return /^([A-Za-z_$][\w$]*\.)?children$/.test(expr.trim());
3350
- }
3351
- function bareSpliceExpr(node, valueExpr) {
3352
- const resolved = valueExpr.trim().replace(/^\(+|\)+$/g, "");
3353
- const isChildren = isChildrenPassthroughExpr(node.expr) || isChildrenPassthroughExpr(resolved);
3354
- return !node.joinArrayChild && isChildren ? `markupOrEmpty(${valueExpr})` : valueExpr;
3355
- }
3356
3483
  function dangerouslyHtmlChildren(attrs, toExpr) {
3357
3484
  const attr = attrs.find((a) => a.name === "dangerouslySetInnerHTML");
3358
3485
  if (!attr || attr.value.kind !== "expression")
3359
3486
  return null;
3360
- return `\${((${toExpr(attr.value)}) ?? {}).__html ?? ''}`;
3487
+ return interp(dangerousInnerHtml(toExpr(attr.value)));
3361
3488
  }
3362
3489
  function transformKeyValue(value, transformExpr) {
3363
3490
  switch (value.kind) {
@@ -3473,7 +3600,7 @@ function buildSpreadAttrsMergeCall(args) {
3473
3600
  return `\${spreadAttrs({${objMembers.join(", ")}})}`;
3474
3601
  }
3475
3602
  function itemAnchorTemplate(keyExpr) {
3476
- return `<!--${loopItemMarker("${" + keyExpr + "}")}-->`;
3603
+ return `<!--${loopItemMarker("${escapeCommentText(" + keyExpr + ")}")}-->`;
3477
3604
  }
3478
3605
  function renderPreamble(preamble, opts) {
3479
3606
  let out = "";
@@ -3482,9 +3609,9 @@ function renderPreamble(preamble, opts) {
3482
3609
  const text = opts.textVariant === "template" ? seg.templateText ?? seg.text : seg.text;
3483
3610
  out += opts.transformJs ? opts.transformJs(text) : text;
3484
3611
  } else if (opts.rawLeaf) {
3485
- out += opts.renderLeaf(escapeLeafTextExpressions(seg.ir));
3612
+ out += opts.renderLeaf(seg.ir);
3486
3613
  } else {
3487
- out += "`" + opts.renderLeaf(escapeLeafTextExpressions(seg.ir)) + "`";
3614
+ out += "`" + opts.renderLeaf(seg.ir) + "`";
3488
3615
  }
3489
3616
  }
3490
3617
  return out;
@@ -3529,36 +3656,12 @@ function renderFlatMapProjectionClientBody(inner, restSpreadNames) {
3529
3656
  const chained = applyLoopChain(inner);
3530
3657
  const params = inner.index ? `(${inner.param}, ${inner.index})` : `(${inner.param})`;
3531
3658
  const key = inner.key ? `(${inner.key})` : "undefined";
3532
- const html = inner.children.map((c) => irToHtmlTemplate(escapeLeafTextExpressions(c), restSpreadNames, 1, undefined, undefined)).join("");
3659
+ const html = inner.children.map((c) => irToHtmlTemplate(c, restSpreadNames, 1, undefined, undefined)).join("");
3533
3660
  return `${chained}.map(${params} => ({ k: ${key}, h: \`${html}\` }))`;
3534
3661
  }
3535
- function escapeLeafTextExpressions(ir) {
3536
- switch (ir.type) {
3537
- case "element":
3538
- return { ...ir, children: ir.children.map(escapeLeafTextExpressions) };
3539
- case "fragment":
3540
- return { ...ir, children: ir.children.map(escapeLeafTextExpressions) };
3541
- case "expression": {
3542
- if (ir.expr === "null" || ir.expr === "undefined")
3543
- return ir;
3544
- if (ir.slotId || ir.expr.trimStart().startsWith("escapeText("))
3545
- return ir;
3546
- return { ...ir, expr: `escapeText((${ir.expr}))`, templateExpr: ir.templateExpr ? `escapeText((${ir.templateExpr}))` : ir.templateExpr };
3547
- }
3548
- case "conditional":
3549
- return {
3550
- ...ir,
3551
- whenTrue: escapeLeafTextExpressions(ir.whenTrue),
3552
- whenFalse: ir.whenFalse ? escapeLeafTextExpressions(ir.whenFalse) : ir.whenFalse
3553
- };
3554
- default:
3555
- return ir;
3556
- }
3557
- }
3558
3662
  function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, branchSlotsVar, inHoistedChildren = false) {
3559
3663
  const recurse = (n) => irToHtmlTemplate(n, restSpreadNames, loopDepth, loopParams, branchSlotsVar, inHoistedChildren);
3560
3664
  const wrapExpr = (expr) => wrapExprWithLoopParams(expr, loopParams);
3561
- const wrapInterpolation = (expr) => branchSlotsVar ? `__bfSlot(${expr}, ${branchSlotsVar})` : expr;
3562
3665
  switch (node.type) {
3563
3666
  case "element": {
3564
3667
  const mergeCtx = {
@@ -3604,25 +3707,17 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3604
3707
  case "expression": {
3605
3708
  if (node.expr === "null" || node.expr === "undefined")
3606
3709
  return "";
3607
- const escapeForClient = (e) => node.escapeInClientTemplate ? `escapeText(${e})` : e;
3608
- if (node.markerless) {
3609
- const bare = escapeForClient(wrapInterpolation(wrapExpr(node.expr)));
3610
- return `\${${bare}}`;
3611
- }
3612
- const inner = escapeForClient(wrapInterpolation(wrapExpr(node.expr)));
3613
- const valueExpr = node.joinArrayChild ? `Array.isArray(${inner}) ? ${inner}.join('') : (${inner} ?? '')` : inner;
3614
- if (node.slotId) {
3615
- const slotted = branchSlotsVar || node.joinArrayChild ? valueExpr : escapeTextSlotExpr(valueExpr);
3616
- return `<!--bf:${node.slotId}-->\${${slotted}}<!--/-->`;
3617
- }
3618
- return `\${${bareSpliceExpr(node, valueExpr)}}`;
3710
+ const hole = interp(spliceChildValue(node, wrapExpr(node.expr), { branchSlotsVar }));
3711
+ if (node.markerless)
3712
+ return hole;
3713
+ return node.slotId ? `<!--bf:${node.slotId}-->${hole}<!--/-->` : hole;
3619
3714
  }
3620
3715
  case "conditional": {
3621
3716
  const trueBranch = recurse(node.whenTrue);
3622
3717
  const falseBranch = recurse(node.whenFalse);
3623
3718
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
3624
3719
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
3625
- return `\${${wrapExpr(node.condition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
3720
+ return interp(conditionalMarkup(wrapExpr(node.condition), trueHtml, falseHtml));
3626
3721
  }
3627
3722
  case "fragment":
3628
3723
  return node.children.map(recurse).join("");
@@ -3659,7 +3754,7 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3659
3754
  const propsExpr = propsEntries.length > 0 ? `{${propsEntries.join(", ")}}` : "{}";
3660
3755
  const keyProp = node.props.find((p) => p.name === "key");
3661
3756
  const keyArg = keyProp ? `, ${attrValueToString(keyProp.value) ?? "undefined"}` : "";
3662
- return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${renderChildScopeArgs(node, keyArg)})}`;
3757
+ return interp(renderChildCall(nameForRegistryRef(node.name), propsExpr, renderChildScopeArgs(node, keyArg)));
3663
3758
  }
3664
3759
  case "loop": {
3665
3760
  const innerRecurse = (n) => irToHtmlTemplate(n, restSpreadNames, loopDepth + 1, loopParams, branchSlotsVar);
@@ -3677,12 +3772,12 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3677
3772
  const body = renderPreamble(node.flatMapCallback, {
3678
3773
  renderLeaf: (ir) => irToHtmlTemplate(stripLeafKeyAttr(ir), restSpreadNames, loopDepth + 1, loopParams, branchSlotsVar)
3679
3774
  });
3680
- mapExpr = `\${${wrappedArray}.flatMap(${node.flatMapCallback.params} => ${body}).join('')}`;
3775
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, "flatMap", node.flatMapCallback.params, body));
3681
3776
  } else if (node.preamble) {
3682
3777
  const preamble = renderPreamble(node.preamble, { textVariant: "client", renderLeaf: (ir) => irToHtmlTemplate(ir, restSpreadNames, loopDepth + 1, loopParams, branchSlotsVar) });
3683
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => { ${preamble} return \`${childTemplate}\` }).join('')}`;
3778
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `{ ${preamble} return \`${childTemplate}\` }`));
3684
3779
  } else {
3685
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => \`${childTemplate}\`).join('')}`;
3780
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `\`${childTemplate}\``));
3686
3781
  }
3687
3782
  return `<!--${loopStartMarker(node.markerId)}-->${mapExpr}<!--${loopEndMarker(node.markerId)}-->`;
3688
3783
  }
@@ -3941,20 +4036,15 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
3941
4036
  case "expression": {
3942
4037
  if (node.expr === "null" || node.expr === "undefined")
3943
4038
  return "";
3944
- const wrapped = wrapExpr(node.expr);
3945
- const value = node.joinArrayChild ? `Array.isArray(${wrapped}) ? ${wrapped}.join('') : (${wrapped} ?? '')` : wrapped;
3946
- if (node.slotId) {
3947
- return `<!--bf:${node.slotId}-->\${${node.joinArrayChild ? value : escapeTextSlotExpr(wrapped)}}<!--/-->`;
3948
- }
3949
- const spliced = bareSpliceExpr(node, value);
3950
- return `\${${node.escapeInClientTemplate ? `escapeText(${spliced})` : spliced}}`;
4039
+ const hole = interp(spliceChildValue(node, wrapExpr(node.expr), {}));
4040
+ return node.slotId ? `<!--bf:${node.slotId}-->${hole}<!--/-->` : hole;
3951
4041
  }
3952
4042
  case "conditional": {
3953
4043
  const trueBranch = recurse(node.whenTrue);
3954
4044
  const falseBranch = recurse(node.whenFalse);
3955
4045
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
3956
4046
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
3957
- return `\${${wrapExpr(node.condition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
4047
+ return interp(conditionalMarkup(wrapExpr(node.condition), trueHtml, falseHtml));
3958
4048
  }
3959
4049
  case "fragment":
3960
4050
  return node.children.map(recurse).join("");
@@ -3978,12 +4068,12 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
3978
4068
  const body = renderPreamble(node.flatMapCallback, {
3979
4069
  renderLeaf: (ir) => irToPlaceholderTemplate(stripLeafKeyAttr(ir), restSpreadNames, loopDepth + 1, loopParams)
3980
4070
  });
3981
- mapExpr = `\${${wrappedArray}.flatMap(${node.flatMapCallback.params} => ${body}).join('')}`;
4071
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, "flatMap", node.flatMapCallback.params, body));
3982
4072
  } else if (node.preamble) {
3983
4073
  const preamble = renderPreamble(node.preamble, { textVariant: "client", renderLeaf: (ir) => irToPlaceholderTemplate(ir, restSpreadNames, loopDepth + 1, loopParams) });
3984
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => { ${preamble} return \`${childTemplate}\` }).join('')}`;
4074
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `{ ${preamble} return \`${childTemplate}\` }`));
3985
4075
  } else {
3986
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => \`${childTemplate}\`).join('')}`;
4076
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `\`${childTemplate}\``));
3987
4077
  }
3988
4078
  return `<!--${loopStartMarker(node.markerId)}-->${mapExpr}<!--${loopEndMarker(node.markerId)}-->`;
3989
4079
  }
@@ -4185,13 +4275,8 @@ function irToComponentTemplateWithOpts(node, opts) {
4185
4275
  return "";
4186
4276
  return `<!--bf:${node.slotId}--><!--/-->`;
4187
4277
  }
4188
- const wrapped = transformExpr(node.expr, node.templateExpr);
4189
- const value = node.joinArrayChild ? `Array.isArray(${wrapped}) ? ${wrapped}.join('') : (${wrapped} ?? '')` : wrapped;
4190
- if (node.slotId) {
4191
- const isMarkup = opts.markupSlotIds?.has(node.slotId) ?? false;
4192
- return `<!--bf:${node.slotId}-->\${${node.joinArrayChild ? value : escapeTextSlotExpr(wrapped, isMarkup)}}<!--/-->`;
4193
- }
4194
- return `\${${bareSpliceExpr(node, value)}}`;
4278
+ const hole = interp(spliceChildValue(node, transformExpr(node.expr, node.templateExpr), { markupSlotIds: opts.markupSlotIds }));
4279
+ return node.slotId ? `<!--bf:${node.slotId}-->${hole}<!--/-->` : hole;
4195
4280
  }
4196
4281
  case "conditional": {
4197
4282
  if (node.clientOnly && node.slotId) {
@@ -4201,7 +4286,7 @@ function irToComponentTemplateWithOpts(node, opts) {
4201
4286
  const falseBranch = recurse(node.whenFalse);
4202
4287
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
4203
4288
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
4204
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
4289
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), trueHtml, falseHtml));
4205
4290
  }
4206
4291
  case "fragment":
4207
4292
  return node.children.map(recurse).join("");
@@ -4239,7 +4324,7 @@ function irToComponentTemplateWithOpts(node, opts) {
4239
4324
  const propsExpr = propsEntries.length > 0 ? `{${propsEntries.join(", ")}}` : "{}";
4240
4325
  const keyProp = node.props.find((p) => p.name === "key");
4241
4326
  const keyArg = keyProp ? `, ${transformKeyValue(keyProp.value, transformExpr)}` : "";
4242
- return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${keyArg})}`;
4327
+ return interp(renderChildCall(nameForRegistryRef(node.name), propsExpr, keyArg));
4243
4328
  }
4244
4329
  case "loop": {
4245
4330
  const innerOpts = { ...opts, loopDepth: loopDepth + 1 };
@@ -4249,7 +4334,7 @@ function irToComponentTemplateWithOpts(node, opts) {
4249
4334
  case "if-statement": {
4250
4335
  const consequent = recurse(node.consequent);
4251
4336
  const alternate = node.alternate ? recurse(node.alternate) : "";
4252
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${consequent}\` : \`${alternate}\`}`;
4337
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), consequent, alternate));
4253
4338
  }
4254
4339
  case "provider":
4255
4340
  case "async":
@@ -4337,7 +4422,7 @@ function generateCsrTemplate(node, inlinableConstants, ctx, restSpreadNames, pro
4337
4422
  }
4338
4423
  }
4339
4424
  const effectiveUnsafeLocalNames = mergeCsrNullUnsafe(ctx, unsafeLocalNames);
4340
- const markupSlotIds = new Set(ctx.dynamicElements.map((e) => e.slotId));
4425
+ const markupSlotIds = markupSlotIdsOf(ctx);
4341
4426
  return generateCsrTemplateWithOpts(node, { inlinableConstants, restSpreadNames, propsObjectName, csrEnv, unsafeLocalNames: effectiveUnsafeLocalNames, deferredChildSlots, loopDepth: -1, markupSlotIds, restPropsName: ctx.restPropsName });
4342
4427
  }
4343
4428
  function mergeCsrNullUnsafe(ctx, unsafeLocalNames) {
@@ -4536,13 +4621,8 @@ function generateCsrTemplateWithOpts(node, opts) {
4536
4621
  }
4537
4622
  {
4538
4623
  const transformed = transformExpr(node.expr, node.templateExpr);
4539
- const expr = transformed === UNSAFE_TEMPLATE_EXPR ? "''" : transformed;
4540
- const value = node.joinArrayChild ? `Array.isArray(${expr}) ? ${expr}.join('') : (${expr} ?? '')` : expr;
4541
- if (node.slotId) {
4542
- const isMarkup = opts.markupSlotIds?.has(node.slotId) ?? false;
4543
- return `<!--bf:${node.slotId}-->\${${node.joinArrayChild ? value : escapeTextSlotExpr(expr, isMarkup)}}<!--/-->`;
4544
- }
4545
- return `\${${bareSpliceExpr(node, value)}}`;
4624
+ const hole = interp(transformed === UNSAFE_TEMPLATE_EXPR ? EMPTY_MARKUP : spliceChildValue(node, transformed, { markupSlotIds: opts.markupSlotIds }));
4625
+ return node.slotId ? `<!--bf:${node.slotId}-->${hole}<!--/-->` : hole;
4546
4626
  }
4547
4627
  case "conditional": {
4548
4628
  if (node.clientOnly && node.slotId) {
@@ -4552,7 +4632,7 @@ function generateCsrTemplateWithOpts(node, opts) {
4552
4632
  const falseBranch = recurse(node.whenFalse);
4553
4633
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
4554
4634
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
4555
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
4635
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), trueHtml, falseHtml));
4556
4636
  }
4557
4637
  case "fragment":
4558
4638
  return node.children.map(recurse).join("");
@@ -4601,7 +4681,7 @@ function generateCsrTemplateWithOpts(node, opts) {
4601
4681
  const propsExpr = propsEntries.length > 0 ? `{${propsEntries.join(", ")}}` : "{}";
4602
4682
  const keyProp = node.props.find((p) => p.name === "key");
4603
4683
  const keyArg = keyProp ? `, ${transformKeyValue(keyProp.value, transformExpr)}` : "";
4604
- return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${renderChildScopeArgs(node, keyArg)})}`;
4684
+ return interp(renderChildCall(nameForRegistryRef(node.name), propsExpr, renderChildScopeArgs(node, keyArg)));
4605
4685
  }
4606
4686
  case "loop": {
4607
4687
  const childScope = (opts.scope ?? BindingScope.EMPTY).enterLoopRow(node);
@@ -4634,19 +4714,19 @@ function generateCsrTemplateWithOpts(node, opts) {
4634
4714
  transformJs: (t) => rewritePropsObjectRef(t, propsObjectName ?? null, restPropsName ?? null, { enclosingScope: childScope }),
4635
4715
  renderLeaf: (ir) => recurseInLoopBody(stripLeafKeyAttr(ir))
4636
4716
  });
4637
- mapExpr = `\${${iterArrayExpr}.flatMap(${node.flatMapCallback.params} => ${body}).join('')}`;
4717
+ mapExpr = interp(mappedRowsMarkup(iterArrayExpr, "flatMap", node.flatMapCallback.params, body));
4638
4718
  } else if (node.preamble) {
4639
4719
  const preamble = renderPreamble(node.preamble, { textVariant: "template", transformJs: (t) => rewritePropsObjectRef(t, propsObjectName ?? null, restPropsName ?? null, { enclosingScope: childScope }), renderLeaf: (ir) => recurseInLoopBody(ir) });
4640
- mapExpr = `\${${iterArrayExpr}.${iterMethod}(${callbackParam} => { ${preamble} return \`${childTemplate}\` }).join('')}`;
4720
+ mapExpr = interp(mappedRowsMarkup(iterArrayExpr, iterMethod, callbackParam, `{ ${preamble} return \`${childTemplate}\` }`));
4641
4721
  } else {
4642
- mapExpr = `\${${iterArrayExpr}.${iterMethod}(${callbackParam} => \`${childTemplate}\`).join('')}`;
4722
+ mapExpr = interp(mappedRowsMarkup(iterArrayExpr, iterMethod, callbackParam, `\`${childTemplate}\``));
4643
4723
  }
4644
4724
  return `<!--${loopStartMarker(node.markerId)}-->${mapExpr}<!--${loopEndMarker(node.markerId)}-->`;
4645
4725
  }
4646
4726
  case "if-statement": {
4647
4727
  const consequent = recurse(node.consequent);
4648
4728
  const alternate = node.alternate ? recurse(node.alternate) : "";
4649
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${consequent}\` : \`${alternate}\`}`;
4729
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), consequent, alternate));
4650
4730
  }
4651
4731
  case "provider":
4652
4732
  case "async":
@@ -4747,8 +4827,6 @@ function collectAstPropRefs(node, propNames, out) {
4747
4827
  walkWithScope(node, (n, parent, shadowed) => {
4748
4828
  if (shadowed || !propNames.has(n.text))
4749
4829
  return;
4750
- if (parent && ts7.isShorthandPropertyAssignment(parent) && parent.name === n)
4751
- return;
4752
4830
  if (isNonValuePosition(n, parent))
4753
4831
  return;
4754
4832
  out.add(n.text);
@@ -6643,6 +6721,7 @@ var CLIENT_EXPORTS = new Set([
6643
6721
  "isSSRPortal",
6644
6722
  "findSiblingSlot",
6645
6723
  "cleanupPortalPlaceholder",
6724
+ "trackPosition",
6646
6725
  "createSearchParams",
6647
6726
  "queryHref",
6648
6727
  "formatDate",
@@ -7962,7 +8041,8 @@ var BROWSER_ONLY_CLIENT_APIS = new Set([
7962
8041
  "createPortal",
7963
8042
  "isSSRPortal",
7964
8043
  "findSiblingSlot",
7965
- "cleanupPortalPlaceholder"
8044
+ "cleanupPortalPlaceholder",
8045
+ "trackPosition"
7966
8046
  ]);
7967
8047
  function importsBrowserOnlyClientApi(ctx) {
7968
8048
  for (const imp of ctx.imports) {
@@ -10170,9 +10250,8 @@ function collectBranchLocalPropRefsViaSubstitution(node, ctx) {
10170
10250
  function visit2(n, parent) {
10171
10251
  if (ts14.isIdentifier(n) && propDepsMap.has(n.text)) {
10172
10252
  const isObjectKey = parent && ts14.isPropertyAssignment(parent) && parent.name === n;
10173
- const isShorthand = parent && ts14.isShorthandPropertyAssignment(parent) && parent.name === n;
10174
10253
  const isAccessName = parent && ts14.isPropertyAccessExpression(parent) && parent.name === n;
10175
- if (!isObjectKey && !isShorthand && !isAccessName) {
10254
+ if (!isObjectKey && !isAccessName) {
10176
10255
  const deps = propDepsMap.get(n.text);
10177
10256
  if (deps && deps.size > 0) {
10178
10257
  if (!acc)
@@ -10650,8 +10729,7 @@ function lowerFormControlValueSsr(tagName, attrs, children) {
10650
10729
  children.push({
10651
10730
  type: "expression",
10652
10731
  expr,
10653
- templateExpr: `escapeText(${templateExpr ?? expr})`,
10654
- escapeInClientTemplate: true,
10732
+ templateExpr,
10655
10733
  typeInfo: null,
10656
10734
  reactive: false,
10657
10735
  slotId: null,
@@ -10662,26 +10740,76 @@ function lowerFormControlValueSsr(tagName, attrs, children) {
10662
10740
  }
10663
10741
  const selectedForLiteral = (optValue) => AttrValueOf.expression(`(${expr}) === ${JSON.stringify(optValue)}`, templateExpr !== undefined ? { templateExpr: `(${templateExpr}) === ${JSON.stringify(optValue)}` } : undefined);
10664
10742
  const selectedForExpr = (optExpr, optTemplateExpr) => AttrValueOf.expression(`(${expr}) === (${optExpr})`, templateExpr !== undefined || optTemplateExpr !== undefined ? { templateExpr: `(${templateExpr ?? expr}) === (${optTemplateExpr ?? optExpr})` } : undefined);
10743
+ const matchConditions = [];
10744
+ let optionSetIsDynamic = false;
10665
10745
  const distribute = (nodes) => {
10666
10746
  for (const n of nodes) {
10747
+ if (n.type === "text")
10748
+ continue;
10667
10749
  if (n.type === "element" && n.tag === "option") {
10668
- if (n.attrs.some((a) => a.name === "selected"))
10750
+ if (n.attrs.some((a) => a.name === "selected")) {
10751
+ optionSetIsDynamic = true;
10669
10752
  continue;
10753
+ }
10670
10754
  const optValue = n.attrs.find((a) => a.name === "value");
10671
- if (!optValue)
10755
+ if (!optValue) {
10756
+ optionSetIsDynamic = true;
10672
10757
  continue;
10758
+ }
10673
10759
  if (optValue.value.kind === "literal") {
10674
- n.attrs.push({ name: "selected", value: selectedForLiteral(optValue.value.value), loc: n.loc });
10760
+ const selected = selectedForLiteral(optValue.value.value);
10761
+ n.attrs.push({ name: "selected", value: selected, loc: n.loc });
10762
+ matchConditions.push(selected);
10675
10763
  } else if (optValue.value.kind === "expression") {
10676
10764
  const selected = selectedForExpr(optValue.value.expr, optValue.value.templateExpr);
10677
10765
  n.attrs.push({ name: "selected", value: selected, loc: n.loc });
10766
+ matchConditions.push(selected);
10767
+ } else {
10768
+ optionSetIsDynamic = true;
10678
10769
  }
10679
- } else if (n.type === "fragment" || n.type === "loop" || n.type === "element" && n.tag === "optgroup") {
10770
+ } else if (n.type === "fragment" || n.type === "element" && n.tag === "optgroup") {
10771
+ distribute(n.children);
10772
+ } else if (n.type === "loop") {
10773
+ optionSetIsDynamic = true;
10680
10774
  distribute(n.children);
10775
+ } else {
10776
+ optionSetIsDynamic = true;
10681
10777
  }
10682
10778
  }
10683
10779
  };
10684
10780
  distribute(children);
10781
+ if (optionSetIsDynamic || matchConditions.length === 0)
10782
+ return;
10783
+ if (isMultiSelection(attrs))
10784
+ return;
10785
+ const orExpr = matchConditions.map((c) => `(${c.expr})`).join(" || ");
10786
+ const orTemplateExpr = matchConditions.some((c) => c.templateExpr !== undefined) ? matchConditions.map((c) => `(${c.templateExpr ?? c.expr})`).join(" || ") : undefined;
10787
+ children.unshift({
10788
+ type: "element",
10789
+ tag: "option",
10790
+ attrs: [
10791
+ { name: "value", value: AttrValueOf.literal(""), loc: valueAttr.loc },
10792
+ { name: "disabled", value: AttrValueOf.booleanAttr(), loc: valueAttr.loc },
10793
+ { name: "hidden", value: AttrValueOf.booleanAttr(), loc: valueAttr.loc },
10794
+ {
10795
+ name: "selected",
10796
+ value: AttrValueOf.expression(`!(${orExpr})`, orTemplateExpr !== undefined ? { templateExpr: `!(${orTemplateExpr})` } : undefined),
10797
+ loc: valueAttr.loc
10798
+ }
10799
+ ],
10800
+ events: [],
10801
+ ref: null,
10802
+ children: [],
10803
+ slotId: null,
10804
+ needsScope: false,
10805
+ loc: valueAttr.loc
10806
+ });
10807
+ }
10808
+ function isMultiSelection(attrs) {
10809
+ if (attrs.some((a) => a.name === "multiple"))
10810
+ return true;
10811
+ const sizeAttr = attrs.find((a) => a.name === "size");
10812
+ return sizeAttr?.value.kind === "literal" && Number(sizeAttr.value.value) > 1;
10685
10813
  }
10686
10814
  function transformHtmlElement(node, ctx, tagName) {
10687
10815
  const { attrs, events, ref } = processAttributes(node.openingElement.attributes, ctx);
@@ -15043,7 +15171,7 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
15043
15171
  },
15044
15172
  loop: ({ node: n, scope, descend }) => {
15045
15173
  const emitDepth = fixedDepth ?? scope.depth + 1;
15046
- const loopParamsForTemplate = outerLoopParam ? [outerLoopParam, { param: n.param, bindings: n.paramBindings }] : undefined;
15174
+ const loopParamsForTemplate = outerLoopParam ? [outerLoopParam, { param: n.param, bindings: n.paramBindings, index: n.index }] : undefined;
15047
15175
  const template = n.children.map((c) => irToPlaceholderTemplate(c, undefined, emitDepth, loopParamsForTemplate)).join("");
15048
15176
  const refsOuter = outerLoopParam ? identifierPattern(outerLoopParam).test(n.array) : false;
15049
15177
  const bindings = emptyLoopChildBindings();
@@ -15640,7 +15768,7 @@ function collectLoopChildConditionals(node, ctx, siblingOffsets, loopParam, loop
15640
15768
  const readsPreamble = preambleNames !== undefined && preambleNames.size > 0 && anyNameIn(expanded.freeIds ?? extractFreeIdentifiersFromText(expanded.expr), preambleNames);
15641
15769
  if (!readsPreamble && classifyReactivity(expanded.expr, ctx, loopParam, loopParamBindings, expanded.freeIds).kind === "none")
15642
15770
  return;
15643
- const loopParamsForCond = loopParam ? [{ param: loopParam, bindings: loopParamBindings }] : undefined;
15771
+ const loopParamsForCond = loopParam ? [{ param: loopParam, bindings: loopParamBindings, index: loopIndex }] : undefined;
15644
15772
  const whenTrueHtml = irToHtmlTemplate(n.whenTrue, undefined, 0, loopParamsForCond, "__slots");
15645
15773
  const whenFalseHtml = irToHtmlTemplate(n.whenFalse, undefined, 0, loopParamsForCond, "__slots");
15646
15774
  conditionals.push({
@@ -16224,6 +16352,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
16224
16352
  "escapeAttr",
16225
16353
  "escapeText",
16226
16354
  "escapeTextOrNode",
16355
+ "escapeCommentText",
16227
16356
  "bfMarkup",
16228
16357
  "escapeTextOrMarkup",
16229
16358
  "markupOrEmpty",
@@ -16436,27 +16565,6 @@ function collectComponentNames(node) {
16436
16565
 
16437
16566
  // ../jsx/src/relocate.ts
16438
16567
  import ts18 from "typescript";
16439
-
16440
- // ../jsx/src/lowering-registry.ts
16441
- var plugins = [];
16442
- function registerLoweringPlugin(plugin) {
16443
- const existing = plugins.findIndex((p) => p.name === plugin.name);
16444
- if (existing >= 0)
16445
- plugins[existing] = plugin;
16446
- else
16447
- plugins.push(plugin);
16448
- }
16449
- function prepareLoweringMatchers(metadata) {
16450
- const matchers = [];
16451
- for (const plugin of plugins) {
16452
- const matcher = plugin.prepare(metadata);
16453
- if (matcher)
16454
- matchers.push(matcher);
16455
- }
16456
- return matchers;
16457
- }
16458
-
16459
- // ../jsx/src/relocate.ts
16460
16568
  function classify(name, env) {
16461
16569
  return env.bindings.get(name) ?? "global";
16462
16570
  }
@@ -17304,7 +17412,7 @@ function emitRegistrationAndHydration(lines, ctx, _ir, graph, inlinability) {
17304
17412
  const isCommentScope = isFragmentRoot || _ir.root.type === "component";
17305
17413
  const defParts = [`init: init${name}`];
17306
17414
  if (canGenerateStaticTemplate(_ir.root, propNamesForStaticCheck, inlinableConstants, unsafeLocalNames)) {
17307
- const markupSlotIds = new Set(ctx.dynamicElements.map((e) => e.slotId));
17415
+ const markupSlotIds = markupSlotIdsOf(ctx);
17308
17416
  const templateHtml = irToComponentTemplate(_ir.root, inlinableConstants, restSpreadNames, ctx.propsObjectName, markupSlotIds, ctx.restPropsName);
17309
17417
  if (templateHtml) {
17310
17418
  defParts.push(buildTemplateDefPart(ctx, templateHtml));
@@ -18304,12 +18412,12 @@ function nestedLoopIndexAlias(inner, syntheticIndexVar, paramHead, comps, events
18304
18412
  return null;
18305
18413
  return `const ${index} = ${syntheticIndexVar}`;
18306
18414
  }
18307
- function buildChildRefBindings(refs, loopParam, loopParamBindings) {
18415
+ function buildChildRefBindings(refs, loopParam, loopParamBindings, loopIndex) {
18308
18416
  if (refs.length === 0)
18309
18417
  return [];
18310
18418
  return refs.map((r) => ({
18311
18419
  childSlotId: r.childSlotId,
18312
- callback: wrapLoopParamAsAccessor(r.callback, loopParam, loopParamBindings)
18420
+ callback: wrapLoopParamAsAccessor(r.callback, loopParam, loopParamBindings, loopIndex)
18313
18421
  }));
18314
18422
  }
18315
18423
  function buildStaticChildRefBindings(refs) {
@@ -18342,17 +18450,17 @@ function destructureLoopParam(param, paramBindings) {
18342
18450
  }
18343
18451
  return { head: param, unwrap: "" };
18344
18452
  }
18345
- function buildPreambleRegionPlans(regions, loopParam, loopParamBindings) {
18453
+ function buildPreambleRegionPlans(regions, loopParam, loopParamBindings, loopIndex) {
18346
18454
  if (!regions || regions.length === 0)
18347
18455
  return [];
18348
18456
  return regions.map((r) => {
18349
- const wrapped = wrapLoopParamAsAccessor(r.expr, loopParam, loopParamBindings);
18350
- const valueExpr = r.joinArrayChild ? `Array.isArray(${wrapped}) ? ${wrapped}.join('') : (${wrapped} ?? '')` : `escapeText(${wrapped})`;
18457
+ const wrapped = wrapLoopParamAsAccessor(r.expr, loopParam, loopParamBindings, loopIndex);
18458
+ const valueExpr = spliceChildValue({ expr: r.expr, slotId: r.slotId, joinArrayChild: r.joinArrayChild }, wrapped, {});
18351
18459
  return { slotId: r.slotId, valueExpr };
18352
18460
  });
18353
18461
  }
18354
- function buildComponentPropsExpr2(comp, loopParam, loopParamBindings) {
18355
- const wrap = loopParam ? (expr) => wrapLoopParamAsAccessor(expr, loopParam, loopParamBindings) : (expr) => expr;
18462
+ function buildComponentPropsExpr2(comp, loopParam, loopParamBindings, loopIndex) {
18463
+ const wrap = loopParam ? (expr) => wrapLoopParamAsAccessor(expr, loopParam, loopParamBindings, loopIndex) : (expr) => expr;
18356
18464
  const entries = comp.props.map((p) => {
18357
18465
  if (p.isEventHandler) {
18358
18466
  const handlerExpr = attrValueToString(p.value) ?? "undefined";
@@ -18396,8 +18504,8 @@ function buildDepthLevels(innerLoops, nestedComps, childEvents) {
18396
18504
  loopInfo: loop
18397
18505
  }));
18398
18506
  }
18399
- function emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot = false) {
18400
- const handler = loopParam ? wrapLoopParamAsAccessor(ev.handler, loopParam, loopParamBindings) : ev.handler;
18507
+ function emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot = false, loopIndex) {
18508
+ const handler = loopParam ? wrapLoopParamAsAccessor(ev.handler, loopParam, loopParamBindings, loopIndex) : ev.handler;
18401
18509
  emitListenerBlock(ls, indent, elVar, ev.childSlotId, "__e", ev.eventName, handler, "dom", bodyIsMultiRoot);
18402
18510
  }
18403
18511
  function buildCompSelector(comp) {
@@ -18409,15 +18517,15 @@ function isTextOnlyConditional(node) {
18409
18517
  const checkNode = (n) => n.type === "text" || n.type === "expression" || n.type === "conditional" && isTextOnlyConditional(n);
18410
18518
  return checkNode(node.whenTrue) && checkNode(node.whenFalse);
18411
18519
  }
18412
- function emitComponentAndEventSetup(ls, indent, elVar, comps, events, loopParam, loopParamBindings, bodyIsMultiRoot = false) {
18413
- const wrap = loopParam ? (expr) => wrapLoopParamAsAccessor(expr, loopParam, loopParamBindings) : (expr) => expr;
18520
+ function emitComponentAndEventSetup(ls, indent, elVar, comps, events, loopParam, loopParamBindings, bodyIsMultiRoot = false, loopIndex) {
18521
+ const wrap = loopParam ? (expr) => wrapLoopParamAsAccessor(expr, loopParam, loopParamBindings, loopIndex) : (expr) => expr;
18414
18522
  const upsertFn = bodyIsMultiRoot ? "upsertChildItem" : "upsertChild";
18415
18523
  for (const comp of comps) {
18416
- const propsExpr = buildComponentPropsExpr2(comp, loopParam, loopParamBindings);
18524
+ const propsExpr = buildComponentPropsExpr2(comp, loopParam, loopParamBindings, loopIndex);
18417
18525
  const isTextOnly = comp.children?.length ? comp.children.every((c) => c.type === "expression" || c.type === "text" || isTextOnlyConditional(c)) : false;
18418
18526
  const rawChildrenExpr = isTextOnly ? irChildrenToJsExpr(comp.children) : null;
18419
18527
  const childrenFreeIds = isTextOnly && comp.children ? irChildrenFreeIds(comp.children) : undefined;
18420
- const childrenRefsLoop = loopParam != null && rawChildrenExpr != null && childrenFreeIds != null && exprRefsLoopBinding(childrenFreeIds, { param: loopParam, paramBindings: loopParamBindings });
18528
+ const childrenRefsLoop = loopParam != null && rawChildrenExpr != null && childrenFreeIds != null && (exprRefsLoopBinding(childrenFreeIds, { param: loopParam, paramBindings: loopParamBindings }) || !!loopIndex && childrenFreeIds.has(loopIndex));
18421
18529
  const slotIdLit = comp.slotId ? `'${comp.slotId}'` : "null";
18422
18530
  const keyProp = comp.props.find((p) => p.name === "key");
18423
18531
  const keyArg = keyProp ? `, ${wrap(attrValueToString(keyProp.value) ?? "undefined")}` : ", undefined";
@@ -18430,7 +18538,7 @@ function emitComponentAndEventSetup(ls, indent, elVar, comps, events, loopParam,
18430
18538
  }
18431
18539
  }
18432
18540
  for (const ev of events) {
18433
- emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot);
18541
+ emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot, loopIndex);
18434
18542
  }
18435
18543
  }
18436
18544
 
@@ -18810,12 +18918,12 @@ function buildBranchInnerLoopsPlan(args) {
18810
18918
  const inner = innerLoops[i];
18811
18919
  if (!inner.refsOuterParam || !inner.template)
18812
18920
  continue;
18813
- const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
18814
- const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
18921
+ const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings, inner.index);
18922
+ const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings, inner.index);
18815
18923
  const csl = inner.containerSlotId;
18816
18924
  const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST}="\${__scopeId}"][${BF_AT}="${csl}"]\`) ?? ${scopeVar})` : `findCondContainer(${scopeVar}, '${condSlotId}')`;
18817
18925
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
18818
- const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
18926
+ const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings, inner.index) : null;
18819
18927
  const wrapIRNode = (node) => {
18820
18928
  if (node.type === "component") {
18821
18929
  return {
@@ -18977,8 +19085,8 @@ function buildLoopChildArmPlan(args) {
18977
19085
 
18978
19086
  // ../jsx/src/ir-to-client-js/control-flow/plan/build-reactive-effects.ts
18979
19087
  function buildReactiveEffectsPlan(args) {
18980
- const { attrs, texts, conditionals, loopParam, loopParamBindings, profileComponentName } = args;
18981
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, loopParam, loopParamBindings);
19088
+ const { attrs, texts, conditionals, loopParam, loopParamBindings, loopIndex, profileComponentName } = args;
19089
+ const wrap = (expr) => wrapLoopParamAsAccessor(expr, loopParam, loopParamBindings, loopIndex);
18982
19090
  const attrsBySlot = new Map;
18983
19091
  for (const attr of attrs) {
18984
19092
  let bucket = attrsBySlot.get(attr.childSlotId);
@@ -19062,6 +19170,7 @@ function buildLoopReactiveEffectsPlan(elem, profileComponentName) {
19062
19170
  conditionals: elem.bindings.conditionals,
19063
19171
  loopParam: elem.param,
19064
19172
  loopParamBindings: elem.paramBindings,
19173
+ loopIndex: elem.index,
19065
19174
  profileComponentName
19066
19175
  });
19067
19176
  }
@@ -19140,10 +19249,10 @@ function buildInnerLoopsPlan(args) {
19140
19249
  return plan;
19141
19250
  }
19142
19251
  function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, outerLoopParamBindings) {
19143
- const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
19144
- const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
19252
+ const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings, inner.index);
19253
+ const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings, inner.index);
19145
19254
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
19146
- const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
19255
+ const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings, inner.index) : null;
19147
19256
  const wrapIRNode = (node) => {
19148
19257
  if (node.type === "component") {
19149
19258
  return {
@@ -19174,11 +19283,11 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
19174
19283
  }));
19175
19284
  const reactiveTexts = inner.bindings.reactiveTexts.map((text) => ({
19176
19285
  slotId: text.slotId,
19177
- wrappedExpression: wrapLoopParamAsAccessor(wrapOuter(text.expression), inner.param, inner.paramBindings),
19286
+ wrappedExpression: wrapLoopParamAsAccessor(wrapOuter(text.expression), inner.param, inner.paramBindings, inner.index),
19178
19287
  insideConditional: !!text.insideConditional
19179
19288
  }));
19180
19289
  const reactiveAttrs = inner.bindings.reactiveAttrs.map((attr) => {
19181
- const wrapped = wrapLoopParamAsAccessor(wrapOuter(attr.expression), inner.param, inner.paramBindings);
19290
+ const wrapped = wrapLoopParamAsAccessor(wrapOuter(attr.expression), inner.param, inner.paramBindings, inner.index);
19182
19291
  return {
19183
19292
  slotId: attr.childSlotId,
19184
19293
  attrName: attr.attrName,
@@ -19195,14 +19304,14 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
19195
19304
  if (inner.preamble) {
19196
19305
  const leafLoopParams = outerLoopParam ? [
19197
19306
  { param: outerLoopParam, bindings: outerLoopParamBindings },
19198
- { param: inner.param, bindings: inner.paramBindings }
19199
- ] : [{ param: inner.param, bindings: inner.paramBindings }];
19307
+ { param: inner.param, bindings: inner.paramBindings, index: inner.index }
19308
+ ] : [{ param: inner.param, bindings: inner.paramBindings, index: inner.index }];
19200
19309
  preludeStatements.push(renderPreamble(inner.preamble, {
19201
19310
  transformJs: (t) => wrapInner(wrapOuter(t)),
19202
19311
  renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, leafLoopParams, undefined)
19203
19312
  }));
19204
19313
  }
19205
- const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings);
19314
+ const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings, inner.index);
19206
19315
  const conditionals = buildLoopChildConditionalsPlan({
19207
19316
  conditionals: inner.bindings.conditionals,
19208
19317
  scopeVar: `__innerEl${uidSuffix}`,
@@ -19251,7 +19360,7 @@ function buildTopLevelCompositePlan(elem, profileComponentName) {
19251
19360
  const nestedComps = elem.nestedComponents;
19252
19361
  const depthLevels = buildDepthLevels(elem.innerLoops ?? [], nestedComps, elem.bindings.events);
19253
19362
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
19254
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings);
19363
+ const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings, elem.index);
19255
19364
  const outerCompsByDepth = nestedComps.filter((c) => !c.loopDepth || c.loopDepth === 0);
19256
19365
  return {
19257
19366
  kind: "composite",
@@ -19265,12 +19374,12 @@ function buildTopLevelCompositePlan(elem, profileComponentName) {
19265
19374
  indexParam: elem.index || "__idx",
19266
19375
  mapPreambleWrapped: elem.preamble ? renderPreamble(elem.preamble, {
19267
19376
  transformJs: wrap,
19268
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings }], undefined)
19377
+ renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings, index: elem.index }], undefined)
19269
19378
  }) : "",
19270
19379
  template: elem.template,
19271
19380
  outerComps: filterCondCompsOut(outerCompsByDepth, elem.bindings.conditionals),
19272
19381
  outerEvents: elem.bindings.events.filter((ev) => ev.nestedLoops.length === 0),
19273
- childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
19382
+ childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings, elem.index),
19274
19383
  innerLoops: buildInnerLoopsPlan({
19275
19384
  levels: depthLevels,
19276
19385
  parentElVar: "__el",
@@ -19279,12 +19388,14 @@ function buildTopLevelCompositePlan(elem, profileComponentName) {
19279
19388
  }),
19280
19389
  loopParam: elem.param,
19281
19390
  loopParamBindings: elem.paramBindings,
19391
+ loopIndex: elem.index,
19282
19392
  reactiveEffects: hasReactive(elem) ? buildReactiveEffectsPlan({
19283
19393
  attrs: elem.bindings.reactiveAttrs,
19284
19394
  texts: elem.bindings.reactiveTexts,
19285
19395
  conditionals: elem.bindings.conditionals,
19286
19396
  loopParam: elem.param,
19287
19397
  loopParamBindings: elem.paramBindings,
19398
+ loopIndex: elem.index,
19288
19399
  profileComponentName
19289
19400
  }) : null,
19290
19401
  branchClearChildren: false,
@@ -19301,7 +19412,7 @@ function buildBranchCompositePlan(loop, cv, profileComponentName) {
19301
19412
  const childEvents = loop.bindings.events;
19302
19413
  const depthLevels = buildDepthLevels(innerLoops, nestedComps, childEvents);
19303
19414
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
19304
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings);
19415
+ const wrap = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings, loop.index);
19305
19416
  const outerCompsByDepth = nestedComps.filter((c) => !c.loopDepth || c.loopDepth === 0);
19306
19417
  return {
19307
19418
  kind: "composite",
@@ -19315,12 +19426,12 @@ function buildBranchCompositePlan(loop, cv, profileComponentName) {
19315
19426
  indexParam: loop.index || "__idx",
19316
19427
  mapPreambleWrapped: loop.preamble ? renderPreamble(loop.preamble, {
19317
19428
  transformJs: wrap,
19318
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: loop.param, bindings: loop.paramBindings }], undefined)
19429
+ renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: loop.param, bindings: loop.paramBindings, index: loop.index }], undefined)
19319
19430
  }) : "",
19320
19431
  template: loop.template,
19321
19432
  outerComps: filterCondCompsOut(outerCompsByDepth, loop.bindings.conditionals),
19322
19433
  outerEvents: childEvents.filter((ev) => ev.nestedLoops.length === 0),
19323
- childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings),
19434
+ childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings, loop.index),
19324
19435
  innerLoops: buildInnerLoopsPlan({
19325
19436
  levels: depthLevels,
19326
19437
  parentElVar: "__el",
@@ -19329,12 +19440,14 @@ function buildBranchCompositePlan(loop, cv, profileComponentName) {
19329
19440
  }),
19330
19441
  loopParam: loop.param,
19331
19442
  loopParamBindings: loop.paramBindings,
19443
+ loopIndex: loop.index,
19332
19444
  reactiveEffects: hasReactiveBranch(loop) ? buildReactiveEffectsPlan({
19333
19445
  attrs: loop.bindings.reactiveAttrs,
19334
19446
  texts: loop.bindings.reactiveTexts,
19335
19447
  conditionals: loop.bindings.conditionals,
19336
19448
  loopParam: loop.param,
19337
19449
  loopParamBindings: loop.paramBindings,
19450
+ loopIndex: loop.index,
19338
19451
  profileComponentName
19339
19452
  }) : null,
19340
19453
  branchClearChildren: true,
@@ -19469,7 +19582,7 @@ function wiringOn(branch) {
19469
19582
  found.push("reactive text");
19470
19583
  return found;
19471
19584
  }
19472
- function analyzeLazyConditional(cond, indexParam, arms) {
19585
+ function analyzeLazyConditional(cond, arms) {
19473
19586
  for (const [label, branch] of [["true", cond.whenTrue], ["false", cond.whenFalse]]) {
19474
19587
  const wiring = wiringOn(branch);
19475
19588
  if (wiring.length > 0) {
@@ -19490,9 +19603,6 @@ function analyzeLazyConditional(cond, indexParam, arms) {
19490
19603
  if (!cond.conditionFreeIdentifiers) {
19491
19604
  return NO(`conditional on slot ${cond.slotId}: condition has no analyzable identifier set`);
19492
19605
  }
19493
- if (cond.conditionFreeIdentifiers.has(indexParam)) {
19494
- return NO(`conditional on slot ${cond.slotId}: condition reads the loop index parameter '${indexParam}'`);
19495
- }
19496
19606
  return {
19497
19607
  lazySafe: true,
19498
19608
  facts: {
@@ -19511,7 +19621,7 @@ var NO_PREAMBLE = {
19511
19621
  facts: { declaredNames: new Set, freeNames: new Set }
19512
19622
  };
19513
19623
  var NO2 = (reason) => ({ lazySafe: false, reason });
19514
- function analyzeLazyPreamble(preamble, indexParam, primableNames) {
19624
+ function analyzeLazyPreamble(preamble, primableNames) {
19515
19625
  if (!preamble)
19516
19626
  return NO_PREAMBLE;
19517
19627
  if (preamble.builderNames.length > 0) {
@@ -19550,9 +19660,6 @@ function analyzeLazyPreamble(preamble, indexParam, primableNames) {
19550
19660
  }
19551
19661
  }
19552
19662
  const readNames = extractFreeIdentifiersFromStatementText(text);
19553
- if (readNames.has(indexParam) && !declaredNames.has(indexParam)) {
19554
- return NO2(`map-callback preamble reads the loop index parameter '${indexParam}'`);
19555
- }
19556
19663
  const freeNames = new Set(readNames);
19557
19664
  for (const declared of declaredNames)
19558
19665
  freeNames.delete(declared);
@@ -19702,9 +19809,6 @@ function lazyRowEligibility(args) {
19702
19809
  if (shape.hasParamUnwrap)
19703
19810
  return NO3("destructured loop param without param bindings");
19704
19811
  for (const b of bindings) {
19705
- if (b.referencesIndex) {
19706
- return NO3(`binding on slot ${b.slotId} references the loop index parameter`);
19707
- }
19708
19812
  if (b.opaqueOuterNames.includes(UNKNOWN_IDENTIFIERS)) {
19709
19813
  return NO3(`binding on slot ${b.slotId} has no analyzable identifier set`);
19710
19814
  }
@@ -19789,6 +19893,7 @@ function classifyLazyBinding(args) {
19789
19893
  }
19790
19894
  if (name === indexParam) {
19791
19895
  referencesIndex = true;
19896
+ readsItem = true;
19792
19897
  return;
19793
19898
  }
19794
19899
  if (INERT_BINDING_GLOBALS.has(name))
@@ -19838,12 +19943,12 @@ function decideLazyRow(args) {
19838
19943
  for (const b of loop.paramBindings ?? [])
19839
19944
  rowLocalNames.add(b.name);
19840
19945
  const primableNames = new Set([...scope.signals.keys(), ...scope.memos]);
19841
- const preambleAnalysis = analyzeLazyPreamble(loop.preamble, args.indexParam, primableNames);
19946
+ const preambleAnalysis = analyzeLazyPreamble(loop.preamble, primableNames);
19842
19947
  const rawConditionals = loop.bindings.conditionals ?? [];
19843
19948
  const condFacts = [];
19844
19949
  let conditionalRefusal = null;
19845
19950
  for (const cond of rawConditionals) {
19846
- const verdict = analyzeLazyConditional(cond, args.indexParam, {
19951
+ const verdict = analyzeLazyConditional(cond, {
19847
19952
  whenTrueHtml: addCondAttrToTemplate(wrap(cond.whenTrueHtml), cond.slotId),
19848
19953
  whenFalseHtml: addCondAttrToTemplate(wrap(cond.whenFalseHtml), cond.slotId)
19849
19954
  });
@@ -19985,7 +20090,8 @@ function decideLazyRow(args) {
19985
20090
  preambleStatements: args.mapPreambleWrapped,
19986
20091
  itemNeedsPreamble: [...attrs, ...texts, ...conditionals].some((b) => b.readsItem && b.readsPreamble),
19987
20092
  outerNeedsPreamble: [...attrs, ...texts, ...conditionals].some((b) => b.readsOuter && b.readsPreamble),
19988
- conditionals
20093
+ conditionals,
20094
+ readsIndex: classified.some((c) => c.referencesIndex)
19989
20095
  },
19990
20096
  decision
19991
20097
  };
@@ -20036,6 +20142,43 @@ function loopSourceIdentifiers(loop, arrayExpr) {
20036
20142
  return names;
20037
20143
  }
20038
20144
 
20145
+ // ../jsx/src/ir-to-client-js/control-flow/plan/build-plain-row.ts
20146
+ function buildPlainRowCore(inputs) {
20147
+ const { loop, arrayExpr, callSite, flatMapLeafItem, anchored, scope } = inputs;
20148
+ const wrapItem = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings);
20149
+ const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
20150
+ const indexParam = loop.index || "__idx";
20151
+ const mapPreambleWrapped = loop.preamble ? renderPreamble(loop.preamble, {
20152
+ transformJs: wrapItem,
20153
+ renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: loop.param, bindings: loop.paramBindings }], undefined)
20154
+ }) : "";
20155
+ const preambleRegions = buildPreambleRegionPlans(loop.preambleRegions, loop.param, loop.paramBindings, loop.index);
20156
+ const lazyRow = buildLazyRowPlan({
20157
+ loop,
20158
+ arrayExpr,
20159
+ indexParam,
20160
+ paramUnwrap,
20161
+ mapPreambleWrapped,
20162
+ preambleRegionCount: preambleRegions.length,
20163
+ callSite,
20164
+ flatMapLeafItem,
20165
+ anchored,
20166
+ scope
20167
+ }) ?? undefined;
20168
+ const mapPreambleWrappedFinal = !lazyRow && loop.index ? wrapIndexParamAsAccessor(mapPreambleWrapped, loop.index) : mapPreambleWrapped;
20169
+ const templateFinal = !lazyRow && loop.index ? wrapIndexParamAsAccessor(loop.template, loop.index) : loop.template;
20170
+ return {
20171
+ indexParam,
20172
+ paramHead,
20173
+ paramUnwrap,
20174
+ preambleRegions,
20175
+ lazyRow,
20176
+ mapPreambleWrapped: mapPreambleWrappedFinal,
20177
+ template: templateFinal,
20178
+ wrapItem
20179
+ };
20180
+ }
20181
+
20039
20182
  // ../jsx/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts
20040
20183
  function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
20041
20184
  const containerSlotId = loop.containerSlotId;
@@ -20050,16 +20193,18 @@ function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
20050
20193
  };
20051
20194
  return composite;
20052
20195
  }
20053
- const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
20054
20196
  const hasReactiveEffects = loop.bindings.reactiveAttrs.length > 0 || loop.bindings.reactiveTexts.length > 0 || loop.bindings.conditionals.length > 0;
20055
20197
  const fm = loop.flatMapClient;
20056
20198
  const arrayExpr = fm ? `(${buildChainedArrayExpr(loop)}).flatMap(${fm.params} => ${fm.body})` : buildChainedArrayExpr(loop);
20057
- const indexParam = loop.index || "__idx";
20058
- const mapPreambleWrapped = loop.preamble ? renderPreamble(loop.preamble, {
20059
- transformJs: (t) => wrapLoopParamAsAccessor(t, loop.param, loop.paramBindings),
20060
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: loop.param, bindings: loop.paramBindings }], undefined)
20061
- }) : "";
20062
- const preambleRegions = buildPreambleRegionPlans(loop.preambleRegions, loop.param, loop.paramBindings);
20199
+ const core = buildPlainRowCore({
20200
+ loop,
20201
+ arrayExpr,
20202
+ callSite: "branch-plain",
20203
+ flatMapLeafItem: Boolean(fm),
20204
+ anchored: false,
20205
+ scope: lazyScope
20206
+ });
20207
+ const { paramHead, paramUnwrap, indexParam, preambleRegions, lazyRow } = core;
20063
20208
  const plan = {
20064
20209
  kind: "plain",
20065
20210
  rowConstruction: "string-template",
@@ -20072,30 +20217,20 @@ function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
20072
20217
  paramHead,
20073
20218
  paramUnwrap,
20074
20219
  indexParam,
20075
- mapPreambleWrapped,
20076
- lazyRow: buildLazyRowPlan({
20077
- loop,
20078
- arrayExpr,
20079
- indexParam,
20080
- paramUnwrap,
20081
- mapPreambleWrapped,
20082
- preambleRegionCount: preambleRegions.length,
20083
- callSite: "branch-plain",
20084
- flatMapLeafItem: Boolean(fm),
20085
- anchored: false,
20086
- scope: lazyScope
20087
- }) ?? undefined,
20088
- template: loop.template,
20220
+ mapPreambleWrapped: core.mapPreambleWrapped,
20221
+ lazyRow,
20222
+ template: core.template,
20089
20223
  reactiveEffects: hasReactiveEffects ? buildReactiveEffectsPlan({
20090
20224
  attrs: loop.bindings.reactiveAttrs,
20091
20225
  texts: loop.bindings.reactiveTexts,
20092
20226
  conditionals: loop.bindings.conditionals,
20093
20227
  loopParam: loop.param,
20094
20228
  loopParamBindings: loop.paramBindings,
20229
+ loopIndex: loop.index,
20095
20230
  profileComponentName
20096
20231
  }) : null,
20097
20232
  eventDelegation: buildBranchLoopDelegationPlan(loop, cv, profileComponentName),
20098
- childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings),
20233
+ childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings, loop.index),
20099
20234
  preambleRegions,
20100
20235
  bodyIsMultiRoot: loop.bodyIsMultiRoot ?? false,
20101
20236
  profileLoopId: profileComponentName ? `${profileComponentName}#binding:${containerSlotId}` : undefined
@@ -20380,7 +20515,7 @@ function emitDynamicTextUpdates(lines, ctx) {
20380
20515
  const __textSlot = (normalElems[0] ?? conditionalElems[0])?.slotId;
20381
20516
  let writer = "";
20382
20517
  if (normalElems.length > 0) {
20383
- const slots = normalElems.map((elem) => ({ id: elem.slotId, kind: "markup", path: [] }));
20518
+ const slots = normalElems.map((elem) => ({ id: elem.slotId, kind: DYNAMIC_ELEMENT_WRITER_KIND, path: [] }));
20384
20519
  writer = claimWriterVarName(slots, varSlotId);
20385
20520
  lines.push(` const ${writer} = lazySlots(__scope, ${claimPlanLiteral(slots)})`);
20386
20521
  }
@@ -20918,6 +21053,8 @@ function stringifyLazyRowLoop(lines, o) {
20918
21053
  lines.push(`${indent}${o.guardContainer ? `if (${o.containerVar}) ` : ""}${call}`);
20919
21054
  const b1 = `${indent} `;
20920
21055
  const b2 = `${indent} `;
21056
+ if (lazyRow.readsIndex)
21057
+ lines.push(`${b1}indexDriven: true,`);
20921
21058
  lines.push(`${b1}createRow: (__e, ${o.indexParam}) => {`);
20922
21059
  lines.push(`${b2}const ${paramHead} = () => __e.item`);
20923
21060
  if (lazyRow.preambleStatements)
@@ -20947,6 +21084,8 @@ function stringifyLazyRowLoop(lines, o) {
20947
21084
  } else {
20948
21085
  lines.push(`${b1}applyItem: (__e) => {`);
20949
21086
  lines.push(`${b2}const ${paramHead} = () => __e.item`);
21087
+ if (lazyRow.readsIndex)
21088
+ lines.push(`${b2}const ${o.indexParam} = __e.index`);
20950
21089
  lines.push(`${b2}const __r = __e.refs ?? (__e.refs = [])`);
20951
21090
  lines.push(`${b2}const __l = __e.last ?? (__e.last = [])`);
20952
21091
  if (lazyRow.itemNeedsPreamble && lazyRow.preambleStatements) {
@@ -20973,6 +21112,8 @@ function stringifyLazyRowLoop(lines, o) {
20973
21112
  lines.push(`${b2}${g}()`);
20974
21113
  lines.push(`${b2}for (const __e of __es) {`);
20975
21114
  lines.push(`${b3}const ${paramHead} = () => __e.item`);
21115
+ if (lazyRow.readsIndex)
21116
+ lines.push(`${b3}const ${o.indexParam} = __e.index`);
20976
21117
  lines.push(`${b3}const __r = __e.refs ?? (__e.refs = [])`);
20977
21118
  lines.push(`${b3}const __l = __e.last ?? (__e.last = [])`);
20978
21119
  if (lazyRow.outerNeedsPreamble && lazyRow.preambleStatements) {
@@ -21497,6 +21638,7 @@ function stringifyCompositeLoop(lines, plan) {
21497
21638
  innerLoops,
21498
21639
  loopParam,
21499
21640
  loopParamBindings,
21641
+ loopIndex,
21500
21642
  reactiveEffects,
21501
21643
  childRefs,
21502
21644
  branchClearChildren,
@@ -21529,7 +21671,7 @@ function stringifyCompositeLoop(lines, plan) {
21529
21671
  singleRootLayout: "multiline",
21530
21672
  mountRow: true
21531
21673
  });
21532
- emitComponentAndEventSetup(lines, bodyIndent, "__el", compsArr, eventsArr, loopParam, loopParamBindings, bodyIsMultiRoot);
21674
+ emitComponentAndEventSetup(lines, bodyIndent, "__el", compsArr, eventsArr, loopParam, loopParamBindings, bodyIsMultiRoot, loopIndex);
21533
21675
  if (innerLoops.length > 0) {
21534
21676
  stringifyInnerLoops(lines, innerLoops, bodyIndent, pc);
21535
21677
  }
@@ -21951,11 +22093,11 @@ function scopeRefToVar(ref) {
21951
22093
  // ../jsx/src/ir-to-client-js/control-flow/plan/build-component-loop.ts
21952
22094
  function buildComponentLoopPlan(elem, profileComponentName) {
21953
22095
  const { name } = elem.childComponent;
21954
- const propsExpr = buildComponentPropsExpr2(elem.childComponent, elem.param);
21955
- const keyExpr = wrapLoopParamAsAccessor(elem.key || "__idx", elem.param, elem.paramBindings);
22096
+ const propsExpr = buildComponentPropsExpr2(elem.childComponent, elem.param, undefined, elem.index);
22097
+ const keyExpr = wrapLoopParamAsAccessor(elem.key || "__idx", elem.param, elem.paramBindings, elem.index);
21956
22098
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
21957
22099
  const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
21958
- transformJs: (text) => wrapLoopParamAsAccessor(text, elem.param, elem.paramBindings),
22100
+ transformJs: (text) => wrapLoopParamAsAccessor(text, elem.param, elem.paramBindings, elem.index),
21959
22101
  renderLeaf: () => {
21960
22102
  internalInvariant(false, "component-root loop received a JSX-bearing preamble — Phase 1 should have refused it");
21961
22103
  }
@@ -21965,12 +22107,12 @@ function buildComponentLoopPlan(elem, profileComponentName) {
21965
22107
  const isTextOnly = comp.children?.length ? comp.children.every((c) => c.type === "expression" || c.type === "text" || isTextOnlyConditional(c)) : false;
21966
22108
  const rawChildrenExpr = isTextOnly ? irChildrenToJsExpr(comp.children) : null;
21967
22109
  const childrenFreeIds = isTextOnly && comp.children ? irChildrenFreeIds(comp.children) : undefined;
21968
- const childrenRefsLoop = rawChildrenExpr != null && childrenFreeIds != null && childrenFreeIds.has(elem.param);
22110
+ const childrenRefsLoop = rawChildrenExpr != null && childrenFreeIds != null && (childrenFreeIds.has(elem.param) || !!elem.index && childrenFreeIds.has(elem.index));
21969
22111
  return {
21970
22112
  componentName: comp.name,
21971
22113
  selector: buildCompSelector(comp),
21972
- propsExpr: buildComponentPropsExpr2(comp, elem.param),
21973
- childrenTextEffect: childrenRefsLoop ? { wrappedChildren: wrapLoopParamAsAccessor(rawChildrenExpr, elem.param, elem.paramBindings) } : null
22114
+ propsExpr: buildComponentPropsExpr2(comp, elem.param, undefined, elem.index),
22115
+ childrenTextEffect: childrenRefsLoop ? { wrappedChildren: wrapLoopParamAsAccessor(rawChildrenExpr, elem.param, elem.paramBindings, elem.index) } : null
21974
22116
  };
21975
22117
  });
21976
22118
  const hasChildConds = elem.bindings.conditionals.length > 0;
@@ -21989,7 +22131,7 @@ function buildComponentLoopPlan(elem, profileComponentName) {
21989
22131
  componentPropsExpr: propsExpr,
21990
22132
  keyExpr,
21991
22133
  nestedComps,
21992
- childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
22134
+ childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings, elem.index),
21993
22135
  profileLoopId: profileComponentName ? `${profileComponentName}#binding:${elem.slotId}` : undefined,
21994
22136
  childConditionalEffects: hasChildConds ? buildReactiveEffectsPlan({
21995
22137
  attrs: [],
@@ -21997,6 +22139,7 @@ function buildComponentLoopPlan(elem, profileComponentName) {
21997
22139
  conditionals: elem.bindings.conditionals,
21998
22140
  loopParam: elem.param,
21999
22141
  loopParamBindings: elem.paramBindings,
22142
+ loopIndex: elem.index,
22000
22143
  profileComponentName
22001
22144
  }) : null
22002
22145
  };
@@ -22020,8 +22163,6 @@ function buildLoopPlan(elem, opts) {
22020
22163
  return buildPlainLoopPlan(elem, opts.profileComponentName, opts.lazyScope);
22021
22164
  }
22022
22165
  function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
22023
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings);
22024
- const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
22025
22166
  const hasReactive2 = elem.bindings.reactiveAttrs.length > 0 || elem.bindings.reactiveTexts.length > 0 || elem.bindings.conditionals.length > 0;
22026
22167
  if (elem.flatMapClient) {
22027
22168
  return {
@@ -22047,12 +22188,15 @@ function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
22047
22188
  };
22048
22189
  }
22049
22190
  const arrayExpr = buildChainedArrayExpr(elem);
22050
- const indexParam = elem.index || "__idx";
22051
- const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
22052
- transformJs: wrap,
22053
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings }], undefined)
22054
- }) : "";
22055
- const preambleRegions = buildPreambleRegionPlans(elem.preambleRegions, elem.param, elem.paramBindings);
22191
+ const core = buildPlainRowCore({
22192
+ loop: elem,
22193
+ arrayExpr,
22194
+ callSite: "plain",
22195
+ flatMapLeafItem: false,
22196
+ anchored: elem.bodyIsItemConditional ?? false,
22197
+ scope: lazyScope
22198
+ });
22199
+ const { paramHead, paramUnwrap, indexParam, preambleRegions, lazyRow, wrapItem: wrap } = core;
22056
22200
  return {
22057
22201
  kind: "plain",
22058
22202
  rowConstruction: "string-template",
@@ -22064,28 +22208,17 @@ function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
22064
22208
  paramHead,
22065
22209
  paramUnwrap,
22066
22210
  indexParam,
22067
- lazyRow: buildLazyRowPlan({
22068
- loop: elem,
22069
- arrayExpr,
22070
- indexParam,
22071
- paramUnwrap,
22072
- mapPreambleWrapped,
22073
- preambleRegionCount: preambleRegions.length,
22074
- callSite: "plain",
22075
- flatMapLeafItem: false,
22076
- anchored: elem.bodyIsItemConditional ?? false,
22077
- scope: lazyScope
22078
- }) ?? undefined,
22079
- mapPreambleWrapped,
22080
- template: elem.template,
22211
+ lazyRow,
22212
+ mapPreambleWrapped: core.mapPreambleWrapped,
22213
+ template: core.template,
22081
22214
  skeletonTemplate: elem.skeletonTemplate,
22082
22215
  skeletonPaths: elem.skeletonPaths,
22083
22216
  reactiveEffects: hasReactive2 ? buildLoopReactiveEffectsPlan(elem, profileComponentName) : null,
22084
- childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
22217
+ childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings, elem.index),
22085
22218
  preambleRegions,
22086
22219
  bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false,
22087
22220
  anchored: elem.bodyIsItemConditional ?? false,
22088
- anchorKeyExpr: elem.key ? wrap(elem.key) : elem.index || "__idx"
22221
+ anchorKeyExpr: elem.key ? wrap(elem.key) : `${indexParam}()`
22089
22222
  };
22090
22223
  }
22091
22224
  function buildStaticLoopPlan(elem, unsafeLocalNames, profileComponentName) {
@@ -22127,7 +22260,7 @@ function buildStaticLoopMaterialize(elem, unsafeLocalNames) {
22127
22260
  return {
22128
22261
  itemTemplate: elem.staticItemTemplate,
22129
22262
  mapPreamble: elem.preamble ? renderPreamble(elem.preamble, {
22130
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings }], undefined)
22263
+ renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings, index: elem.index }], undefined)
22131
22264
  }) : "",
22132
22265
  bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false
22133
22266
  };
@@ -22703,7 +22836,7 @@ function generateTemplateOnlyMount(ir, ctx) {
22703
22836
  const restSpreadNames = resolveRestSpreadNames(ctx);
22704
22837
  let templateHtml;
22705
22838
  if (canGenerateStaticTemplate(ir.root, propNamesForStaticCheck, inlinableConstants, unsafeLocalNames)) {
22706
- const markupSlotIds = new Set(ctx.dynamicElements.map((e) => e.slotId));
22839
+ const markupSlotIds = markupSlotIdsOf(ctx);
22707
22840
  templateHtml = irToComponentTemplate(ir.root, inlinableConstants, restSpreadNames, ctx.propsObjectName, markupSlotIds, ctx.restPropsName);
22708
22841
  }
22709
22842
  if (!templateHtml) {
@@ -23421,6 +23554,21 @@ function extractSsrDefaults(metadata) {
23421
23554
  }
23422
23555
  bindings[memo.name] = value;
23423
23556
  }
23557
+ {
23558
+ const getterNames = collectAliasableGetterNames(metadata.signals, metadata.memos);
23559
+ for (const [alias, origin] of resolveGetterAliases(metadata.localConstants ?? [], (n) => getterNames.has(n))) {
23560
+ if (alias in out)
23561
+ continue;
23562
+ out[alias] = out[origin];
23563
+ }
23564
+ }
23565
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(metadata.localConstants ?? [], metadata.propsObjectName)) {
23566
+ if (local in out)
23567
+ continue;
23568
+ const origin = out[callerKey];
23569
+ if (origin)
23570
+ out[local] = origin;
23571
+ }
23424
23572
  if (metadata.propsObjectName !== null) {
23425
23573
  const referenced = new Set;
23426
23574
  for (const sig of metadata.signals) {