@barefootjs/vite 0.34.0 → 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 +341 -215
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -2473,12 +2473,22 @@ function renderLoopBindingAccess(b, base) {
2473
2473
  }
2474
2474
  return parent;
2475
2475
  }
2476
- function wrapLoopParamAsAccessor(expr, paramName, bindings) {
2476
+ function wrapLoopParamAsAccessor(expr, paramName, bindings, indexParam) {
2477
+ let result;
2477
2478
  if (bindings && bindings.length > 0) {
2478
- 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}()`);
2483
+ }
2484
+ if (indexParam && indexParam !== paramName) {
2485
+ result = wrapIndexParamAsAccessor(result, indexParam);
2479
2486
  }
2480
- const re = new RegExp(`${ID_BOUNDARY_BEFORE}${escapeIdentifierForRegex(paramName)}(?!\\s*\\()(?!-)${ID_BOUNDARY_AFTER}`, "gu");
2481
- return replaceInExprContexts(expr, re, () => `${paramName}()`);
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}()`);
2482
2492
  }
2483
2493
  function rewriteLoopBindingRefs(expr, bindings, accessor) {
2484
2494
  const byName = new Map;
@@ -2525,7 +2535,7 @@ function wrapExprWithLoopParams(expr, loopParams) {
2525
2535
  let result = expr;
2526
2536
  for (const p of loopParams) {
2527
2537
  const spec = typeof p === "string" ? { param: p } : p;
2528
- result = wrapLoopParamAsAccessor(result, spec.param, spec.bindings);
2538
+ result = wrapLoopParamAsAccessor(result, spec.param, spec.bindings, spec.index);
2529
2539
  }
2530
2540
  return result;
2531
2541
  }
@@ -2808,6 +2818,20 @@ function buildPropAliasMap(params) {
2808
2818
  }
2809
2819
  return map;
2810
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
+ }
2811
2835
  function boundPropLocalNames(b) {
2812
2836
  if (b.propsObjectName !== null)
2813
2837
  return EMPTY_SET;
@@ -3040,6 +3064,18 @@ function resolveGetterAliases(localConstants, isGetter) {
3040
3064
  }
3041
3065
  return aliases;
3042
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
+ }
3043
3079
  function buildSignalMemoEnv(signals, memos, propsObjectName, localConstants = []) {
3044
3080
  const substitutions = new Map;
3045
3081
  for (const s of signals) {
@@ -3216,6 +3252,65 @@ class BindingScope {
3216
3252
  }
3217
3253
  }
3218
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
+
3219
3314
  // ../jsx/src/ir-to-client-js/html-template.ts
3220
3315
  function createStringProtector() {
3221
3316
  const strings = [];
@@ -3385,22 +3480,11 @@ function templateAttrExpr(attrName, valExpr, presenceOrUndefined) {
3385
3480
  function escapeAttrValueExpr(valExpr) {
3386
3481
  return `escapeAttr(${valExpr})`;
3387
3482
  }
3388
- function escapeTextSlotExpr(innerExpr, isMarkup = false) {
3389
- return `${isMarkup ? "escapeTextOrMarkup" : "escapeText"}(${innerExpr})`;
3390
- }
3391
- function isChildrenPassthroughExpr(expr) {
3392
- return /^([A-Za-z_$][\w$]*\.)?children$/.test(expr.trim());
3393
- }
3394
- function bareSpliceExpr(node, valueExpr) {
3395
- const resolved = valueExpr.trim().replace(/^\(+|\)+$/g, "");
3396
- const isChildren = isChildrenPassthroughExpr(node.expr) || isChildrenPassthroughExpr(resolved);
3397
- return !node.joinArrayChild && isChildren ? `markupOrEmpty(${valueExpr})` : valueExpr;
3398
- }
3399
3483
  function dangerouslyHtmlChildren(attrs, toExpr) {
3400
3484
  const attr = attrs.find((a) => a.name === "dangerouslySetInnerHTML");
3401
3485
  if (!attr || attr.value.kind !== "expression")
3402
3486
  return null;
3403
- return `\${((${toExpr(attr.value)}) ?? {}).__html ?? ''}`;
3487
+ return interp(dangerousInnerHtml(toExpr(attr.value)));
3404
3488
  }
3405
3489
  function transformKeyValue(value, transformExpr) {
3406
3490
  switch (value.kind) {
@@ -3516,7 +3600,7 @@ function buildSpreadAttrsMergeCall(args) {
3516
3600
  return `\${spreadAttrs({${objMembers.join(", ")}})}`;
3517
3601
  }
3518
3602
  function itemAnchorTemplate(keyExpr) {
3519
- return `<!--${loopItemMarker("${" + keyExpr + "}")}-->`;
3603
+ return `<!--${loopItemMarker("${escapeCommentText(" + keyExpr + ")}")}-->`;
3520
3604
  }
3521
3605
  function renderPreamble(preamble, opts) {
3522
3606
  let out = "";
@@ -3525,9 +3609,9 @@ function renderPreamble(preamble, opts) {
3525
3609
  const text = opts.textVariant === "template" ? seg.templateText ?? seg.text : seg.text;
3526
3610
  out += opts.transformJs ? opts.transformJs(text) : text;
3527
3611
  } else if (opts.rawLeaf) {
3528
- out += opts.renderLeaf(escapeLeafTextExpressions(seg.ir));
3612
+ out += opts.renderLeaf(seg.ir);
3529
3613
  } else {
3530
- out += "`" + opts.renderLeaf(escapeLeafTextExpressions(seg.ir)) + "`";
3614
+ out += "`" + opts.renderLeaf(seg.ir) + "`";
3531
3615
  }
3532
3616
  }
3533
3617
  return out;
@@ -3572,36 +3656,12 @@ function renderFlatMapProjectionClientBody(inner, restSpreadNames) {
3572
3656
  const chained = applyLoopChain(inner);
3573
3657
  const params = inner.index ? `(${inner.param}, ${inner.index})` : `(${inner.param})`;
3574
3658
  const key = inner.key ? `(${inner.key})` : "undefined";
3575
- 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("");
3576
3660
  return `${chained}.map(${params} => ({ k: ${key}, h: \`${html}\` }))`;
3577
3661
  }
3578
- function escapeLeafTextExpressions(ir) {
3579
- switch (ir.type) {
3580
- case "element":
3581
- return { ...ir, children: ir.children.map(escapeLeafTextExpressions) };
3582
- case "fragment":
3583
- return { ...ir, children: ir.children.map(escapeLeafTextExpressions) };
3584
- case "expression": {
3585
- if (ir.expr === "null" || ir.expr === "undefined")
3586
- return ir;
3587
- if (ir.slotId || ir.expr.trimStart().startsWith("escapeText("))
3588
- return ir;
3589
- return { ...ir, expr: `escapeText((${ir.expr}))`, templateExpr: ir.templateExpr ? `escapeText((${ir.templateExpr}))` : ir.templateExpr };
3590
- }
3591
- case "conditional":
3592
- return {
3593
- ...ir,
3594
- whenTrue: escapeLeafTextExpressions(ir.whenTrue),
3595
- whenFalse: ir.whenFalse ? escapeLeafTextExpressions(ir.whenFalse) : ir.whenFalse
3596
- };
3597
- default:
3598
- return ir;
3599
- }
3600
- }
3601
3662
  function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, branchSlotsVar, inHoistedChildren = false) {
3602
3663
  const recurse = (n) => irToHtmlTemplate(n, restSpreadNames, loopDepth, loopParams, branchSlotsVar, inHoistedChildren);
3603
3664
  const wrapExpr = (expr) => wrapExprWithLoopParams(expr, loopParams);
3604
- const wrapInterpolation = (expr) => branchSlotsVar ? `__bfSlot(${expr}, ${branchSlotsVar})` : expr;
3605
3665
  switch (node.type) {
3606
3666
  case "element": {
3607
3667
  const mergeCtx = {
@@ -3647,25 +3707,17 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3647
3707
  case "expression": {
3648
3708
  if (node.expr === "null" || node.expr === "undefined")
3649
3709
  return "";
3650
- const escapeForClient = (e) => node.escapeInClientTemplate ? `escapeText(${e})` : e;
3651
- if (node.markerless) {
3652
- const bare = escapeForClient(wrapInterpolation(wrapExpr(node.expr)));
3653
- return `\${${bare}}`;
3654
- }
3655
- const inner = escapeForClient(wrapInterpolation(wrapExpr(node.expr)));
3656
- const valueExpr = node.joinArrayChild ? `Array.isArray(${inner}) ? ${inner}.join('') : (${inner} ?? '')` : inner;
3657
- if (node.slotId) {
3658
- const slotted = branchSlotsVar || node.joinArrayChild ? valueExpr : escapeTextSlotExpr(valueExpr);
3659
- return `<!--bf:${node.slotId}-->\${${slotted}}<!--/-->`;
3660
- }
3661
- 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;
3662
3714
  }
3663
3715
  case "conditional": {
3664
3716
  const trueBranch = recurse(node.whenTrue);
3665
3717
  const falseBranch = recurse(node.whenFalse);
3666
3718
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
3667
3719
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
3668
- return `\${${wrapExpr(node.condition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
3720
+ return interp(conditionalMarkup(wrapExpr(node.condition), trueHtml, falseHtml));
3669
3721
  }
3670
3722
  case "fragment":
3671
3723
  return node.children.map(recurse).join("");
@@ -3702,7 +3754,7 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3702
3754
  const propsExpr = propsEntries.length > 0 ? `{${propsEntries.join(", ")}}` : "{}";
3703
3755
  const keyProp = node.props.find((p) => p.name === "key");
3704
3756
  const keyArg = keyProp ? `, ${attrValueToString(keyProp.value) ?? "undefined"}` : "";
3705
- return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${renderChildScopeArgs(node, keyArg)})}`;
3757
+ return interp(renderChildCall(nameForRegistryRef(node.name), propsExpr, renderChildScopeArgs(node, keyArg)));
3706
3758
  }
3707
3759
  case "loop": {
3708
3760
  const innerRecurse = (n) => irToHtmlTemplate(n, restSpreadNames, loopDepth + 1, loopParams, branchSlotsVar);
@@ -3720,12 +3772,12 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3720
3772
  const body = renderPreamble(node.flatMapCallback, {
3721
3773
  renderLeaf: (ir) => irToHtmlTemplate(stripLeafKeyAttr(ir), restSpreadNames, loopDepth + 1, loopParams, branchSlotsVar)
3722
3774
  });
3723
- mapExpr = `\${${wrappedArray}.flatMap(${node.flatMapCallback.params} => ${body}).join('')}`;
3775
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, "flatMap", node.flatMapCallback.params, body));
3724
3776
  } else if (node.preamble) {
3725
3777
  const preamble = renderPreamble(node.preamble, { textVariant: "client", renderLeaf: (ir) => irToHtmlTemplate(ir, restSpreadNames, loopDepth + 1, loopParams, branchSlotsVar) });
3726
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => { ${preamble} return \`${childTemplate}\` }).join('')}`;
3778
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `{ ${preamble} return \`${childTemplate}\` }`));
3727
3779
  } else {
3728
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => \`${childTemplate}\`).join('')}`;
3780
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `\`${childTemplate}\``));
3729
3781
  }
3730
3782
  return `<!--${loopStartMarker(node.markerId)}-->${mapExpr}<!--${loopEndMarker(node.markerId)}-->`;
3731
3783
  }
@@ -3984,20 +4036,15 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
3984
4036
  case "expression": {
3985
4037
  if (node.expr === "null" || node.expr === "undefined")
3986
4038
  return "";
3987
- const wrapped = wrapExpr(node.expr);
3988
- const value = node.joinArrayChild ? `Array.isArray(${wrapped}) ? ${wrapped}.join('') : (${wrapped} ?? '')` : wrapped;
3989
- if (node.slotId) {
3990
- return `<!--bf:${node.slotId}-->\${${node.joinArrayChild ? value : escapeTextSlotExpr(wrapped)}}<!--/-->`;
3991
- }
3992
- const spliced = bareSpliceExpr(node, value);
3993
- return `\${${node.escapeInClientTemplate ? `escapeText(${spliced})` : spliced}}`;
4039
+ const hole = interp(spliceChildValue(node, wrapExpr(node.expr), {}));
4040
+ return node.slotId ? `<!--bf:${node.slotId}-->${hole}<!--/-->` : hole;
3994
4041
  }
3995
4042
  case "conditional": {
3996
4043
  const trueBranch = recurse(node.whenTrue);
3997
4044
  const falseBranch = recurse(node.whenFalse);
3998
4045
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
3999
4046
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
4000
- return `\${${wrapExpr(node.condition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
4047
+ return interp(conditionalMarkup(wrapExpr(node.condition), trueHtml, falseHtml));
4001
4048
  }
4002
4049
  case "fragment":
4003
4050
  return node.children.map(recurse).join("");
@@ -4021,12 +4068,12 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
4021
4068
  const body = renderPreamble(node.flatMapCallback, {
4022
4069
  renderLeaf: (ir) => irToPlaceholderTemplate(stripLeafKeyAttr(ir), restSpreadNames, loopDepth + 1, loopParams)
4023
4070
  });
4024
- mapExpr = `\${${wrappedArray}.flatMap(${node.flatMapCallback.params} => ${body}).join('')}`;
4071
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, "flatMap", node.flatMapCallback.params, body));
4025
4072
  } else if (node.preamble) {
4026
4073
  const preamble = renderPreamble(node.preamble, { textVariant: "client", renderLeaf: (ir) => irToPlaceholderTemplate(ir, restSpreadNames, loopDepth + 1, loopParams) });
4027
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => { ${preamble} return \`${childTemplate}\` }).join('')}`;
4074
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `{ ${preamble} return \`${childTemplate}\` }`));
4028
4075
  } else {
4029
- mapExpr = `\${${wrappedArray}.${iterMethod}(${callbackParam} => \`${childTemplate}\`).join('')}`;
4076
+ mapExpr = interp(mappedRowsMarkup(wrappedArray, iterMethod, callbackParam, `\`${childTemplate}\``));
4030
4077
  }
4031
4078
  return `<!--${loopStartMarker(node.markerId)}-->${mapExpr}<!--${loopEndMarker(node.markerId)}-->`;
4032
4079
  }
@@ -4228,13 +4275,8 @@ function irToComponentTemplateWithOpts(node, opts) {
4228
4275
  return "";
4229
4276
  return `<!--bf:${node.slotId}--><!--/-->`;
4230
4277
  }
4231
- const wrapped = transformExpr(node.expr, node.templateExpr);
4232
- const value = node.joinArrayChild ? `Array.isArray(${wrapped}) ? ${wrapped}.join('') : (${wrapped} ?? '')` : wrapped;
4233
- if (node.slotId) {
4234
- const isMarkup = opts.markupSlotIds?.has(node.slotId) ?? false;
4235
- return `<!--bf:${node.slotId}-->\${${node.joinArrayChild ? value : escapeTextSlotExpr(wrapped, isMarkup)}}<!--/-->`;
4236
- }
4237
- 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;
4238
4280
  }
4239
4281
  case "conditional": {
4240
4282
  if (node.clientOnly && node.slotId) {
@@ -4244,7 +4286,7 @@ function irToComponentTemplateWithOpts(node, opts) {
4244
4286
  const falseBranch = recurse(node.whenFalse);
4245
4287
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
4246
4288
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
4247
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
4289
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), trueHtml, falseHtml));
4248
4290
  }
4249
4291
  case "fragment":
4250
4292
  return node.children.map(recurse).join("");
@@ -4282,7 +4324,7 @@ function irToComponentTemplateWithOpts(node, opts) {
4282
4324
  const propsExpr = propsEntries.length > 0 ? `{${propsEntries.join(", ")}}` : "{}";
4283
4325
  const keyProp = node.props.find((p) => p.name === "key");
4284
4326
  const keyArg = keyProp ? `, ${transformKeyValue(keyProp.value, transformExpr)}` : "";
4285
- return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${keyArg})}`;
4327
+ return interp(renderChildCall(nameForRegistryRef(node.name), propsExpr, keyArg));
4286
4328
  }
4287
4329
  case "loop": {
4288
4330
  const innerOpts = { ...opts, loopDepth: loopDepth + 1 };
@@ -4292,7 +4334,7 @@ function irToComponentTemplateWithOpts(node, opts) {
4292
4334
  case "if-statement": {
4293
4335
  const consequent = recurse(node.consequent);
4294
4336
  const alternate = node.alternate ? recurse(node.alternate) : "";
4295
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${consequent}\` : \`${alternate}\`}`;
4337
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), consequent, alternate));
4296
4338
  }
4297
4339
  case "provider":
4298
4340
  case "async":
@@ -4380,7 +4422,7 @@ function generateCsrTemplate(node, inlinableConstants, ctx, restSpreadNames, pro
4380
4422
  }
4381
4423
  }
4382
4424
  const effectiveUnsafeLocalNames = mergeCsrNullUnsafe(ctx, unsafeLocalNames);
4383
- const markupSlotIds = new Set(ctx.dynamicElements.map((e) => e.slotId));
4425
+ const markupSlotIds = markupSlotIdsOf(ctx);
4384
4426
  return generateCsrTemplateWithOpts(node, { inlinableConstants, restSpreadNames, propsObjectName, csrEnv, unsafeLocalNames: effectiveUnsafeLocalNames, deferredChildSlots, loopDepth: -1, markupSlotIds, restPropsName: ctx.restPropsName });
4385
4427
  }
4386
4428
  function mergeCsrNullUnsafe(ctx, unsafeLocalNames) {
@@ -4579,13 +4621,8 @@ function generateCsrTemplateWithOpts(node, opts) {
4579
4621
  }
4580
4622
  {
4581
4623
  const transformed = transformExpr(node.expr, node.templateExpr);
4582
- const expr = transformed === UNSAFE_TEMPLATE_EXPR ? "''" : transformed;
4583
- const value = node.joinArrayChild ? `Array.isArray(${expr}) ? ${expr}.join('') : (${expr} ?? '')` : expr;
4584
- if (node.slotId) {
4585
- const isMarkup = opts.markupSlotIds?.has(node.slotId) ?? false;
4586
- return `<!--bf:${node.slotId}-->\${${node.joinArrayChild ? value : escapeTextSlotExpr(expr, isMarkup)}}<!--/-->`;
4587
- }
4588
- 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;
4589
4626
  }
4590
4627
  case "conditional": {
4591
4628
  if (node.clientOnly && node.slotId) {
@@ -4595,7 +4632,7 @@ function generateCsrTemplateWithOpts(node, opts) {
4595
4632
  const falseBranch = recurse(node.whenFalse);
4596
4633
  const trueHtml = node.slotId ? addCondAttrToTemplate(trueBranch, node.slotId) : trueBranch;
4597
4634
  const falseHtml = node.slotId ? addCondAttrToTemplate(falseBranch, node.slotId) : falseBranch;
4598
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${trueHtml}\` : \`${falseHtml}\`}`;
4635
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), trueHtml, falseHtml));
4599
4636
  }
4600
4637
  case "fragment":
4601
4638
  return node.children.map(recurse).join("");
@@ -4644,7 +4681,7 @@ function generateCsrTemplateWithOpts(node, opts) {
4644
4681
  const propsExpr = propsEntries.length > 0 ? `{${propsEntries.join(", ")}}` : "{}";
4645
4682
  const keyProp = node.props.find((p) => p.name === "key");
4646
4683
  const keyArg = keyProp ? `, ${transformKeyValue(keyProp.value, transformExpr)}` : "";
4647
- return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${renderChildScopeArgs(node, keyArg)})}`;
4684
+ return interp(renderChildCall(nameForRegistryRef(node.name), propsExpr, renderChildScopeArgs(node, keyArg)));
4648
4685
  }
4649
4686
  case "loop": {
4650
4687
  const childScope = (opts.scope ?? BindingScope.EMPTY).enterLoopRow(node);
@@ -4677,19 +4714,19 @@ function generateCsrTemplateWithOpts(node, opts) {
4677
4714
  transformJs: (t) => rewritePropsObjectRef(t, propsObjectName ?? null, restPropsName ?? null, { enclosingScope: childScope }),
4678
4715
  renderLeaf: (ir) => recurseInLoopBody(stripLeafKeyAttr(ir))
4679
4716
  });
4680
- mapExpr = `\${${iterArrayExpr}.flatMap(${node.flatMapCallback.params} => ${body}).join('')}`;
4717
+ mapExpr = interp(mappedRowsMarkup(iterArrayExpr, "flatMap", node.flatMapCallback.params, body));
4681
4718
  } else if (node.preamble) {
4682
4719
  const preamble = renderPreamble(node.preamble, { textVariant: "template", transformJs: (t) => rewritePropsObjectRef(t, propsObjectName ?? null, restPropsName ?? null, { enclosingScope: childScope }), renderLeaf: (ir) => recurseInLoopBody(ir) });
4683
- mapExpr = `\${${iterArrayExpr}.${iterMethod}(${callbackParam} => { ${preamble} return \`${childTemplate}\` }).join('')}`;
4720
+ mapExpr = interp(mappedRowsMarkup(iterArrayExpr, iterMethod, callbackParam, `{ ${preamble} return \`${childTemplate}\` }`));
4684
4721
  } else {
4685
- mapExpr = `\${${iterArrayExpr}.${iterMethod}(${callbackParam} => \`${childTemplate}\`).join('')}`;
4722
+ mapExpr = interp(mappedRowsMarkup(iterArrayExpr, iterMethod, callbackParam, `\`${childTemplate}\``));
4686
4723
  }
4687
4724
  return `<!--${loopStartMarker(node.markerId)}-->${mapExpr}<!--${loopEndMarker(node.markerId)}-->`;
4688
4725
  }
4689
4726
  case "if-statement": {
4690
4727
  const consequent = recurse(node.consequent);
4691
4728
  const alternate = node.alternate ? recurse(node.alternate) : "";
4692
- return `\${${transformExpr(node.condition, node.templateCondition)} ? \`${consequent}\` : \`${alternate}\`}`;
4729
+ return interp(conditionalMarkup(transformExpr(node.condition, node.templateCondition), consequent, alternate));
4693
4730
  }
4694
4731
  case "provider":
4695
4732
  case "async":
@@ -4790,8 +4827,6 @@ function collectAstPropRefs(node, propNames, out) {
4790
4827
  walkWithScope(node, (n, parent, shadowed) => {
4791
4828
  if (shadowed || !propNames.has(n.text))
4792
4829
  return;
4793
- if (parent && ts7.isShorthandPropertyAssignment(parent) && parent.name === n)
4794
- return;
4795
4830
  if (isNonValuePosition(n, parent))
4796
4831
  return;
4797
4832
  out.add(n.text);
@@ -6686,6 +6721,7 @@ var CLIENT_EXPORTS = new Set([
6686
6721
  "isSSRPortal",
6687
6722
  "findSiblingSlot",
6688
6723
  "cleanupPortalPlaceholder",
6724
+ "trackPosition",
6689
6725
  "createSearchParams",
6690
6726
  "queryHref",
6691
6727
  "formatDate",
@@ -8005,7 +8041,8 @@ var BROWSER_ONLY_CLIENT_APIS = new Set([
8005
8041
  "createPortal",
8006
8042
  "isSSRPortal",
8007
8043
  "findSiblingSlot",
8008
- "cleanupPortalPlaceholder"
8044
+ "cleanupPortalPlaceholder",
8045
+ "trackPosition"
8009
8046
  ]);
8010
8047
  function importsBrowserOnlyClientApi(ctx) {
8011
8048
  for (const imp of ctx.imports) {
@@ -10213,9 +10250,8 @@ function collectBranchLocalPropRefsViaSubstitution(node, ctx) {
10213
10250
  function visit2(n, parent) {
10214
10251
  if (ts14.isIdentifier(n) && propDepsMap.has(n.text)) {
10215
10252
  const isObjectKey = parent && ts14.isPropertyAssignment(parent) && parent.name === n;
10216
- const isShorthand = parent && ts14.isShorthandPropertyAssignment(parent) && parent.name === n;
10217
10253
  const isAccessName = parent && ts14.isPropertyAccessExpression(parent) && parent.name === n;
10218
- if (!isObjectKey && !isShorthand && !isAccessName) {
10254
+ if (!isObjectKey && !isAccessName) {
10219
10255
  const deps = propDepsMap.get(n.text);
10220
10256
  if (deps && deps.size > 0) {
10221
10257
  if (!acc)
@@ -10693,8 +10729,7 @@ function lowerFormControlValueSsr(tagName, attrs, children) {
10693
10729
  children.push({
10694
10730
  type: "expression",
10695
10731
  expr,
10696
- templateExpr: `escapeText(${templateExpr ?? expr})`,
10697
- escapeInClientTemplate: true,
10732
+ templateExpr,
10698
10733
  typeInfo: null,
10699
10734
  reactive: false,
10700
10735
  slotId: null,
@@ -10705,26 +10740,76 @@ function lowerFormControlValueSsr(tagName, attrs, children) {
10705
10740
  }
10706
10741
  const selectedForLiteral = (optValue) => AttrValueOf.expression(`(${expr}) === ${JSON.stringify(optValue)}`, templateExpr !== undefined ? { templateExpr: `(${templateExpr}) === ${JSON.stringify(optValue)}` } : undefined);
10707
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;
10708
10745
  const distribute = (nodes) => {
10709
10746
  for (const n of nodes) {
10747
+ if (n.type === "text")
10748
+ continue;
10710
10749
  if (n.type === "element" && n.tag === "option") {
10711
- if (n.attrs.some((a) => a.name === "selected"))
10750
+ if (n.attrs.some((a) => a.name === "selected")) {
10751
+ optionSetIsDynamic = true;
10712
10752
  continue;
10753
+ }
10713
10754
  const optValue = n.attrs.find((a) => a.name === "value");
10714
- if (!optValue)
10755
+ if (!optValue) {
10756
+ optionSetIsDynamic = true;
10715
10757
  continue;
10758
+ }
10716
10759
  if (optValue.value.kind === "literal") {
10717
- 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);
10718
10763
  } else if (optValue.value.kind === "expression") {
10719
10764
  const selected = selectedForExpr(optValue.value.expr, optValue.value.templateExpr);
10720
10765
  n.attrs.push({ name: "selected", value: selected, loc: n.loc });
10766
+ matchConditions.push(selected);
10767
+ } else {
10768
+ optionSetIsDynamic = true;
10721
10769
  }
10722
- } 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") {
10723
10771
  distribute(n.children);
10772
+ } else if (n.type === "loop") {
10773
+ optionSetIsDynamic = true;
10774
+ distribute(n.children);
10775
+ } else {
10776
+ optionSetIsDynamic = true;
10724
10777
  }
10725
10778
  }
10726
10779
  };
10727
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;
10728
10813
  }
10729
10814
  function transformHtmlElement(node, ctx, tagName) {
10730
10815
  const { attrs, events, ref } = processAttributes(node.openingElement.attributes, ctx);
@@ -15086,7 +15171,7 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
15086
15171
  },
15087
15172
  loop: ({ node: n, scope, descend }) => {
15088
15173
  const emitDepth = fixedDepth ?? scope.depth + 1;
15089
- 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;
15090
15175
  const template = n.children.map((c) => irToPlaceholderTemplate(c, undefined, emitDepth, loopParamsForTemplate)).join("");
15091
15176
  const refsOuter = outerLoopParam ? identifierPattern(outerLoopParam).test(n.array) : false;
15092
15177
  const bindings = emptyLoopChildBindings();
@@ -15683,7 +15768,7 @@ function collectLoopChildConditionals(node, ctx, siblingOffsets, loopParam, loop
15683
15768
  const readsPreamble = preambleNames !== undefined && preambleNames.size > 0 && anyNameIn(expanded.freeIds ?? extractFreeIdentifiersFromText(expanded.expr), preambleNames);
15684
15769
  if (!readsPreamble && classifyReactivity(expanded.expr, ctx, loopParam, loopParamBindings, expanded.freeIds).kind === "none")
15685
15770
  return;
15686
- const loopParamsForCond = loopParam ? [{ param: loopParam, bindings: loopParamBindings }] : undefined;
15771
+ const loopParamsForCond = loopParam ? [{ param: loopParam, bindings: loopParamBindings, index: loopIndex }] : undefined;
15687
15772
  const whenTrueHtml = irToHtmlTemplate(n.whenTrue, undefined, 0, loopParamsForCond, "__slots");
15688
15773
  const whenFalseHtml = irToHtmlTemplate(n.whenFalse, undefined, 0, loopParamsForCond, "__slots");
15689
15774
  conditionals.push({
@@ -16267,6 +16352,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
16267
16352
  "escapeAttr",
16268
16353
  "escapeText",
16269
16354
  "escapeTextOrNode",
16355
+ "escapeCommentText",
16270
16356
  "bfMarkup",
16271
16357
  "escapeTextOrMarkup",
16272
16358
  "markupOrEmpty",
@@ -17326,7 +17412,7 @@ function emitRegistrationAndHydration(lines, ctx, _ir, graph, inlinability) {
17326
17412
  const isCommentScope = isFragmentRoot || _ir.root.type === "component";
17327
17413
  const defParts = [`init: init${name}`];
17328
17414
  if (canGenerateStaticTemplate(_ir.root, propNamesForStaticCheck, inlinableConstants, unsafeLocalNames)) {
17329
- const markupSlotIds = new Set(ctx.dynamicElements.map((e) => e.slotId));
17415
+ const markupSlotIds = markupSlotIdsOf(ctx);
17330
17416
  const templateHtml = irToComponentTemplate(_ir.root, inlinableConstants, restSpreadNames, ctx.propsObjectName, markupSlotIds, ctx.restPropsName);
17331
17417
  if (templateHtml) {
17332
17418
  defParts.push(buildTemplateDefPart(ctx, templateHtml));
@@ -18326,12 +18412,12 @@ function nestedLoopIndexAlias(inner, syntheticIndexVar, paramHead, comps, events
18326
18412
  return null;
18327
18413
  return `const ${index} = ${syntheticIndexVar}`;
18328
18414
  }
18329
- function buildChildRefBindings(refs, loopParam, loopParamBindings) {
18415
+ function buildChildRefBindings(refs, loopParam, loopParamBindings, loopIndex) {
18330
18416
  if (refs.length === 0)
18331
18417
  return [];
18332
18418
  return refs.map((r) => ({
18333
18419
  childSlotId: r.childSlotId,
18334
- callback: wrapLoopParamAsAccessor(r.callback, loopParam, loopParamBindings)
18420
+ callback: wrapLoopParamAsAccessor(r.callback, loopParam, loopParamBindings, loopIndex)
18335
18421
  }));
18336
18422
  }
18337
18423
  function buildStaticChildRefBindings(refs) {
@@ -18364,17 +18450,17 @@ function destructureLoopParam(param, paramBindings) {
18364
18450
  }
18365
18451
  return { head: param, unwrap: "" };
18366
18452
  }
18367
- function buildPreambleRegionPlans(regions, loopParam, loopParamBindings) {
18453
+ function buildPreambleRegionPlans(regions, loopParam, loopParamBindings, loopIndex) {
18368
18454
  if (!regions || regions.length === 0)
18369
18455
  return [];
18370
18456
  return regions.map((r) => {
18371
- const wrapped = wrapLoopParamAsAccessor(r.expr, loopParam, loopParamBindings);
18372
- 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, {});
18373
18459
  return { slotId: r.slotId, valueExpr };
18374
18460
  });
18375
18461
  }
18376
- function buildComponentPropsExpr2(comp, loopParam, loopParamBindings) {
18377
- 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;
18378
18464
  const entries = comp.props.map((p) => {
18379
18465
  if (p.isEventHandler) {
18380
18466
  const handlerExpr = attrValueToString(p.value) ?? "undefined";
@@ -18418,8 +18504,8 @@ function buildDepthLevels(innerLoops, nestedComps, childEvents) {
18418
18504
  loopInfo: loop
18419
18505
  }));
18420
18506
  }
18421
- function emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot = false) {
18422
- 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;
18423
18509
  emitListenerBlock(ls, indent, elVar, ev.childSlotId, "__e", ev.eventName, handler, "dom", bodyIsMultiRoot);
18424
18510
  }
18425
18511
  function buildCompSelector(comp) {
@@ -18431,15 +18517,15 @@ function isTextOnlyConditional(node) {
18431
18517
  const checkNode = (n) => n.type === "text" || n.type === "expression" || n.type === "conditional" && isTextOnlyConditional(n);
18432
18518
  return checkNode(node.whenTrue) && checkNode(node.whenFalse);
18433
18519
  }
18434
- function emitComponentAndEventSetup(ls, indent, elVar, comps, events, loopParam, loopParamBindings, bodyIsMultiRoot = false) {
18435
- 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;
18436
18522
  const upsertFn = bodyIsMultiRoot ? "upsertChildItem" : "upsertChild";
18437
18523
  for (const comp of comps) {
18438
- const propsExpr = buildComponentPropsExpr2(comp, loopParam, loopParamBindings);
18524
+ const propsExpr = buildComponentPropsExpr2(comp, loopParam, loopParamBindings, loopIndex);
18439
18525
  const isTextOnly = comp.children?.length ? comp.children.every((c) => c.type === "expression" || c.type === "text" || isTextOnlyConditional(c)) : false;
18440
18526
  const rawChildrenExpr = isTextOnly ? irChildrenToJsExpr(comp.children) : null;
18441
18527
  const childrenFreeIds = isTextOnly && comp.children ? irChildrenFreeIds(comp.children) : undefined;
18442
- 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));
18443
18529
  const slotIdLit = comp.slotId ? `'${comp.slotId}'` : "null";
18444
18530
  const keyProp = comp.props.find((p) => p.name === "key");
18445
18531
  const keyArg = keyProp ? `, ${wrap(attrValueToString(keyProp.value) ?? "undefined")}` : ", undefined";
@@ -18452,7 +18538,7 @@ function emitComponentAndEventSetup(ls, indent, elVar, comps, events, loopParam,
18452
18538
  }
18453
18539
  }
18454
18540
  for (const ev of events) {
18455
- emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot);
18541
+ emitEventSetup(ls, indent, elVar, ev, loopParam, loopParamBindings, bodyIsMultiRoot, loopIndex);
18456
18542
  }
18457
18543
  }
18458
18544
 
@@ -18832,12 +18918,12 @@ function buildBranchInnerLoopsPlan(args) {
18832
18918
  const inner = innerLoops[i];
18833
18919
  if (!inner.refsOuterParam || !inner.template)
18834
18920
  continue;
18835
- const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
18836
- 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);
18837
18923
  const csl = inner.containerSlotId;
18838
18924
  const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST}="\${__scopeId}"][${BF_AT}="${csl}"]\`) ?? ${scopeVar})` : `findCondContainer(${scopeVar}, '${condSlotId}')`;
18839
18925
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
18840
- 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;
18841
18927
  const wrapIRNode = (node) => {
18842
18928
  if (node.type === "component") {
18843
18929
  return {
@@ -18999,8 +19085,8 @@ function buildLoopChildArmPlan(args) {
18999
19085
 
19000
19086
  // ../jsx/src/ir-to-client-js/control-flow/plan/build-reactive-effects.ts
19001
19087
  function buildReactiveEffectsPlan(args) {
19002
- const { attrs, texts, conditionals, loopParam, loopParamBindings, profileComponentName } = args;
19003
- 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);
19004
19090
  const attrsBySlot = new Map;
19005
19091
  for (const attr of attrs) {
19006
19092
  let bucket = attrsBySlot.get(attr.childSlotId);
@@ -19084,6 +19170,7 @@ function buildLoopReactiveEffectsPlan(elem, profileComponentName) {
19084
19170
  conditionals: elem.bindings.conditionals,
19085
19171
  loopParam: elem.param,
19086
19172
  loopParamBindings: elem.paramBindings,
19173
+ loopIndex: elem.index,
19087
19174
  profileComponentName
19088
19175
  });
19089
19176
  }
@@ -19162,10 +19249,10 @@ function buildInnerLoopsPlan(args) {
19162
19249
  return plan;
19163
19250
  }
19164
19251
  function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, outerLoopParamBindings) {
19165
- const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
19166
- 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);
19167
19254
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
19168
- 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;
19169
19256
  const wrapIRNode = (node) => {
19170
19257
  if (node.type === "component") {
19171
19258
  return {
@@ -19196,11 +19283,11 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
19196
19283
  }));
19197
19284
  const reactiveTexts = inner.bindings.reactiveTexts.map((text) => ({
19198
19285
  slotId: text.slotId,
19199
- wrappedExpression: wrapLoopParamAsAccessor(wrapOuter(text.expression), inner.param, inner.paramBindings),
19286
+ wrappedExpression: wrapLoopParamAsAccessor(wrapOuter(text.expression), inner.param, inner.paramBindings, inner.index),
19200
19287
  insideConditional: !!text.insideConditional
19201
19288
  }));
19202
19289
  const reactiveAttrs = inner.bindings.reactiveAttrs.map((attr) => {
19203
- const wrapped = wrapLoopParamAsAccessor(wrapOuter(attr.expression), inner.param, inner.paramBindings);
19290
+ const wrapped = wrapLoopParamAsAccessor(wrapOuter(attr.expression), inner.param, inner.paramBindings, inner.index);
19204
19291
  return {
19205
19292
  slotId: attr.childSlotId,
19206
19293
  attrName: attr.attrName,
@@ -19217,14 +19304,14 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
19217
19304
  if (inner.preamble) {
19218
19305
  const leafLoopParams = outerLoopParam ? [
19219
19306
  { param: outerLoopParam, bindings: outerLoopParamBindings },
19220
- { param: inner.param, bindings: inner.paramBindings }
19221
- ] : [{ 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 }];
19222
19309
  preludeStatements.push(renderPreamble(inner.preamble, {
19223
19310
  transformJs: (t) => wrapInner(wrapOuter(t)),
19224
19311
  renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, leafLoopParams, undefined)
19225
19312
  }));
19226
19313
  }
19227
- const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings);
19314
+ const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings, inner.index);
19228
19315
  const conditionals = buildLoopChildConditionalsPlan({
19229
19316
  conditionals: inner.bindings.conditionals,
19230
19317
  scopeVar: `__innerEl${uidSuffix}`,
@@ -19273,7 +19360,7 @@ function buildTopLevelCompositePlan(elem, profileComponentName) {
19273
19360
  const nestedComps = elem.nestedComponents;
19274
19361
  const depthLevels = buildDepthLevels(elem.innerLoops ?? [], nestedComps, elem.bindings.events);
19275
19362
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
19276
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings);
19363
+ const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings, elem.index);
19277
19364
  const outerCompsByDepth = nestedComps.filter((c) => !c.loopDepth || c.loopDepth === 0);
19278
19365
  return {
19279
19366
  kind: "composite",
@@ -19287,12 +19374,12 @@ function buildTopLevelCompositePlan(elem, profileComponentName) {
19287
19374
  indexParam: elem.index || "__idx",
19288
19375
  mapPreambleWrapped: elem.preamble ? renderPreamble(elem.preamble, {
19289
19376
  transformJs: wrap,
19290
- 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)
19291
19378
  }) : "",
19292
19379
  template: elem.template,
19293
19380
  outerComps: filterCondCompsOut(outerCompsByDepth, elem.bindings.conditionals),
19294
19381
  outerEvents: elem.bindings.events.filter((ev) => ev.nestedLoops.length === 0),
19295
- childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
19382
+ childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings, elem.index),
19296
19383
  innerLoops: buildInnerLoopsPlan({
19297
19384
  levels: depthLevels,
19298
19385
  parentElVar: "__el",
@@ -19301,12 +19388,14 @@ function buildTopLevelCompositePlan(elem, profileComponentName) {
19301
19388
  }),
19302
19389
  loopParam: elem.param,
19303
19390
  loopParamBindings: elem.paramBindings,
19391
+ loopIndex: elem.index,
19304
19392
  reactiveEffects: hasReactive(elem) ? buildReactiveEffectsPlan({
19305
19393
  attrs: elem.bindings.reactiveAttrs,
19306
19394
  texts: elem.bindings.reactiveTexts,
19307
19395
  conditionals: elem.bindings.conditionals,
19308
19396
  loopParam: elem.param,
19309
19397
  loopParamBindings: elem.paramBindings,
19398
+ loopIndex: elem.index,
19310
19399
  profileComponentName
19311
19400
  }) : null,
19312
19401
  branchClearChildren: false,
@@ -19323,7 +19412,7 @@ function buildBranchCompositePlan(loop, cv, profileComponentName) {
19323
19412
  const childEvents = loop.bindings.events;
19324
19413
  const depthLevels = buildDepthLevels(innerLoops, nestedComps, childEvents);
19325
19414
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
19326
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings);
19415
+ const wrap = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings, loop.index);
19327
19416
  const outerCompsByDepth = nestedComps.filter((c) => !c.loopDepth || c.loopDepth === 0);
19328
19417
  return {
19329
19418
  kind: "composite",
@@ -19337,12 +19426,12 @@ function buildBranchCompositePlan(loop, cv, profileComponentName) {
19337
19426
  indexParam: loop.index || "__idx",
19338
19427
  mapPreambleWrapped: loop.preamble ? renderPreamble(loop.preamble, {
19339
19428
  transformJs: wrap,
19340
- 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)
19341
19430
  }) : "",
19342
19431
  template: loop.template,
19343
19432
  outerComps: filterCondCompsOut(outerCompsByDepth, loop.bindings.conditionals),
19344
19433
  outerEvents: childEvents.filter((ev) => ev.nestedLoops.length === 0),
19345
- childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings),
19434
+ childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings, loop.index),
19346
19435
  innerLoops: buildInnerLoopsPlan({
19347
19436
  levels: depthLevels,
19348
19437
  parentElVar: "__el",
@@ -19351,12 +19440,14 @@ function buildBranchCompositePlan(loop, cv, profileComponentName) {
19351
19440
  }),
19352
19441
  loopParam: loop.param,
19353
19442
  loopParamBindings: loop.paramBindings,
19443
+ loopIndex: loop.index,
19354
19444
  reactiveEffects: hasReactiveBranch(loop) ? buildReactiveEffectsPlan({
19355
19445
  attrs: loop.bindings.reactiveAttrs,
19356
19446
  texts: loop.bindings.reactiveTexts,
19357
19447
  conditionals: loop.bindings.conditionals,
19358
19448
  loopParam: loop.param,
19359
19449
  loopParamBindings: loop.paramBindings,
19450
+ loopIndex: loop.index,
19360
19451
  profileComponentName
19361
19452
  }) : null,
19362
19453
  branchClearChildren: true,
@@ -19491,7 +19582,7 @@ function wiringOn(branch) {
19491
19582
  found.push("reactive text");
19492
19583
  return found;
19493
19584
  }
19494
- function analyzeLazyConditional(cond, indexParam, arms) {
19585
+ function analyzeLazyConditional(cond, arms) {
19495
19586
  for (const [label, branch] of [["true", cond.whenTrue], ["false", cond.whenFalse]]) {
19496
19587
  const wiring = wiringOn(branch);
19497
19588
  if (wiring.length > 0) {
@@ -19512,9 +19603,6 @@ function analyzeLazyConditional(cond, indexParam, arms) {
19512
19603
  if (!cond.conditionFreeIdentifiers) {
19513
19604
  return NO(`conditional on slot ${cond.slotId}: condition has no analyzable identifier set`);
19514
19605
  }
19515
- if (cond.conditionFreeIdentifiers.has(indexParam)) {
19516
- return NO(`conditional on slot ${cond.slotId}: condition reads the loop index parameter '${indexParam}'`);
19517
- }
19518
19606
  return {
19519
19607
  lazySafe: true,
19520
19608
  facts: {
@@ -19533,7 +19621,7 @@ var NO_PREAMBLE = {
19533
19621
  facts: { declaredNames: new Set, freeNames: new Set }
19534
19622
  };
19535
19623
  var NO2 = (reason) => ({ lazySafe: false, reason });
19536
- function analyzeLazyPreamble(preamble, indexParam, primableNames) {
19624
+ function analyzeLazyPreamble(preamble, primableNames) {
19537
19625
  if (!preamble)
19538
19626
  return NO_PREAMBLE;
19539
19627
  if (preamble.builderNames.length > 0) {
@@ -19572,9 +19660,6 @@ function analyzeLazyPreamble(preamble, indexParam, primableNames) {
19572
19660
  }
19573
19661
  }
19574
19662
  const readNames = extractFreeIdentifiersFromStatementText(text);
19575
- if (readNames.has(indexParam) && !declaredNames.has(indexParam)) {
19576
- return NO2(`map-callback preamble reads the loop index parameter '${indexParam}'`);
19577
- }
19578
19663
  const freeNames = new Set(readNames);
19579
19664
  for (const declared of declaredNames)
19580
19665
  freeNames.delete(declared);
@@ -19724,9 +19809,6 @@ function lazyRowEligibility(args) {
19724
19809
  if (shape.hasParamUnwrap)
19725
19810
  return NO3("destructured loop param without param bindings");
19726
19811
  for (const b of bindings) {
19727
- if (b.referencesIndex) {
19728
- return NO3(`binding on slot ${b.slotId} references the loop index parameter`);
19729
- }
19730
19812
  if (b.opaqueOuterNames.includes(UNKNOWN_IDENTIFIERS)) {
19731
19813
  return NO3(`binding on slot ${b.slotId} has no analyzable identifier set`);
19732
19814
  }
@@ -19811,6 +19893,7 @@ function classifyLazyBinding(args) {
19811
19893
  }
19812
19894
  if (name === indexParam) {
19813
19895
  referencesIndex = true;
19896
+ readsItem = true;
19814
19897
  return;
19815
19898
  }
19816
19899
  if (INERT_BINDING_GLOBALS.has(name))
@@ -19860,12 +19943,12 @@ function decideLazyRow(args) {
19860
19943
  for (const b of loop.paramBindings ?? [])
19861
19944
  rowLocalNames.add(b.name);
19862
19945
  const primableNames = new Set([...scope.signals.keys(), ...scope.memos]);
19863
- const preambleAnalysis = analyzeLazyPreamble(loop.preamble, args.indexParam, primableNames);
19946
+ const preambleAnalysis = analyzeLazyPreamble(loop.preamble, primableNames);
19864
19947
  const rawConditionals = loop.bindings.conditionals ?? [];
19865
19948
  const condFacts = [];
19866
19949
  let conditionalRefusal = null;
19867
19950
  for (const cond of rawConditionals) {
19868
- const verdict = analyzeLazyConditional(cond, args.indexParam, {
19951
+ const verdict = analyzeLazyConditional(cond, {
19869
19952
  whenTrueHtml: addCondAttrToTemplate(wrap(cond.whenTrueHtml), cond.slotId),
19870
19953
  whenFalseHtml: addCondAttrToTemplate(wrap(cond.whenFalseHtml), cond.slotId)
19871
19954
  });
@@ -20007,7 +20090,8 @@ function decideLazyRow(args) {
20007
20090
  preambleStatements: args.mapPreambleWrapped,
20008
20091
  itemNeedsPreamble: [...attrs, ...texts, ...conditionals].some((b) => b.readsItem && b.readsPreamble),
20009
20092
  outerNeedsPreamble: [...attrs, ...texts, ...conditionals].some((b) => b.readsOuter && b.readsPreamble),
20010
- conditionals
20093
+ conditionals,
20094
+ readsIndex: classified.some((c) => c.referencesIndex)
20011
20095
  },
20012
20096
  decision
20013
20097
  };
@@ -20058,6 +20142,43 @@ function loopSourceIdentifiers(loop, arrayExpr) {
20058
20142
  return names;
20059
20143
  }
20060
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
+
20061
20182
  // ../jsx/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts
20062
20183
  function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
20063
20184
  const containerSlotId = loop.containerSlotId;
@@ -20072,16 +20193,18 @@ function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
20072
20193
  };
20073
20194
  return composite;
20074
20195
  }
20075
- const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
20076
20196
  const hasReactiveEffects = loop.bindings.reactiveAttrs.length > 0 || loop.bindings.reactiveTexts.length > 0 || loop.bindings.conditionals.length > 0;
20077
20197
  const fm = loop.flatMapClient;
20078
20198
  const arrayExpr = fm ? `(${buildChainedArrayExpr(loop)}).flatMap(${fm.params} => ${fm.body})` : buildChainedArrayExpr(loop);
20079
- const indexParam = loop.index || "__idx";
20080
- const mapPreambleWrapped = loop.preamble ? renderPreamble(loop.preamble, {
20081
- transformJs: (t) => wrapLoopParamAsAccessor(t, loop.param, loop.paramBindings),
20082
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: loop.param, bindings: loop.paramBindings }], undefined)
20083
- }) : "";
20084
- 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;
20085
20208
  const plan = {
20086
20209
  kind: "plain",
20087
20210
  rowConstruction: "string-template",
@@ -20094,30 +20217,20 @@ function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
20094
20217
  paramHead,
20095
20218
  paramUnwrap,
20096
20219
  indexParam,
20097
- mapPreambleWrapped,
20098
- lazyRow: buildLazyRowPlan({
20099
- loop,
20100
- arrayExpr,
20101
- indexParam,
20102
- paramUnwrap,
20103
- mapPreambleWrapped,
20104
- preambleRegionCount: preambleRegions.length,
20105
- callSite: "branch-plain",
20106
- flatMapLeafItem: Boolean(fm),
20107
- anchored: false,
20108
- scope: lazyScope
20109
- }) ?? undefined,
20110
- template: loop.template,
20220
+ mapPreambleWrapped: core.mapPreambleWrapped,
20221
+ lazyRow,
20222
+ template: core.template,
20111
20223
  reactiveEffects: hasReactiveEffects ? buildReactiveEffectsPlan({
20112
20224
  attrs: loop.bindings.reactiveAttrs,
20113
20225
  texts: loop.bindings.reactiveTexts,
20114
20226
  conditionals: loop.bindings.conditionals,
20115
20227
  loopParam: loop.param,
20116
20228
  loopParamBindings: loop.paramBindings,
20229
+ loopIndex: loop.index,
20117
20230
  profileComponentName
20118
20231
  }) : null,
20119
20232
  eventDelegation: buildBranchLoopDelegationPlan(loop, cv, profileComponentName),
20120
- childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings),
20233
+ childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings, loop.index),
20121
20234
  preambleRegions,
20122
20235
  bodyIsMultiRoot: loop.bodyIsMultiRoot ?? false,
20123
20236
  profileLoopId: profileComponentName ? `${profileComponentName}#binding:${containerSlotId}` : undefined
@@ -20402,7 +20515,7 @@ function emitDynamicTextUpdates(lines, ctx) {
20402
20515
  const __textSlot = (normalElems[0] ?? conditionalElems[0])?.slotId;
20403
20516
  let writer = "";
20404
20517
  if (normalElems.length > 0) {
20405
- 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: [] }));
20406
20519
  writer = claimWriterVarName(slots, varSlotId);
20407
20520
  lines.push(` const ${writer} = lazySlots(__scope, ${claimPlanLiteral(slots)})`);
20408
20521
  }
@@ -20940,6 +21053,8 @@ function stringifyLazyRowLoop(lines, o) {
20940
21053
  lines.push(`${indent}${o.guardContainer ? `if (${o.containerVar}) ` : ""}${call}`);
20941
21054
  const b1 = `${indent} `;
20942
21055
  const b2 = `${indent} `;
21056
+ if (lazyRow.readsIndex)
21057
+ lines.push(`${b1}indexDriven: true,`);
20943
21058
  lines.push(`${b1}createRow: (__e, ${o.indexParam}) => {`);
20944
21059
  lines.push(`${b2}const ${paramHead} = () => __e.item`);
20945
21060
  if (lazyRow.preambleStatements)
@@ -20969,6 +21084,8 @@ function stringifyLazyRowLoop(lines, o) {
20969
21084
  } else {
20970
21085
  lines.push(`${b1}applyItem: (__e) => {`);
20971
21086
  lines.push(`${b2}const ${paramHead} = () => __e.item`);
21087
+ if (lazyRow.readsIndex)
21088
+ lines.push(`${b2}const ${o.indexParam} = __e.index`);
20972
21089
  lines.push(`${b2}const __r = __e.refs ?? (__e.refs = [])`);
20973
21090
  lines.push(`${b2}const __l = __e.last ?? (__e.last = [])`);
20974
21091
  if (lazyRow.itemNeedsPreamble && lazyRow.preambleStatements) {
@@ -20995,6 +21112,8 @@ function stringifyLazyRowLoop(lines, o) {
20995
21112
  lines.push(`${b2}${g}()`);
20996
21113
  lines.push(`${b2}for (const __e of __es) {`);
20997
21114
  lines.push(`${b3}const ${paramHead} = () => __e.item`);
21115
+ if (lazyRow.readsIndex)
21116
+ lines.push(`${b3}const ${o.indexParam} = __e.index`);
20998
21117
  lines.push(`${b3}const __r = __e.refs ?? (__e.refs = [])`);
20999
21118
  lines.push(`${b3}const __l = __e.last ?? (__e.last = [])`);
21000
21119
  if (lazyRow.outerNeedsPreamble && lazyRow.preambleStatements) {
@@ -21519,6 +21638,7 @@ function stringifyCompositeLoop(lines, plan) {
21519
21638
  innerLoops,
21520
21639
  loopParam,
21521
21640
  loopParamBindings,
21641
+ loopIndex,
21522
21642
  reactiveEffects,
21523
21643
  childRefs,
21524
21644
  branchClearChildren,
@@ -21551,7 +21671,7 @@ function stringifyCompositeLoop(lines, plan) {
21551
21671
  singleRootLayout: "multiline",
21552
21672
  mountRow: true
21553
21673
  });
21554
- emitComponentAndEventSetup(lines, bodyIndent, "__el", compsArr, eventsArr, loopParam, loopParamBindings, bodyIsMultiRoot);
21674
+ emitComponentAndEventSetup(lines, bodyIndent, "__el", compsArr, eventsArr, loopParam, loopParamBindings, bodyIsMultiRoot, loopIndex);
21555
21675
  if (innerLoops.length > 0) {
21556
21676
  stringifyInnerLoops(lines, innerLoops, bodyIndent, pc);
21557
21677
  }
@@ -21973,11 +22093,11 @@ function scopeRefToVar(ref) {
21973
22093
  // ../jsx/src/ir-to-client-js/control-flow/plan/build-component-loop.ts
21974
22094
  function buildComponentLoopPlan(elem, profileComponentName) {
21975
22095
  const { name } = elem.childComponent;
21976
- const propsExpr = buildComponentPropsExpr2(elem.childComponent, elem.param);
21977
- 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);
21978
22098
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
21979
22099
  const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
21980
- transformJs: (text) => wrapLoopParamAsAccessor(text, elem.param, elem.paramBindings),
22100
+ transformJs: (text) => wrapLoopParamAsAccessor(text, elem.param, elem.paramBindings, elem.index),
21981
22101
  renderLeaf: () => {
21982
22102
  internalInvariant(false, "component-root loop received a JSX-bearing preamble — Phase 1 should have refused it");
21983
22103
  }
@@ -21987,12 +22107,12 @@ function buildComponentLoopPlan(elem, profileComponentName) {
21987
22107
  const isTextOnly = comp.children?.length ? comp.children.every((c) => c.type === "expression" || c.type === "text" || isTextOnlyConditional(c)) : false;
21988
22108
  const rawChildrenExpr = isTextOnly ? irChildrenToJsExpr(comp.children) : null;
21989
22109
  const childrenFreeIds = isTextOnly && comp.children ? irChildrenFreeIds(comp.children) : undefined;
21990
- 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));
21991
22111
  return {
21992
22112
  componentName: comp.name,
21993
22113
  selector: buildCompSelector(comp),
21994
- propsExpr: buildComponentPropsExpr2(comp, elem.param),
21995
- 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
21996
22116
  };
21997
22117
  });
21998
22118
  const hasChildConds = elem.bindings.conditionals.length > 0;
@@ -22011,7 +22131,7 @@ function buildComponentLoopPlan(elem, profileComponentName) {
22011
22131
  componentPropsExpr: propsExpr,
22012
22132
  keyExpr,
22013
22133
  nestedComps,
22014
- childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
22134
+ childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings, elem.index),
22015
22135
  profileLoopId: profileComponentName ? `${profileComponentName}#binding:${elem.slotId}` : undefined,
22016
22136
  childConditionalEffects: hasChildConds ? buildReactiveEffectsPlan({
22017
22137
  attrs: [],
@@ -22019,6 +22139,7 @@ function buildComponentLoopPlan(elem, profileComponentName) {
22019
22139
  conditionals: elem.bindings.conditionals,
22020
22140
  loopParam: elem.param,
22021
22141
  loopParamBindings: elem.paramBindings,
22142
+ loopIndex: elem.index,
22022
22143
  profileComponentName
22023
22144
  }) : null
22024
22145
  };
@@ -22042,8 +22163,6 @@ function buildLoopPlan(elem, opts) {
22042
22163
  return buildPlainLoopPlan(elem, opts.profileComponentName, opts.lazyScope);
22043
22164
  }
22044
22165
  function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
22045
- const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings);
22046
- const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
22047
22166
  const hasReactive2 = elem.bindings.reactiveAttrs.length > 0 || elem.bindings.reactiveTexts.length > 0 || elem.bindings.conditionals.length > 0;
22048
22167
  if (elem.flatMapClient) {
22049
22168
  return {
@@ -22069,12 +22188,15 @@ function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
22069
22188
  };
22070
22189
  }
22071
22190
  const arrayExpr = buildChainedArrayExpr(elem);
22072
- const indexParam = elem.index || "__idx";
22073
- const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
22074
- transformJs: wrap,
22075
- renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings }], undefined)
22076
- }) : "";
22077
- 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;
22078
22200
  return {
22079
22201
  kind: "plain",
22080
22202
  rowConstruction: "string-template",
@@ -22086,28 +22208,17 @@ function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
22086
22208
  paramHead,
22087
22209
  paramUnwrap,
22088
22210
  indexParam,
22089
- lazyRow: buildLazyRowPlan({
22090
- loop: elem,
22091
- arrayExpr,
22092
- indexParam,
22093
- paramUnwrap,
22094
- mapPreambleWrapped,
22095
- preambleRegionCount: preambleRegions.length,
22096
- callSite: "plain",
22097
- flatMapLeafItem: false,
22098
- anchored: elem.bodyIsItemConditional ?? false,
22099
- scope: lazyScope
22100
- }) ?? undefined,
22101
- mapPreambleWrapped,
22102
- template: elem.template,
22211
+ lazyRow,
22212
+ mapPreambleWrapped: core.mapPreambleWrapped,
22213
+ template: core.template,
22103
22214
  skeletonTemplate: elem.skeletonTemplate,
22104
22215
  skeletonPaths: elem.skeletonPaths,
22105
22216
  reactiveEffects: hasReactive2 ? buildLoopReactiveEffectsPlan(elem, profileComponentName) : null,
22106
- childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
22217
+ childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings, elem.index),
22107
22218
  preambleRegions,
22108
22219
  bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false,
22109
22220
  anchored: elem.bodyIsItemConditional ?? false,
22110
- anchorKeyExpr: elem.key ? wrap(elem.key) : elem.index || "__idx"
22221
+ anchorKeyExpr: elem.key ? wrap(elem.key) : `${indexParam}()`
22111
22222
  };
22112
22223
  }
22113
22224
  function buildStaticLoopPlan(elem, unsafeLocalNames, profileComponentName) {
@@ -22149,7 +22260,7 @@ function buildStaticLoopMaterialize(elem, unsafeLocalNames) {
22149
22260
  return {
22150
22261
  itemTemplate: elem.staticItemTemplate,
22151
22262
  mapPreamble: elem.preamble ? renderPreamble(elem.preamble, {
22152
- 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)
22153
22264
  }) : "",
22154
22265
  bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false
22155
22266
  };
@@ -22725,7 +22836,7 @@ function generateTemplateOnlyMount(ir, ctx) {
22725
22836
  const restSpreadNames = resolveRestSpreadNames(ctx);
22726
22837
  let templateHtml;
22727
22838
  if (canGenerateStaticTemplate(ir.root, propNamesForStaticCheck, inlinableConstants, unsafeLocalNames)) {
22728
- const markupSlotIds = new Set(ctx.dynamicElements.map((e) => e.slotId));
22839
+ const markupSlotIds = markupSlotIdsOf(ctx);
22729
22840
  templateHtml = irToComponentTemplate(ir.root, inlinableConstants, restSpreadNames, ctx.propsObjectName, markupSlotIds, ctx.restPropsName);
22730
22841
  }
22731
22842
  if (!templateHtml) {
@@ -23443,6 +23554,21 @@ function extractSsrDefaults(metadata) {
23443
23554
  }
23444
23555
  bindings[memo.name] = value;
23445
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
+ }
23446
23572
  if (metadata.propsObjectName !== null) {
23447
23573
  const referenced = new Set;
23448
23574
  for (const sig of metadata.signals) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/vite",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Vite plugin for BarefootJS: Vite/Rollup owns bundling, hashing, chunking, tree-shaking and minification of client assets, BarefootJS keeps only the JSX to (template, client JS) compile",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,17 +38,17 @@
38
38
  "directory": "packages/vite"
39
39
  },
40
40
  "dependencies": {
41
- "@barefootjs/shared": "0.34.0"
41
+ "@barefootjs/shared": "0.35.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@barefootjs/jsx": ">=0.2.0",
45
45
  "vite": "^6.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@barefootjs/client": "0.34.0",
49
- "@barefootjs/go-template": "0.34.0",
50
- "@barefootjs/hono": "0.34.0",
51
- "@barefootjs/jsx": "0.34.0",
48
+ "@barefootjs/client": "0.35.0",
49
+ "@barefootjs/go-template": "0.35.0",
50
+ "@barefootjs/hono": "0.35.0",
51
+ "@barefootjs/jsx": "0.35.0",
52
52
  "typescript": "^5.0.0",
53
53
  "vite": "^6.0.0"
54
54
  }