@barefootjs/cli 0.31.2 → 0.31.4

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 +409 -123
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -2384,6 +2384,30 @@ var init_template_parts = __esm({
2384
2384
  }
2385
2385
  });
2386
2386
 
2387
+ // ../jsx/src/identifier-pattern.ts
2388
+ function withUnicodeFlag(flags) {
2389
+ return flags.includes("u") ? flags : `${flags}u`;
2390
+ }
2391
+ function escapeIdentifierForRegex(name2) {
2392
+ return name2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2393
+ }
2394
+ function identifierPattern(name2, flags = "") {
2395
+ const esc = escapeIdentifierForRegex(name2);
2396
+ return new RegExp(`${ID_BOUNDARY_BEFORE}${esc}${ID_BOUNDARY_AFTER}`, withUnicodeFlag(flags));
2397
+ }
2398
+ function identifierCallPattern(name2, flags = "") {
2399
+ const esc = escapeIdentifierForRegex(name2);
2400
+ return new RegExp(`${ID_BOUNDARY_BEFORE}${esc}\\s*\\(`, withUnicodeFlag(flags));
2401
+ }
2402
+ var ID_BOUNDARY_BEFORE, ID_BOUNDARY_AFTER;
2403
+ var init_identifier_pattern = __esm({
2404
+ "../jsx/src/identifier-pattern.ts"() {
2405
+ "use strict";
2406
+ ID_BOUNDARY_BEFORE = "(?<![\\p{ID_Continue}$])";
2407
+ ID_BOUNDARY_AFTER = "(?![\\p{ID_Continue}$])";
2408
+ }
2409
+ });
2410
+
2387
2411
  // ../jsx/src/scanner/js-scanner.ts
2388
2412
  import ts2 from "typescript";
2389
2413
  function* iterateJsTokens(text, start2 = 0, end2 = text.length) {
@@ -2914,9 +2938,6 @@ function inferDefaultValue(type2) {
2914
2938
  if (type2.kind === "object") return "{}";
2915
2939
  return "undefined";
2916
2940
  }
2917
- function escapeRegExp(s) {
2918
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2919
- }
2920
2941
  function freeIdsFromRefs(refs) {
2921
2942
  const out = /* @__PURE__ */ new Set();
2922
2943
  if (!refs) return out;
@@ -3031,15 +3052,15 @@ function wrapLoopParamAsAccessor(expr, paramName, bindings) {
3031
3052
  if (bindings && bindings.length > 0) {
3032
3053
  return rewriteLoopBindingRefs(expr, bindings, "__bfItem()");
3033
3054
  }
3034
- const re = new RegExp(`\\b${escapeRegExp(paramName)}\\b(?!\\s*\\()(?!-)`, "g");
3035
- return replaceInExprContexts(expr, re, `${paramName}()`);
3055
+ const re = new RegExp(`${ID_BOUNDARY_BEFORE}${escapeIdentifierForRegex(paramName)}(?!\\s*\\()(?!-)${ID_BOUNDARY_AFTER}`, "gu");
3056
+ return replaceInExprContexts(expr, re, () => `${paramName}()`);
3036
3057
  }
3037
3058
  function rewriteLoopBindingRefs(expr, bindings, accessor) {
3038
3059
  const byName = /* @__PURE__ */ new Map();
3039
3060
  for (const b of bindings) byName.set(b.name, b);
3040
3061
  const preprocessed = expandShorthandBindings(expr, new Set(byName.keys()));
3041
- const alt = bindings.map((b) => escapeRegExp(b.name)).join("|");
3042
- const re = new RegExp(`\\b(${alt})\\b`, "g");
3062
+ const alt = bindings.map((b) => escapeIdentifierForRegex(b.name)).join("|");
3063
+ const re = new RegExp(`${ID_BOUNDARY_BEFORE}(${alt})${ID_BOUNDARY_AFTER}`, "gu");
3043
3064
  return replaceInExprContexts(
3044
3065
  preprocessed,
3045
3066
  re,
@@ -3094,6 +3115,7 @@ var init_utils = __esm({
3094
3115
  "use strict";
3095
3116
  init_loop_chain();
3096
3117
  init_template_parts();
3118
+ init_identifier_pattern();
3097
3119
  init_js_scanner();
3098
3120
  init_src();
3099
3121
  PROPS_PARAM = "_p";
@@ -3341,7 +3363,7 @@ var init_walker = __esm({
3341
3363
 
3342
3364
  // ../jsx/src/ir-to-client-js/csr-substitute.ts
3343
3365
  import ts4 from "typescript";
3344
- function csrSubstitute(value2, env) {
3366
+ function csrSubstitute(value2, env, enclosingScope) {
3345
3367
  if (!value2 || value2.trim().length === 0) {
3346
3368
  return { rewritten: value2, freeIdentifiers: /* @__PURE__ */ new Set() };
3347
3369
  }
@@ -3349,14 +3371,14 @@ function csrSubstitute(value2, env) {
3349
3371
  let current = value2;
3350
3372
  let lastFreeIdentifiers = /* @__PURE__ */ new Set();
3351
3373
  for (let i = 0; i < maxIter; i++) {
3352
- const step = csrSubstituteOnce(current, env);
3374
+ const step = csrSubstituteOnce(current, env, enclosingScope);
3353
3375
  lastFreeIdentifiers = step.freeIdentifiers;
3354
3376
  if (step.rewritten === current) break;
3355
3377
  current = step.rewritten;
3356
3378
  }
3357
3379
  return { rewritten: current, freeIdentifiers: lastFreeIdentifiers };
3358
3380
  }
3359
- function csrSubstituteOnce(value2, env) {
3381
+ function csrSubstituteOnce(value2, env, enclosingScope) {
3360
3382
  if (!value2 || value2.trim().length === 0) {
3361
3383
  return { rewritten: value2, freeIdentifiers: /* @__PURE__ */ new Set() };
3362
3384
  }
@@ -3380,7 +3402,7 @@ function csrSubstituteOnce(value2, env) {
3380
3402
  for (let i = boundStack.length - 1; i >= 0; i--) {
3381
3403
  if (boundStack[i].has(name2)) return true;
3382
3404
  }
3383
- return false;
3405
+ return enclosingScope?.isBound(name2) ?? false;
3384
3406
  };
3385
3407
  const recordSubstitution = (start2, end2, sub2) => {
3386
3408
  splices.push({ start: start2 - OFFSET, end: end2 - OFFSET, text: `(${sub2.replacement})` });
@@ -3584,6 +3606,176 @@ var init_child_scope = __esm({
3584
3606
  }
3585
3607
  });
3586
3608
 
3609
+ // ../jsx/src/scope/binding-scope.ts
3610
+ var BindingScope;
3611
+ var init_binding_scope = __esm({
3612
+ "../jsx/src/scope/binding-scope.ts"() {
3613
+ "use strict";
3614
+ BindingScope = class _BindingScope {
3615
+ constructor(frames2) {
3616
+ this.frames = frames2;
3617
+ }
3618
+ static EMPTY = new _BindingScope([]);
3619
+ /**
3620
+ * Child scope with a new `'loop-row'` frame for one loop's per-item
3621
+ * bindings. Parent (`this`) is not mutated; the returned scope is a
3622
+ * NEW object with `frames = [newFrame, ...this.frames]`.
3623
+ *
3624
+ * Binding semantics mirror `jsx-to-ir.ts`'s `ctx.loopParams` add site
3625
+ * EXACTLY (verified against lines ~4320-4345 and the matching delete
3626
+ * site ~4695-4710 of `packages/jsx/src/jsx-to-ir.ts`):
3627
+ *
3628
+ * - When `loop.paramBindings` is non-empty (a destructured callback
3629
+ * param, e.g. `.map(({ id, name }) => ...)`), each `paramBindings[i].name`
3630
+ * is bound with source `'destructure'` and the raw `param` text
3631
+ * (which for a destructured callback holds the ORIGINAL pattern
3632
+ * source, e.g. `"{ id, name }"`, not a usable identifier) is NOT
3633
+ * bound. This matches `jsx-to-ir.ts`:
3634
+ * `if (paramBindings) { for (const b of paramBindings) ctx.loopParams.add(b.name) }`
3635
+ * — the `else` branch (`ctx.loopParams.add(param)`) is skipped
3636
+ * entirely when `paramBindings` is present.
3637
+ * - Otherwise (a plain identifier param, e.g. `.map(item => ...)`),
3638
+ * `param` itself is bound with source `'item'`.
3639
+ * - `index` (the second callback param, e.g. `.map((item, i) => ...)`)
3640
+ * is bound with source `'index'` when non-null/non-undefined.
3641
+ * - Every name in `preamble.declaredNames` (a `.map()` callback's
3642
+ * pre-return `const`/`let`/`function` locals, #2447) is bound with
3643
+ * source `'preamble'`.
3644
+ *
3645
+ * NOTE on a sibling mechanism this method does NOT mirror:
3646
+ * `adapters/loop-bound-names.ts`'s `collectLoopBoundNames` adds BOTH
3647
+ * `node.param` AND every `paramBindings[i].name` unconditionally
3648
+ * (never skipping `param` in the destructured case) — a deliberately
3649
+ * coarser, over-inclusive collection used only to subtract names from
3650
+ * a flat string-typing Set (safe to over-exclude there). This method
3651
+ * follows the precise `jsx-to-ir.ts` `ctx.loopParams` semantics, since
3652
+ * that is the mechanism actually doing scope-shadowed name RESOLUTION
3653
+ * (the behavior `BindingScope` replaces), not coarse exclusion.
3654
+ */
3655
+ enterLoopRow(loop) {
3656
+ const bindings = /* @__PURE__ */ new Map();
3657
+ if (loop.paramBindings && loop.paramBindings.length > 0) {
3658
+ for (const b of loop.paramBindings) bindings.set(b.name, { source: "destructure" });
3659
+ } else {
3660
+ bindings.set(loop.param, { source: "item" });
3661
+ }
3662
+ if (loop.index != null) bindings.set(loop.index, { source: "index" });
3663
+ for (const name2 of loop.preamble?.declaredNames ?? []) bindings.set(name2, { source: "preamble" });
3664
+ const frame = { kind: "loop-row", bindings };
3665
+ return new _BindingScope([frame, ...this.frames]);
3666
+ }
3667
+ /**
3668
+ * Child scope with a new `'callback'` frame binding `params` (a filter
3669
+ * predicate's `x`, a sort comparator's `(a, b)`, or a nested arrow's
3670
+ * parameter list) with source `'param'`. Parent is not mutated.
3671
+ */
3672
+ enterCallback(params) {
3673
+ const bindings = /* @__PURE__ */ new Map();
3674
+ for (const name2 of params) bindings.set(name2, { source: "param" });
3675
+ const frame = { kind: "callback", bindings };
3676
+ return new _BindingScope([frame, ...this.frames]);
3677
+ }
3678
+ /** Innermost-first membership check across every frame in the stack. */
3679
+ isBound(name2) {
3680
+ for (const frame of this.frames) {
3681
+ if (frame.bindings.has(name2)) return true;
3682
+ }
3683
+ return false;
3684
+ }
3685
+ /**
3686
+ * Resolves `name` against the frame stack innermost-first. `depth 0`
3687
+ * means the innermost (most recently entered) frame; `null` when `name`
3688
+ * is not bound in any frame.
3689
+ */
3690
+ lookup(name2) {
3691
+ for (let depth = 0; depth < this.frames.length; depth++) {
3692
+ const frame = this.frames[depth];
3693
+ const binding = frame.bindings.get(name2);
3694
+ if (binding) return { depth, frame, binding };
3695
+ }
3696
+ return null;
3697
+ }
3698
+ /**
3699
+ * Union of every frame's bound names (every `ScopeBindingSource`), for
3700
+ * migration interop with legacy `Set<string>`-shaped consumers (e.g.
3701
+ * `collectLoopBoundNames`'s return type) as later stages migrate them
3702
+ * onto `BindingScope`.
3703
+ *
3704
+ * This is the SHADOW-GUARD query — see {@link valueBoundNames} for the
3705
+ * other consumer class and why the two must not be conflated.
3706
+ */
3707
+ boundNames() {
3708
+ if (this.boundNamesCache) return this.boundNamesCache;
3709
+ const names = /* @__PURE__ */ new Set();
3710
+ for (const frame of this.frames) {
3711
+ for (const name2 of frame.bindings.keys()) names.add(name2);
3712
+ }
3713
+ this.boundNamesCache = names;
3714
+ return names;
3715
+ }
3716
+ // Both name queries are hot (shadow guards, slot/reactivity classifiers,
3717
+ // binding-env memo keying) and the scope is immutable, so each computes
3718
+ // once per instance. Callers receive the cached set as ReadonlySet —
3719
+ // never mutate it.
3720
+ boundNamesCache;
3721
+ valueBoundNamesCache;
3722
+ /**
3723
+ * Union of names bound via `'item'`/`'index'`/`'destructure'` sources
3724
+ * only — the loop row's own per-item identity — excluding `'preamble'`
3725
+ * (a `.map()` callback's pre-return `const`/`let`/`function` locals,
3726
+ * #2447) and `'param'` (an `enterCallback` frame's filter/sort/nested-
3727
+ * arrow parameters).
3728
+ *
3729
+ * `BindingScope` has exactly two consumer classes, and conflating them
3730
+ * is the #2482 Stage 1a Commit 2 regression this split exists to
3731
+ * prevent (a `ctx.scope`-wide preamble merge flipped `tag-cloud` and
3732
+ * `preamble-cells` conformance fixtures before this method existed):
3733
+ *
3734
+ * - SHADOW GUARDS (`tryResolveTemplateSpanFromConst`,
3735
+ * `tryResolveIdentifierAsTemplateLiteral`, `rewriteBarePropRefs`
3736
+ * in `jsx-to-ir.ts`) ask "is this name resolved to SOMETHING in
3737
+ * this scope, so an outer const/prop of the same name must not be
3738
+ * substituted here at this transform position" — every source
3739
+ * qualifies, including a preamble local shadowing a module const.
3740
+ * These call `isBound` / `boundNames()`.
3741
+ * - REACTIVITY / SLOT-ID CLASSIFIERS (`referencesLoopParam`,
3742
+ * `hasReactiveAttributes`, and the `BindingEnvironment.loopParams`
3743
+ * feed built from `makeBindingEnv`, all in `jsx-to-ir.ts`) ask
3744
+ * "does this expression read a value that changes per row and so
3745
+ * needs its own patchable slot" — a preamble local already gets
3746
+ * ITS OWN dedicated slot/region-patch machinery
3747
+ * (`preambleRegions` / `markPreambleAttrSlots`, #2447), so folding
3748
+ * it into this classification double-counts it. Worse: widening a
3749
+ * text child's `reactive` flag this way is read by
3750
+ * `hasDynamicContent` to decide whether the loop ROW's own root
3751
+ * element needs a slot — an unrelated, narrower decision that must
3752
+ * not move just because a preamble local is now scope-visible.
3753
+ * These call `valueBoundNames()`.
3754
+ */
3755
+ valueBoundNames() {
3756
+ if (this.valueBoundNamesCache) return this.valueBoundNamesCache;
3757
+ const names = /* @__PURE__ */ new Set();
3758
+ for (const frame of this.frames) {
3759
+ for (const [name2, binding] of frame.bindings) {
3760
+ if (binding.source === "item" || binding.source === "index" || binding.source === "destructure") {
3761
+ names.add(name2);
3762
+ }
3763
+ }
3764
+ }
3765
+ this.valueBoundNamesCache = names;
3766
+ return names;
3767
+ }
3768
+ /**
3769
+ * Drop-in for `resolveStaticLoopSource`'s `opts.isNameShadowed`
3770
+ * (`packages/jsx/src/static-literal.ts:112-128`).
3771
+ */
3772
+ asShadowPredicate() {
3773
+ return (name2) => this.isBound(name2);
3774
+ }
3775
+ };
3776
+ }
3777
+ });
3778
+
3587
3779
  // ../jsx/src/ir-to-client-js/html-template.ts
3588
3780
  function createStringProtector() {
3589
3781
  const strings = [];
@@ -4705,7 +4897,7 @@ function generateCsrTemplateWithOpts(node, opts) {
4705
4897
  const transformExpr = (expr, templateExpr) => {
4706
4898
  const source = templateExpr ?? expr;
4707
4899
  if (!source) return source;
4708
- const { rewritten, freeIdentifiers: freeIdentifiers2 } = csrSubstitute(source, env);
4900
+ const { rewritten, freeIdentifiers: freeIdentifiers2 } = csrSubstitute(source, env, opts.scope);
4709
4901
  if (unsafeLocalNames && unsafeLocalNames.size > 0 && setIntersects(freeIdentifiers2, unsafeLocalNames)) {
4710
4902
  return UNSAFE_TEMPLATE_EXPR;
4711
4903
  }
@@ -4838,13 +5030,8 @@ function generateCsrTemplateWithOpts(node, opts) {
4838
5030
  return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${keyArg || (slotArg ? ", undefined" : "")}${slotArg})}`;
4839
5031
  }
4840
5032
  case "loop": {
4841
- const boundHere = new Set(opts.loopBoundNames ?? []);
4842
- if (node.paramBindings && node.paramBindings.length > 0) {
4843
- for (const b of node.paramBindings) boundHere.add(b.name);
4844
- } else if (!node.param.startsWith("[") && !node.param.startsWith("{")) {
4845
- boundHere.add(node.param);
4846
- }
4847
- if (node.index) boundHere.add(node.index);
5033
+ const childScope = (opts.scope ?? BindingScope.EMPTY).enterLoopRow(node);
5034
+ const boundHere = childScope.boundNames();
4848
5035
  const childEnv = {
4849
5036
  ...env,
4850
5037
  substitutions: new Map([...env.substitutions].filter(([name2]) => !boundHere.has(name2)))
@@ -4853,7 +5040,7 @@ function generateCsrTemplateWithOpts(node, opts) {
4853
5040
  ...opts,
4854
5041
  loopDepth: loopDepth + 1,
4855
5042
  inHoistedChildren: false,
4856
- loopBoundNames: boundHere,
5043
+ scope: childScope,
4857
5044
  csrEnv: childEnv
4858
5045
  });
4859
5046
  let childTemplate = node.children.map(recurseInLoopBody).join("");
@@ -4923,6 +5110,7 @@ var init_html_template = __esm({
4923
5110
  init_src();
4924
5111
  init_loop_chain();
4925
5112
  init_child_scope();
5113
+ init_binding_scope();
4926
5114
  VOID_ELEMENTS = /* @__PURE__ */ new Set([
4927
5115
  "area",
4928
5116
  "base",
@@ -6164,7 +6352,8 @@ function visit(node, ctx2, targetComponentName, namedExports) {
6164
6352
  if (!ctx2.componentNode) {
6165
6353
  collectAmbientGlobals(node, ctx2);
6166
6354
  }
6167
- if (ts9.isVariableStatement(node) && !ctx2.componentNode) {
6355
+ const isDeclareStatement = ts9.isVariableStatement(node) && (node.modifiers?.some((m) => m.kind === ts9.SyntaxKind.DeclareKeyword) ?? false);
6356
+ if (ts9.isVariableStatement(node) && !ctx2.componentNode && !isDeclareStatement) {
6168
6357
  const isExported = node.modifiers?.some((m) => m.kind === ts9.SyntaxKind.ExportKeyword) ?? false;
6169
6358
  const isLet = (node.declarationList.flags & ts9.NodeFlags.Let) !== 0;
6170
6359
  const isModuleClientDirective = hasLeadingClientDirectiveOnStatement(node, ctx2.sourceFile);
@@ -6180,7 +6369,7 @@ function visit(node, ctx2, targetComponentName, namedExports) {
6180
6369
  }
6181
6370
  continue;
6182
6371
  }
6183
- if (ts9.isIdentifier(decl.name) && decl.initializer && !isArrowComponentFunction(decl)) {
6372
+ if (ts9.isIdentifier(decl.name) && (decl.initializer || isLet) && !isArrowComponentFunction(decl)) {
6184
6373
  collectConstant(decl, ctx2, true, isLet ? "let" : "const", isExported);
6185
6374
  }
6186
6375
  }
@@ -7590,6 +7779,7 @@ function collectConstant(node, ctx2, _isModule, declarationKind = "const", isExp
7590
7779
  value: value2,
7591
7780
  parsed,
7592
7781
  typedValue: typedValue !== value2 ? typedValue : void 0,
7782
+ typeAnnotation: node.type ? node.type.getText(ctx2.sourceFile) : void 0,
7593
7783
  valueBranches,
7594
7784
  declarationKind,
7595
7785
  isExported,
@@ -9284,7 +9474,7 @@ function findReachableNames(primaryRefs, declarations) {
9284
9474
  const reachable = /* @__PURE__ */ new Set();
9285
9475
  const queue = [];
9286
9476
  for (const name2 of allNames) {
9287
- if (new RegExp(`\\b${name2}\\b`).test(primaryRefs)) {
9477
+ if (identifierPattern(name2).test(primaryRefs)) {
9288
9478
  reachable.add(name2);
9289
9479
  queue.push(name2);
9290
9480
  }
@@ -9293,7 +9483,7 @@ function findReachableNames(primaryRefs, declarations) {
9293
9483
  const current = queue.shift();
9294
9484
  const body2 = bodyMap.get(current) || "";
9295
9485
  for (const name2 of allNames) {
9296
- if (!reachable.has(name2) && new RegExp(`\\b${name2}\\b`).test(body2)) {
9486
+ if (!reachable.has(name2) && identifierPattern(name2).test(body2)) {
9297
9487
  reachable.add(name2);
9298
9488
  queue.push(name2);
9299
9489
  }
@@ -9319,6 +9509,7 @@ function extractFunctionParams(value2) {
9319
9509
  var init_module_exports = __esm({
9320
9510
  "../jsx/src/module-exports.ts"() {
9321
9511
  "use strict";
9512
+ init_identifier_pattern();
9322
9513
  }
9323
9514
  });
9324
9515
 
@@ -10151,8 +10342,9 @@ function rewriteBarePropRefs2(text, expr, ctx2) {
10151
10342
  const dateLowered = lowerToLocaleDateCalls(lowerDateCalls(text, expr, ctx2), expr, ctx2);
10152
10343
  let propNames = getDestructuredPropNames(ctx2);
10153
10344
  if (!propNames) return dateLowered === text ? void 0 : dateLowered;
10154
- if (ctx2.loopParams.size > 0) {
10155
- const filtered = new Set([...propNames].filter((n) => !ctx2.loopParams.has(n)));
10345
+ const shadowingNames = ctx2.scope.boundNames();
10346
+ if (shadowingNames.size > 0) {
10347
+ const filtered = new Set([...propNames].filter((n) => !shadowingNames.has(n)));
10156
10348
  if (filtered.size === 0) return dateLowered === text ? void 0 : dateLowered;
10157
10349
  propNames = filtered;
10158
10350
  }
@@ -10220,22 +10412,22 @@ function createTransformContext(analyzer) {
10220
10412
  spreadIdCounter: 0,
10221
10413
  isRoot: true,
10222
10414
  insideComponentChildren: false,
10223
- loopParams: /* @__PURE__ */ new Set(),
10415
+ scope: BindingScope.EMPTY,
10224
10416
  loopDepth: 0,
10225
10417
  patterns: {
10226
10418
  signals: analyzer.signals.map((s) => ({
10227
10419
  getter: s.getter,
10228
- pattern: new RegExp(`\\b${s.getter}\\s*\\(`)
10420
+ pattern: identifierCallPattern(s.getter)
10229
10421
  })),
10230
10422
  memos: analyzer.memos.map((m) => ({
10231
10423
  name: m.name,
10232
- pattern: new RegExp(`\\b${m.name}\\s*\\(`)
10424
+ pattern: identifierCallPattern(m.name)
10233
10425
  })),
10234
- props: analyzer.propsParams.filter((p) => p.name !== "children").map((p) => ({ name: p.name, pattern: new RegExp(`\\b${p.name}\\b`) })),
10426
+ props: analyzer.propsParams.filter((p) => p.name !== "children").map((p) => ({ name: p.name, pattern: identifierPattern(p.name) })),
10235
10427
  constants: analyzer.localConstants.map((c) => ({
10236
10428
  name: c.name,
10237
10429
  value: c.value,
10238
- pattern: new RegExp(`\\b${c.name}\\b`)
10430
+ pattern: identifierPattern(c.name)
10239
10431
  }))
10240
10432
  },
10241
10433
  getJS(node) {
@@ -10289,7 +10481,8 @@ function generateSpreadSlotId(ctx2) {
10289
10481
  return `Spread_${ctx2.spreadIdCounter++}`;
10290
10482
  }
10291
10483
  function makeBindingEnv(ctx2) {
10292
- const loopKey = ctx2.loopParams.size === 0 ? "" : Array.from(ctx2.loopParams).sort().join("\0");
10484
+ const boundNames = ctx2.scope.valueBoundNames();
10485
+ const loopKey = boundNames.size === 0 ? "" : Array.from(boundNames).sort().join("\0");
10293
10486
  if (ctx2._bindingEnv && ctx2._bindingEnvLoopKey === loopKey) {
10294
10487
  return ctx2._bindingEnv;
10295
10488
  }
@@ -10304,9 +10497,11 @@ function makeBindingEnv(ctx2) {
10304
10497
  localFunctions: a.localFunctions,
10305
10498
  imports: a.imports,
10306
10499
  ambientGlobals: a.ambientGlobals,
10307
- // Snapshot the env must observe a stable view even if `ctx.loopParams`
10308
- // is later mutated by an enclosing visitor frame.
10309
- loopParams: new Set(ctx2.loopParams),
10500
+ // `valueBoundNames()` returns a per-instance set that is never
10501
+ // mutated (cached on the immutable `BindingScope`) a stable
10502
+ // snapshot even if `ctx.scope` is later reassigned by an enclosing
10503
+ // visitor frame, which swaps the instance rather than mutating it.
10504
+ loopParams: boundNames,
10310
10505
  checker: a.checker
10311
10506
  };
10312
10507
  ctx2._bindingEnv = env;
@@ -11003,7 +11198,8 @@ function transformExpressionInner(expr, ctx2, node, isClientOnly) {
11003
11198
  freeRefs
11004
11199
  };
11005
11200
  const reactive = isReactiveExpression(exprText, ctx2, expr) || isReactiveOrigin(origin);
11006
- const refsLoopParam = ctx2.loopParams.size > 0 && Array.from(ctx2.loopParams).some((p) => new RegExp(`\\b${p}\\b`).test(exprText));
11201
+ const scopeValueNames = ctx2.scope.valueBoundNames();
11202
+ const refsLoopParam = scopeValueNames.size > 0 && Array.from(scopeValueNames).some((p) => identifierPattern(p).test(exprText));
11007
11203
  const callsReactive = exprCallsReactiveGetters(expr, ctx2);
11008
11204
  const hasCalls = exprHasFunctionCalls(expr);
11009
11205
  const needsSlot = reactive || isClientOnly || refsLoopParam || callsReactive || hasCalls;
@@ -11038,7 +11234,7 @@ function transformJsxFunctionCall(callExpr, jsxFunc, ctx2, _isClientOnly) {
11038
11234
  const substitutedGetJS = (node) => {
11039
11235
  let text = baseGetJS(node);
11040
11236
  for (const [paramName, argExpr] of substitutions) {
11041
- text = text.replace(new RegExp(`\\b${paramName}\\b`, "g"), argExpr);
11237
+ text = text.replace(identifierPattern(paramName, "g"), () => argExpr);
11042
11238
  }
11043
11239
  return text;
11044
11240
  };
@@ -11080,7 +11276,7 @@ function transformMultiReturnJsxFunctionCall(callExpr, info, ctx2) {
11080
11276
  const substitutedGetJS = (node) => {
11081
11277
  let text = baseGetJS(node);
11082
11278
  for (const [paramName, argExpr] of substitutions) {
11083
- text = text.replace(new RegExp(`\\b${paramName}\\b`, "g"), argExpr);
11279
+ text = text.replace(identifierPattern(paramName, "g"), () => argExpr);
11084
11280
  }
11085
11281
  return text;
11086
11282
  };
@@ -12055,7 +12251,7 @@ function extractItemConditionalKey(cond) {
12055
12251
  return a ?? b;
12056
12252
  }
12057
12253
  function transformMapCall(node, ctx2, isClientOnly = false, method2 = "map") {
12058
- const isNested = ctx2.loopParams.size > 0;
12254
+ const isNested = ctx2.scope.valueBoundNames().size > 0;
12059
12255
  const diagCountAtEntry = ctx2.analyzer.errors.length;
12060
12256
  const depth = ctx2.loopDepth;
12061
12257
  const propAccess = node.expression;
@@ -12250,12 +12446,8 @@ function transformMapCall(node, ctx2, isClientOnly = false, method2 = "map") {
12250
12446
  indexType = secondParam.type.getText(ctx2.sourceFile);
12251
12447
  }
12252
12448
  }
12253
- if (paramBindings) {
12254
- for (const b of paramBindings) ctx2.loopParams.add(b.name);
12255
- } else {
12256
- ctx2.loopParams.add(param);
12257
- }
12258
- if (index) ctx2.loopParams.add(index);
12449
+ const savedScope = ctx2.scope;
12450
+ ctx2.scope = ctx2.scope.enterLoopRow({ param, index, paramBindings });
12259
12451
  ctx2.loopDepth++;
12260
12452
  const tryTransformRenderableBody = (expr) => {
12261
12453
  if (!ts12.isBinaryExpression(expr)) return;
@@ -12317,6 +12509,23 @@ function transformMapCall(node, ctx2, isClientOnly = false, method2 = "map") {
12317
12509
  const returnStmt = children2.length === 0 ? body2.statements.find(
12318
12510
  (s) => ts12.isReturnStatement(s) && s.expression != null
12319
12511
  ) : void 0;
12512
+ let rowScopeBeforePreamble = null;
12513
+ if (returnStmt) {
12514
+ const preambleNames = /* @__PURE__ */ new Set();
12515
+ for (const stmt of body2.statements) {
12516
+ if (stmt === returnStmt) break;
12517
+ collectPreambleDeclaredNames(stmt, preambleNames);
12518
+ }
12519
+ if (preambleNames.size > 0) {
12520
+ rowScopeBeforePreamble = ctx2.scope;
12521
+ ctx2.scope = savedScope.enterLoopRow({
12522
+ param,
12523
+ index,
12524
+ paramBindings,
12525
+ preamble: { declaredNames: [...preambleNames] }
12526
+ });
12527
+ }
12528
+ }
12320
12529
  if (returnStmt && returnStmt.expression) {
12321
12530
  let returnExpr = returnStmt.expression;
12322
12531
  while (ts12.isParenthesizedExpression(returnExpr)) {
@@ -12408,6 +12617,9 @@ function transformMapCall(node, ctx2, isClientOnly = false, method2 = "map") {
12408
12617
  }
12409
12618
  }
12410
12619
  }
12620
+ if (rowScopeBeforePreamble) {
12621
+ ctx2.scope = rowScopeBeforePreamble;
12622
+ }
12411
12623
  if (method2 === "flatMap" && children2.length === 0 && !flatMapProjectionCall(body2)) {
12412
12624
  flatMapCallback = buildFlatMapCallback(callback, body2, ctx2);
12413
12625
  }
@@ -12441,12 +12653,7 @@ function transformMapCall(node, ctx2, isClientOnly = false, method2 = "map") {
12441
12653
  )
12442
12654
  );
12443
12655
  }
12444
- if (paramBindings) {
12445
- for (const b of paramBindings) ctx2.loopParams.delete(b.name);
12446
- } else {
12447
- ctx2.loopParams.delete(param);
12448
- }
12449
- if (index) ctx2.loopParams.delete(index);
12656
+ ctx2.scope = savedScope;
12450
12657
  ctx2.loopDepth--;
12451
12658
  }
12452
12659
  if (children2.length === 0 && !flatMapCallback) {
@@ -13207,7 +13414,7 @@ function parseTemplateLiteral(expr, ctx2) {
13207
13414
  }
13208
13415
  function tryResolveTemplateSpanFromConst(expr, ctx2) {
13209
13416
  if (ts12.isIdentifier(expr)) {
13210
- if (ctx2.loopParams.has(expr.text)) return null;
13417
+ if (ctx2.scope.isBound(expr.text)) return null;
13211
13418
  const constInfo = findLocalConst(expr.text, ctx2.analyzer);
13212
13419
  if (!constInfo) return null;
13213
13420
  const ast = parseConstInitializer(constInfo);
@@ -13219,7 +13426,7 @@ function tryResolveTemplateSpanFromConst(expr, ctx2) {
13219
13426
  }
13220
13427
  if (ts12.isElementAccessExpression(expr)) {
13221
13428
  if (!ts12.isIdentifier(expr.expression)) return null;
13222
- if (ctx2.loopParams.has(expr.expression.text)) return null;
13429
+ if (ctx2.scope.isBound(expr.expression.text)) return null;
13223
13430
  const constInfo = findLocalConst(expr.expression.text, ctx2.analyzer);
13224
13431
  if (!constInfo) return null;
13225
13432
  const ast = parseConstInitializer(constInfo);
@@ -13285,7 +13492,7 @@ function hasDynamicTagBinding(name2, sourceFile) {
13285
13492
  return found;
13286
13493
  }
13287
13494
  function tryResolveIdentifierAsTemplateLiteral(ident, ctx2) {
13288
- if (ctx2.loopParams.has(ident.text)) return null;
13495
+ if (ctx2.scope.isBound(ident.text)) return null;
13289
13496
  const constInfo = findLocalConst(ident.text, ctx2.analyzer);
13290
13497
  if (!constInfo) return null;
13291
13498
  const ast = parseConstInitializer(constInfo);
@@ -13621,9 +13828,10 @@ function isSignalOrMemoArray(array, ctx2) {
13621
13828
  return false;
13622
13829
  }
13623
13830
  function referencesLoopParam(expr, ctx2) {
13624
- if (ctx2.loopParams.size === 0) return false;
13625
- for (const p of ctx2.loopParams) {
13626
- if (new RegExp(`\\b${p}\\b`).test(expr)) return true;
13831
+ const boundNames = ctx2.scope.valueBoundNames();
13832
+ if (boundNames.size === 0) return false;
13833
+ for (const p of boundNames) {
13834
+ if (identifierPattern(p).test(expr)) return true;
13627
13835
  }
13628
13836
  return false;
13629
13837
  }
@@ -13688,9 +13896,10 @@ function hasReactiveAttributes(attrs, ctx2) {
13688
13896
  if (isSignalOrMemoReference(valueToCheck, ctx2) || isPropsReference(valueToCheck, ctx2)) {
13689
13897
  return true;
13690
13898
  }
13691
- if (ctx2.loopParams.size > 0) {
13692
- for (const p of ctx2.loopParams) {
13693
- if (new RegExp(`\\b${p}\\b`).test(valueToCheck)) return true;
13899
+ const scopeValueNames = ctx2.scope.valueBoundNames();
13900
+ if (scopeValueNames.size > 0) {
13901
+ for (const p of scopeValueNames) {
13902
+ if (identifierPattern(p).test(valueToCheck)) return true;
13694
13903
  }
13695
13904
  }
13696
13905
  }
@@ -13913,6 +14122,8 @@ var init_jsx_to_ir = __esm({
13913
14122
  init_strip_types();
13914
14123
  init_template_parts();
13915
14124
  init_src();
14125
+ init_binding_scope();
14126
+ init_identifier_pattern();
13916
14127
  CLIENT_DIRECTIVE_INTERIOR_RE2 = /^\s*@client\s*$/;
13917
14128
  BLOCK_COMMENT_RE2 = /\/\*([\s\S]*?)\*\//g;
13918
14129
  EMPTY_BOUND = /* @__PURE__ */ new Set();
@@ -13922,17 +14133,19 @@ var init_jsx_to_ir = __esm({
13922
14133
  });
13923
14134
 
13924
14135
  // ../jsx/src/ir-to-client-js/prop-handling.ts
13925
- function expandDynamicPropValue(value2, ctx2) {
14136
+ function expandDynamicPropValue(value2, ctx2, scope) {
13926
14137
  const trimmedValue = value2.trim();
14138
+ if (scope?.isBound(trimmedValue)) return value2;
13927
14139
  const constant = ctx2.localConstants.find((c) => c.name === trimmedValue);
13928
14140
  if (constant && constant.value) {
13929
14141
  return constant.value;
13930
14142
  }
13931
14143
  return value2;
13932
14144
  }
13933
- function expandConstantForReactivity(expr, ctx2, originalFreeIds) {
14145
+ function expandConstantForReactivity(expr, ctx2, originalFreeIds, scope) {
13934
14146
  if (ctx2.propsObjectName) return { expr, freeIds: originalFreeIds };
13935
14147
  const trimmedValue = expr.trim();
14148
+ if (scope?.isBound(trimmedValue)) return { expr, freeIds: originalFreeIds };
13936
14149
  const constant = ctx2.localConstants.find((c) => c.name === trimmedValue);
13937
14150
  if (constant && constant.value) {
13938
14151
  return { expr: constant.value, freeIds: constant.freeIdentifiers };
@@ -13973,6 +14186,15 @@ var init_prop_handling = __esm({
13973
14186
  });
13974
14187
 
13975
14188
  // ../jsx/src/ir-to-client-js/reactivity.ts
14189
+ function buildLoopRowScope(loopParam, loopParamBindings, preambleNames, loopIndex) {
14190
+ if (!loopParam) return void 0;
14191
+ return BindingScope.EMPTY.enterLoopRow({
14192
+ param: loopParam,
14193
+ paramBindings: loopParamBindings,
14194
+ index: loopIndex,
14195
+ preamble: preambleNames && preambleNames.size > 0 ? { declaredNames: [...preambleNames] } : void 0
14196
+ });
14197
+ }
13976
14198
  function decideWrapFromAstFlags(node) {
13977
14199
  if (node.origin && isReactiveOrigin(node.origin)) {
13978
14200
  return { wrap: true, reason: "proven-reactive" };
@@ -13994,12 +14216,12 @@ function decideWrapForChildProp(expandedValue, ctx2, prop) {
13994
14216
  }
13995
14217
  function needsEffectWrapper(expr, ctx2, freeIdentifiers2) {
13996
14218
  for (const signal2 of ctx2.signals) {
13997
- if (new RegExp(`\\b${signal2.getter}\\s*\\(`).test(expr)) {
14219
+ if (identifierCallPattern(signal2.getter).test(expr)) {
13998
14220
  return true;
13999
14221
  }
14000
14222
  }
14001
14223
  for (const memo of ctx2.memos) {
14002
- if (new RegExp(`\\b${memo.name}\\s*\\(`).test(expr)) {
14224
+ if (identifierCallPattern(memo.name).test(expr)) {
14003
14225
  return true;
14004
14226
  }
14005
14227
  }
@@ -14195,8 +14417,9 @@ function traverseForComponents(node, components, skipConditionals = false) {
14195
14417
  }
14196
14418
  });
14197
14419
  }
14198
- function collectLoopChildReactiveTexts(node, ctx2, loopParam, loopParamBindings, stopAtReactiveConditionals = false) {
14420
+ function collectLoopChildReactiveTexts(node, ctx2, loopParam, loopParamBindings, stopAtReactiveConditionals = false, preambleNames, loopIndex) {
14199
14421
  const texts = [];
14422
+ const scope = buildLoopRowScope(loopParam, loopParamBindings, preambleNames, loopIndex);
14200
14423
  walkIR(node, false, {
14201
14424
  // Skip loop/async/if-statement subtrees — the original walker omitted
14202
14425
  // them; they have their own scopes (inner-loop reconciliation, async
@@ -14206,7 +14429,7 @@ function collectLoopChildReactiveTexts(node, ctx2, loopParam, loopParamBindings,
14206
14429
  if (!n.slotId) return;
14207
14430
  if (n.preambleRegion) return;
14208
14431
  const originFreeIds = freeIdsFromRefs(n.origin?.freeRefs);
14209
- const expanded = expandConstantForReactivity(n.expr, ctx2, originFreeIds);
14432
+ const expanded = expandConstantForReactivity(n.expr, ctx2, originFreeIds, scope);
14210
14433
  const reactive = classifyReactivity(expanded.expr, ctx2, loopParam, loopParamBindings, expanded.freeIds).kind !== "none" || decideWrapFromAstFlags(n).wrap;
14211
14434
  if (!reactive) return;
14212
14435
  texts.push({
@@ -14226,8 +14449,9 @@ function anyNameIn(names, set) {
14226
14449
  for (const n of names) if (set.has(n)) return true;
14227
14450
  return false;
14228
14451
  }
14229
- function collectLoopChildReactiveAttrs(node, ctx2, loopParam, loopParamBindings, stopAtReactiveConditionals = false, preambleNames) {
14452
+ function collectLoopChildReactiveAttrs(node, ctx2, loopParam, loopParamBindings, stopAtReactiveConditionals = false, preambleNames, loopIndex) {
14230
14453
  const attrs = [];
14454
+ const scope = buildLoopRowScope(loopParam, loopParamBindings, preambleNames, loopIndex);
14231
14455
  traverseElements(node, (el) => {
14232
14456
  if (el.slotId) {
14233
14457
  for (const attr of el.attrs) {
@@ -14236,7 +14460,7 @@ function collectLoopChildReactiveAttrs(node, ctx2, loopParam, loopParamBindings,
14236
14460
  if (attr.name === "key") continue;
14237
14461
  const valueStr = attrValueToString(attr.value);
14238
14462
  if (!valueStr) continue;
14239
- const expanded = expandConstantForReactivity(valueStr, ctx2, attr.freeIdentifiers);
14463
+ const expanded = expandConstantForReactivity(valueStr, ctx2, attr.freeIdentifiers, scope);
14240
14464
  const readsPreamble = preambleNames !== void 0 && preambleNames.size > 0 && anyNameIn(expanded.freeIds ?? extractFreeIdentifiersFromText(expanded.expr), preambleNames);
14241
14465
  const reactive = classifyReactivity(expanded.expr, ctx2, loopParam, loopParamBindings, expanded.freeIds).kind !== "none" || readsPreamble || attr.callsReactiveGetters || attr.hasFunctionCalls;
14242
14466
  if (!attr.clientOnly && !reactive) continue;
@@ -14261,6 +14485,8 @@ var init_reactivity = __esm({
14261
14485
  init_prop_handling();
14262
14486
  init_csr_substitute();
14263
14487
  init_walker();
14488
+ init_binding_scope();
14489
+ init_identifier_pattern();
14264
14490
  }
14265
14491
  });
14266
14492
 
@@ -14533,13 +14759,13 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx2, options2
14533
14759
  const emitDepth = fixedDepth ?? scope.depth + 1;
14534
14760
  const loopParamsForTemplate = outerLoopParam ? [outerLoopParam, { param: n.param, bindings: n.paramBindings }] : void 0;
14535
14761
  const template = n.children.map((c) => irToPlaceholderTemplate(c, void 0, emitDepth, loopParamsForTemplate)).join("");
14536
- const refsOuter = outerLoopParam ? new RegExp(`\\b${outerLoopParam}\\b`).test(n.array) : false;
14762
+ const refsOuter = outerLoopParam ? identifierPattern(outerLoopParam).test(n.array) : false;
14537
14763
  const bindings = emptyLoopChildBindings();
14538
14764
  const innerPreambleNames = preambleNamesOf(n);
14539
14765
  if (ctx2) {
14540
14766
  for (const child of n.children) {
14541
- bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx2, n.param, n.paramBindings));
14542
- bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx2, n.param, n.paramBindings, false, innerPreambleNames));
14767
+ bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx2, n.param, n.paramBindings, false, innerPreambleNames, n.index));
14768
+ bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx2, n.param, n.paramBindings, false, innerPreambleNames, n.index));
14543
14769
  bindings.refs.push(...collectLoopChildRefs(child));
14544
14770
  }
14545
14771
  }
@@ -14571,7 +14797,9 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx2, options2
14571
14797
  ctx2,
14572
14798
  siblingOffsets,
14573
14799
  n.param,
14574
- n.paramBindings
14800
+ n.paramBindings,
14801
+ innerPreambleNames,
14802
+ n.index
14575
14803
  ));
14576
14804
  }
14577
14805
  }
@@ -14753,7 +14981,7 @@ function collectElements(node, ctx2, siblingOffsets, insideConditional = false)
14753
14981
  if (!l.slotId || inCond) return;
14754
14982
  const projectionInner = l.method === "flatMap" && l.children.length === 1 && l.children[0].type === "loop" ? l.children[0] : void 0;
14755
14983
  const childHandlers = [];
14756
- const bindings = projectionInner ? emptyLoopChildBindings() : collectLoopChildBindings(l.children, ctx2, siblingOffsets, l.param, l.paramBindings, preambleNamesOf(l));
14984
+ const bindings = projectionInner ? emptyLoopChildBindings() : collectLoopChildBindings(l.children, ctx2, siblingOffsets, l.param, l.paramBindings, preambleNamesOf(l), l.index);
14757
14985
  if (!projectionInner) {
14758
14986
  for (const child of l.children) {
14759
14987
  childHandlers.push(...collectEventHandlersFromIR(child));
@@ -15005,7 +15233,7 @@ function collectBranchLoops(node, ctx2, siblingOffsets) {
15005
15233
  } else {
15006
15234
  childTemplate = n.children.map((c) => irToHtmlTemplate(c, void 0, 0, branchLoopParamSpec)).join("");
15007
15235
  }
15008
- const branchBindings = ctx2 && !projectionInner ? collectLoopChildBindings(n.children, ctx2, siblingOffsets, n.param, n.paramBindings, preambleNamesOf(n)) : emptyLoopChildBindings();
15236
+ const branchBindings = ctx2 && !projectionInner ? collectLoopChildBindings(n.children, ctx2, siblingOffsets, n.param, n.paramBindings, preambleNamesOf(n), n.index) : emptyLoopChildBindings();
15009
15237
  loops.push({
15010
15238
  kind: "branch",
15011
15239
  array: n.array,
@@ -15091,19 +15319,20 @@ function preambleNamesOf(loop) {
15091
15319
  const declared = loop.preamble?.declaredNames;
15092
15320
  return declared && declared.length > 0 ? new Set(declared) : void 0;
15093
15321
  }
15094
- function collectLoopChildBindings(children2, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames) {
15322
+ function collectLoopChildBindings(children2, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex) {
15095
15323
  const bindings = emptyLoopChildBindings();
15096
15324
  for (const child of children2) {
15097
15325
  bindings.events.push(...collectLoopChildEventsWithNesting(child));
15098
- bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx2, loopParam, loopParamBindings, true, preambleNames));
15099
- bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx2, loopParam, loopParamBindings, true));
15326
+ bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx2, loopParam, loopParamBindings, true, preambleNames, loopIndex));
15327
+ bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx2, loopParam, loopParamBindings, true, preambleNames, loopIndex));
15100
15328
  bindings.refs.push(...collectLoopChildRefs(child));
15101
- bindings.conditionals.push(...collectLoopChildConditionals(child, ctx2, siblingOffsets, loopParam, loopParamBindings));
15329
+ bindings.conditionals.push(...collectLoopChildConditionals(child, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex));
15102
15330
  }
15103
15331
  return bindings;
15104
15332
  }
15105
- function collectLoopChildConditionals(node, ctx2, siblingOffsets, loopParam, loopParamBindings) {
15333
+ function collectLoopChildConditionals(node, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex) {
15106
15334
  const conditionals = [];
15335
+ const scope = buildLoopRowScope(loopParam, loopParamBindings, preambleNames, loopIndex);
15107
15336
  const refsAnyBindingViaFreeIds = (freeIds) => {
15108
15337
  if (loopParamBindings && loopParamBindings.length > 0) {
15109
15338
  for (const b of loopParamBindings) {
@@ -15123,7 +15352,7 @@ function collectLoopChildConditionals(node, ctx2, siblingOffsets, loopParam, loo
15123
15352
  const sourceFreeIds = freeIdsFromRefs(n.origin?.freeRefs);
15124
15353
  const refsLoopParamInSource = refsAnyBindingViaFreeIds(sourceFreeIds);
15125
15354
  if (!n.reactive && !refsLoopParamInSource) return;
15126
- const expanded = expandConstantForReactivity(n.condition, ctx2, sourceFreeIds);
15355
+ const expanded = expandConstantForReactivity(n.condition, ctx2, sourceFreeIds, scope);
15127
15356
  if (classifyReactivity(expanded.expr, ctx2, loopParam, loopParamBindings, expanded.freeIds).kind === "none") return;
15128
15357
  const loopParamsForCond = loopParam ? [{ param: loopParam, bindings: loopParamBindings }] : void 0;
15129
15358
  const whenTrueHtml = irToHtmlTemplate(n.whenTrue, void 0, 0, loopParamsForCond, "__slots");
@@ -15133,27 +15362,27 @@ function collectLoopChildConditionals(node, ctx2, siblingOffsets, loopParam, loo
15133
15362
  condition: expanded.expr,
15134
15363
  whenTrueHtml,
15135
15364
  whenFalseHtml,
15136
- whenTrue: summarizeLoopChildBranch(n.whenTrue, ctx2, siblingOffsets, loopParam, loopParamBindings),
15137
- whenFalse: summarizeLoopChildBranch(n.whenFalse, ctx2, siblingOffsets, loopParam, loopParamBindings),
15365
+ whenTrue: summarizeLoopChildBranch(n.whenTrue, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex),
15366
+ whenFalse: summarizeLoopChildBranch(n.whenFalse, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex),
15138
15367
  ...expanded.freeIds !== void 0 && { conditionFreeIdentifiers: expanded.freeIds }
15139
15368
  });
15140
15369
  }
15141
15370
  });
15142
15371
  return conditionals;
15143
15372
  }
15144
- function summarizeLoopChildBranch(node, ctx2, siblingOffsets, loopParam, loopParamBindings) {
15373
+ function summarizeLoopChildBranch(node, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex) {
15145
15374
  const inner = collectInnerLoops([node], siblingOffsets, loopParam, ctx2, branchInnerLoopOptions);
15146
15375
  return {
15147
15376
  childComponents: collectConditionalBranchChildComponents(node),
15148
15377
  innerLoops: inner.length > 0 ? inner : void 0,
15149
- conditionals: collectLoopChildConditionals(node, ctx2, siblingOffsets, loopParam, loopParamBindings),
15378
+ conditionals: collectLoopChildConditionals(node, ctx2, siblingOffsets, loopParam, loopParamBindings, preambleNames, loopIndex),
15150
15379
  events: collectConditionalBranchEvents(node),
15151
15380
  // Loop-param-aware — reuses the flat loop-item collectors scoped to just
15152
15381
  // this branch's subtree. Both already stop descending into any further
15153
15382
  // nested reactive conditional (own insert()/arm), so calling them here
15154
15383
  // on the branch root yields exactly this branch's direct bindings
15155
15384
  // without re-collecting what a nested arm already owns (#2347).
15156
- reactiveAttrs: collectLoopChildReactiveAttrs(node, ctx2, loopParam, loopParamBindings, true),
15385
+ reactiveAttrs: collectLoopChildReactiveAttrs(node, ctx2, loopParam, loopParamBindings, true, preambleNames, loopIndex),
15157
15386
  // Skip ONLY when the branch's entire content is a single bare
15158
15387
  // `expression` (no wrapping element) that MAY yield a live DOM node —
15159
15388
  // i.e. it contains a call anywhere (`node.hasFunctionCalls`, computed
@@ -15201,7 +15430,7 @@ function summarizeLoopChildBranch(node, ctx2, siblingOffsets, loopParam, loopPar
15201
15430
  // makes `irToHtmlTemplate` emit its `<!--bf:sN-->…<!--/-->` marker (the
15202
15431
  // same call builds both the SSR and the CSR/hydration template, so the
15203
15432
  // two can't disagree on shape).
15204
- reactiveTexts: node.type === "expression" && node.hasFunctionCalls ? [] : collectLoopChildReactiveTexts(node, ctx2, loopParam, loopParamBindings, true)
15433
+ reactiveTexts: node.type === "expression" && node.hasFunctionCalls ? [] : collectLoopChildReactiveTexts(node, ctx2, loopParam, loopParamBindings, true, preambleNames, loopIndex)
15205
15434
  };
15206
15435
  }
15207
15436
  var EMPTY_RENDER_EXPRS, branchInnerLoopOptions;
@@ -15216,6 +15445,7 @@ var init_collect_elements = __esm({
15216
15445
  init_prop_handling();
15217
15446
  init_walker();
15218
15447
  init_loop_chain();
15448
+ init_identifier_pattern();
15219
15449
  EMPTY_RENDER_EXPRS = /* @__PURE__ */ new Set(["null", "undefined", "false", "''", '""', "``"]);
15220
15450
  branchInnerLoopOptions = {
15221
15451
  collectItemBindings: true,
@@ -15730,7 +15960,7 @@ var init_value_references = __esm({
15730
15960
  function detectUsedImports(code) {
15731
15961
  const used = /* @__PURE__ */ new Set();
15732
15962
  for (const name2 of RUNTIME_IMPORT_CANDIDATES) {
15733
- if (new RegExp(`\\b${name2}\\s*\\(`).test(code)) {
15963
+ if (identifierCallPattern(name2).test(code)) {
15734
15964
  used.add(name2);
15735
15965
  }
15736
15966
  }
@@ -15830,6 +16060,7 @@ var init_imports = __esm({
15830
16060
  "use strict";
15831
16061
  init_builtins();
15832
16062
  init_value_references();
16063
+ init_identifier_pattern();
15833
16064
  RUNTIME_IMPORT_CANDIDATES = [
15834
16065
  "createSignal",
15835
16066
  "createMemo",
@@ -16204,7 +16435,7 @@ function containsAnyIdentifier(node, names) {
16204
16435
  function scanRefsByName(text, bindings) {
16205
16436
  const result2 = /* @__PURE__ */ new Map();
16206
16437
  for (const name2 of bindings.keys()) {
16207
- const re = new RegExp(`\\b${name2}\\b`);
16438
+ const re = identifierPattern(name2);
16208
16439
  if (re.test(text)) result2.set(name2, []);
16209
16440
  }
16210
16441
  return result2;
@@ -16297,6 +16528,7 @@ var init_relocate = __esm({
16297
16528
  init_props_binding();
16298
16529
  init_expression_parser();
16299
16530
  init_lowering_registry();
16531
+ init_identifier_pattern();
16300
16532
  REGISTRY_SAFE_BINDING_KINDS = /* @__PURE__ */ new Set([
16301
16533
  "global",
16302
16534
  "module-import",
@@ -19051,7 +19283,7 @@ function buildStaticArrayDelegationPlan(elem, profileComponentName) {
19051
19283
  function buildKeyedOrIndexLookup(args2) {
19052
19284
  const hasBindings = (args2.paramBindings?.length ?? 0) > 0;
19053
19285
  if (args2.key !== null) {
19054
- const keyWithItem = hasBindings ? substituteLoopBindings(args2.key, args2.paramBindings, "item") : args2.key.replace(new RegExp(`\\b${args2.param}\\b`, "g"), "item");
19286
+ const keyWithItem = hasBindings ? substituteLoopBindings(args2.key, args2.paramBindings, "item") : args2.key.replace(identifierPattern(args2.param, "g"), "item");
19055
19287
  return {
19056
19288
  kind: "keyed",
19057
19289
  arrayExpr: args2.array,
@@ -19078,6 +19310,7 @@ var init_build_event_delegation = __esm({
19078
19310
  "../jsx/src/ir-to-client-js/control-flow/plan/build-event-delegation.ts"() {
19079
19311
  "use strict";
19080
19312
  init_utils();
19313
+ init_identifier_pattern();
19081
19314
  init_html_template();
19082
19315
  }
19083
19316
  });
@@ -21367,7 +21600,7 @@ function emitKeyedLookup(ls, ev, handlerCall, lookup) {
21367
21600
  }
21368
21601
  for (const nested of ev.nestedLoops) {
21369
21602
  const rawKey = nested.key ?? "";
21370
- const innerKeyExpr = nested.paramBindings && nested.paramBindings.length > 0 ? substituteLoopBindings(rawKey, nested.paramBindings, "item") : rawKey.replace(new RegExp(`\\b${nested.param}\\b`, "g"), "item");
21603
+ const innerKeyExpr = nested.paramBindings && nested.paramBindings.length > 0 ? substituteLoopBindings(rawKey, nested.paramBindings, "item") : rawKey.replace(identifierPattern(nested.param, "g"), "item");
21371
21604
  const outerRef = hasBindings ? "__bfLoopItem" : param;
21372
21605
  ls.push(` const ${nested.param} = ${outerRef} && ${nested.array}.find(item => String(${innerKeyExpr}) === innerKey${nested.depth})`);
21373
21606
  }
@@ -21428,6 +21661,7 @@ var init_event_delegation = __esm({
21428
21661
  "use strict";
21429
21662
  init_utils();
21430
21663
  init_csr_substitute();
21664
+ init_identifier_pattern();
21431
21665
  NON_BUBBLING_EVENTS = /* @__PURE__ */ new Set([
21432
21666
  "blur",
21433
21667
  "focus",
@@ -22176,7 +22410,7 @@ import ts19 from "typescript";
22176
22410
  function rewritePropsObjectRef(code, propsObjectName) {
22177
22411
  const srcPropsName = propsObjectName ?? "props";
22178
22412
  if (srcPropsName === PROPS_PARAM) return code;
22179
- if (!new RegExp(`\\b${srcPropsName}\\b`).test(code)) return code;
22413
+ if (!identifierPattern(srcPropsName).test(code)) return code;
22180
22414
  const sourceFile = ts19.createSourceFile(
22181
22415
  "init-body.ts",
22182
22416
  code,
@@ -22216,6 +22450,7 @@ var init_rewrite_props_object = __esm({
22216
22450
  "../jsx/src/ir-to-client-js/rewrite-props-object.ts"() {
22217
22451
  "use strict";
22218
22452
  init_utils();
22453
+ init_identifier_pattern();
22219
22454
  }
22220
22455
  });
22221
22456
 
@@ -24829,6 +25064,7 @@ var init_jsx_adapter = __esm({
24829
25064
  init_env_signal();
24830
25065
  init_module_exports();
24831
25066
  init_csr_substitute();
25067
+ init_identifier_pattern();
24832
25068
  JsxAdapter = class extends BaseAdapter {
24833
25069
  componentName = "";
24834
25070
  /**
@@ -24920,7 +25156,7 @@ var init_jsx_adapter = __esm({
24920
25156
  lines.push(` const ${signal2.getter} = () => ${initialValue}`);
24921
25157
  }
24922
25158
  if (signal2.setter) {
24923
- const setterUsed = new RegExp(`\\b${signal2.setter}\\b`).test(setterRefText);
25159
+ const setterUsed = identifierPattern(signal2.setter).test(setterRefText);
24924
25160
  if (setterUsed) {
24925
25161
  lines.push(` const ${signal2.setter} = (..._args: any[]) => {}`);
24926
25162
  }
@@ -24937,7 +25173,7 @@ var init_jsx_adapter = __esm({
24937
25173
  if (moduleScopeNames.has(constant.name)) continue;
24938
25174
  const keyword = constant.declarationKind ?? "const";
24939
25175
  if (!constant.value) {
24940
- const typeAnnotation = preserveTypes && constant.type ? `: ${constant.type.raw}` : "";
25176
+ const typeAnnotation = preserveTypes && (constant.typeAnnotation ?? constant.type) ? `: ${constant.typeAnnotation ?? constant.type?.raw}` : "";
24941
25177
  lines.push(` ${keyword} ${constant.name}${typeAnnotation}`);
24942
25178
  continue;
24943
25179
  }
@@ -24945,7 +25181,8 @@ var init_jsx_adapter = __esm({
24945
25181
  if (/^createContext\b/.test(value2) || /^new WeakMap\b/.test(value2)) continue;
24946
25182
  if (!reachable.has(constant.name)) continue;
24947
25183
  const constValue = preserveTypes ? constant.typedValue ?? constant.value : constant.value;
24948
- lines.push(` ${keyword} ${constant.name} = ${constValue}`);
25184
+ const letTypeAnnotation = preserveTypes && keyword === "let" && constant.typeAnnotation ? `: ${constant.typeAnnotation}` : "";
25185
+ lines.push(` ${keyword} ${constant.name}${letTypeAnnotation} = ${constValue}`);
24949
25186
  }
24950
25187
  for (const func of localFunctions) {
24951
25188
  if (moduleScopeNames.has(func.name)) continue;
@@ -25102,14 +25339,16 @@ var init_jsx_adapter = __esm({
25102
25339
  const keyword = c.declarationKind ?? "const";
25103
25340
  const exportKw = c.isExported ? "export " : "";
25104
25341
  if (!c.value) {
25105
- entries2.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}` });
25342
+ const typeAnnotation = preserveTypes && (c.typeAnnotation ?? c.type) ? `: ${c.typeAnnotation ?? c.type?.raw}` : "";
25343
+ entries2.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}${typeAnnotation}` });
25106
25344
  continue;
25107
25345
  }
25108
25346
  const trimmed = c.value.trim();
25109
25347
  if (/^new WeakMap\b/.test(trimmed)) continue;
25110
25348
  if (c.isExported && /^createContext\b/.test(trimmed)) continue;
25111
25349
  const value2 = preserveTypes ? c.typedValue ?? c.value : c.value;
25112
- entries2.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name} = ${value2}` });
25350
+ const letTypeAnnotation = preserveTypes && keyword === "let" && c.typeAnnotation ? `: ${c.typeAnnotation}` : "";
25351
+ entries2.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}${letTypeAnnotation} = ${value2}` });
25113
25352
  }
25114
25353
  for (const f of ir.metadata.localFunctions) {
25115
25354
  if (!f.isModule || !moduleNames.has(f.name)) continue;
@@ -25186,6 +25425,7 @@ var init_jsx_adapter = __esm({
25186
25425
  });
25187
25426
 
25188
25427
  // ../jsx/src/adapters/template-imports.ts
25428
+ import ts25 from "typescript";
25189
25429
  function rewriteImportsForTemplate(imports, shimSource, rewriteRelative) {
25190
25430
  const remap = (imp) => {
25191
25431
  if (!rewriteRelative || !imp.source.startsWith(".")) return imp;
@@ -25227,6 +25467,48 @@ function rewriteImportsForTemplate(imports, shimSource, rewriteRelative) {
25227
25467
  function specKey(s) {
25228
25468
  return `${s.isDefault ? "d" : ""}${s.isNamespace ? "n" : ""}:${s.name}:${s.alias ?? ""}`;
25229
25469
  }
25470
+ function rewriteDynamicImportsInSource(sourceText, rewriteRelative) {
25471
+ if (!sourceText.includes("import")) return sourceText;
25472
+ const sf = ts25.createSourceFile(
25473
+ "bf-template-fragment.tsx",
25474
+ sourceText,
25475
+ ts25.ScriptTarget.Latest,
25476
+ /* setParentNodes */
25477
+ false,
25478
+ ts25.ScriptKind.TSX
25479
+ );
25480
+ const edits = [];
25481
+ const visit3 = (node) => {
25482
+ if (ts25.isCallExpression(node) && node.expression.kind === ts25.SyntaxKind.ImportKeyword && node.arguments.length > 0 && ts25.isStringLiteralLike(node.arguments[0])) {
25483
+ collect(node.arguments[0]);
25484
+ }
25485
+ if (ts25.isImportTypeNode(node) && ts25.isLiteralTypeNode(node.argument)) {
25486
+ const literal = node.argument.literal;
25487
+ if (ts25.isStringLiteralLike(literal)) collect(literal);
25488
+ }
25489
+ ts25.forEachChild(node, visit3);
25490
+ };
25491
+ const collect = (literal) => {
25492
+ const specifier = literal.text;
25493
+ if (!specifier.startsWith(".")) return;
25494
+ const next = rewriteRelative(specifier);
25495
+ if (next === specifier) return;
25496
+ edits.push({
25497
+ start: literal.getStart(sf),
25498
+ end: literal.getEnd(),
25499
+ // Re-quote rather than reusing the original delimiters: a rewritten
25500
+ // POSIX-relative path never contains a quote to escape.
25501
+ text: `'${next}'`
25502
+ });
25503
+ };
25504
+ ts25.forEachChild(sf, visit3);
25505
+ if (edits.length === 0) return sourceText;
25506
+ let out = sourceText;
25507
+ for (const edit of edits.sort((a, b) => b.start - a.start)) {
25508
+ out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
25509
+ }
25510
+ return out;
25511
+ }
25230
25512
  var CLIENT_PACKAGE_SOURCES;
25231
25513
  var init_template_imports = __esm({
25232
25514
  "../jsx/src/adapters/template-imports.ts"() {
@@ -26065,7 +26347,7 @@ var init_dangerous_inner_html = __esm({
26065
26347
  });
26066
26348
 
26067
26349
  // ../jsx/src/combine-client-js.ts
26068
- import ts25 from "typescript";
26350
+ import ts26 from "typescript";
26069
26351
  function combineParentChildClientJs(files2) {
26070
26352
  const result2 = /* @__PURE__ */ new Map();
26071
26353
  const lookup = /* @__PURE__ */ new Map();
@@ -26122,17 +26404,17 @@ function combineParentChildClientJs(files2) {
26122
26404
  return result2;
26123
26405
  }
26124
26406
  function parseAndMerge(content2, importsBySource, otherImports, codeSections) {
26125
- const sourceFile = ts25.createSourceFile(
26407
+ const sourceFile = ts26.createSourceFile(
26126
26408
  "combine.js",
26127
26409
  content2,
26128
- ts25.ScriptTarget.Latest,
26410
+ ts26.ScriptTarget.Latest,
26129
26411
  /*setParentNodes*/
26130
26412
  false,
26131
- ts25.ScriptKind.JS
26413
+ ts26.ScriptKind.JS
26132
26414
  );
26133
26415
  const importSpans = [];
26134
26416
  for (const stmt of sourceFile.statements) {
26135
- if (!ts25.isImportDeclaration(stmt)) continue;
26417
+ if (!ts26.isImportDeclaration(stmt)) continue;
26136
26418
  const start2 = stmt.getStart(sourceFile);
26137
26419
  const end2 = stmt.getEnd();
26138
26420
  importSpans.push([start2, end2]);
@@ -26140,8 +26422,8 @@ function parseAndMerge(content2, importsBySource, otherImports, codeSections) {
26140
26422
  if (stmtText.includes("@bf-child:")) continue;
26141
26423
  const clause = stmt.importClause;
26142
26424
  const bindings = clause?.namedBindings;
26143
- const specifier = ts25.isStringLiteral(stmt.moduleSpecifier) ? stmt.moduleSpecifier.text : "";
26144
- if (clause && !clause.name && bindings && ts25.isNamedImports(bindings)) {
26425
+ const specifier = ts26.isStringLiteral(stmt.moduleSpecifier) ? stmt.moduleSpecifier.text : "";
26426
+ if (clause && !clause.name && bindings && ts26.isNamedImports(bindings)) {
26145
26427
  if (!importsBySource.has(specifier)) {
26146
26428
  importsBySource.set(specifier, /* @__PURE__ */ new Set());
26147
26429
  }
@@ -26316,7 +26598,7 @@ var init_loop_destructure = __esm({
26316
26598
  });
26317
26599
 
26318
26600
  // ../jsx/src/debug.ts
26319
- import ts26 from "typescript";
26601
+ import ts27 from "typescript";
26320
26602
  function buildComponentGraph(source, filePath, componentName) {
26321
26603
  const ctx2 = analyzeComponent(source, filePath, componentName);
26322
26604
  if (!ctx2.jsxReturn) {
@@ -27528,18 +27810,18 @@ function truncateExpr(expr, max = 40) {
27528
27810
  function exprReadsPropMember(expr, propsObjectName) {
27529
27811
  let sf;
27530
27812
  try {
27531
- sf = ts26.createSourceFile("__attr.tsx", `(${expr})`, ts26.ScriptTarget.Latest, true, ts26.ScriptKind.TSX);
27813
+ sf = ts27.createSourceFile("__attr.tsx", `(${expr})`, ts27.ScriptTarget.Latest, true, ts27.ScriptKind.TSX);
27532
27814
  } catch {
27533
27815
  return false;
27534
27816
  }
27535
27817
  let found = false;
27536
27818
  const visit3 = (n) => {
27537
27819
  if (found) return;
27538
- if (ts26.isPropertyAccessExpression(n) && ts26.isIdentifier(n.expression) && n.expression.text === propsObjectName && n.name.text !== "children") {
27820
+ if (ts27.isPropertyAccessExpression(n) && ts27.isIdentifier(n.expression) && n.expression.text === propsObjectName && n.name.text !== "children") {
27539
27821
  found = true;
27540
27822
  return;
27541
27823
  }
27542
- ts26.forEachChild(n, visit3);
27824
+ ts27.forEachChild(n, visit3);
27543
27825
  };
27544
27826
  visit3(sf);
27545
27827
  return found;
@@ -27567,12 +27849,12 @@ function attrValueToString2(value2) {
27567
27849
  function extractReactiveDeps(expr, signalGetters, memoNames) {
27568
27850
  const deps = [];
27569
27851
  for (const getter of signalGetters) {
27570
- if (new RegExp(`\\b${getter}\\s*\\(`).test(expr)) {
27852
+ if (identifierCallPattern(getter).test(expr)) {
27571
27853
  deps.push(getter);
27572
27854
  }
27573
27855
  }
27574
27856
  for (const memo of memoNames) {
27575
- if (new RegExp(`\\b${memo}\\s*\\(`).test(expr)) {
27857
+ if (identifierCallPattern(memo).test(expr)) {
27576
27858
  deps.push(memo);
27577
27859
  }
27578
27860
  }
@@ -27585,7 +27867,7 @@ function extractSetterRefs(expr, signalGetters) {
27585
27867
  refs.push(match[1]);
27586
27868
  }
27587
27869
  for (const getter of signalGetters) {
27588
- if (new RegExp(`\\b${getter}\\s*\\(`).test(expr)) {
27870
+ if (identifierCallPattern(getter).test(expr)) {
27589
27871
  refs.push(getter);
27590
27872
  }
27591
27873
  }
@@ -27612,11 +27894,12 @@ var init_debug = __esm({
27612
27894
  init_ir_to_client_js();
27613
27895
  init_reactivity();
27614
27896
  init_utils();
27897
+ init_identifier_pattern();
27615
27898
  }
27616
27899
  });
27617
27900
 
27618
27901
  // ../jsx/src/profiler.ts
27619
- import ts27 from "typescript";
27902
+ import ts28 from "typescript";
27620
27903
  function buildStaticBudget(source, filePath, componentName, options2 = {}) {
27621
27904
  const threshold = options2.fanOutThreshold ?? DEFAULT_FANOUT_THRESHOLD;
27622
27905
  const program = createProgramForFile(source, filePath)?.program;
@@ -27871,14 +28154,14 @@ function joinProfilerEvents(events, index) {
27871
28154
  return { joined, unattributed, diagnostics };
27872
28155
  }
27873
28156
  function findUninstrumentedEffects(source, filePath, instrumentedLines) {
27874
- const sf = ts27.createSourceFile(filePath, source, ts27.ScriptTarget.Latest, true, ts27.ScriptKind.TSX);
28157
+ const sf = ts28.createSourceFile(filePath, source, ts28.ScriptTarget.Latest, true, ts28.ScriptKind.TSX);
27875
28158
  const out = [];
27876
28159
  const visit3 = (node) => {
27877
- if (ts27.isCallExpression(node) && ts27.isIdentifier(node.expression) && node.expression.text === "createEffect") {
28160
+ if (ts28.isCallExpression(node) && ts28.isIdentifier(node.expression) && node.expression.text === "createEffect") {
27878
28161
  const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
27879
28162
  if (!instrumentedLines.has(line)) out.push({ file: filePath, line });
27880
28163
  }
27881
- ts27.forEachChild(node, visit3);
28164
+ ts28.forEachChild(node, visit3);
27882
28165
  };
27883
28166
  visit3(sf);
27884
28167
  out.sort((a, b) => a.line - b.line);
@@ -28164,19 +28447,19 @@ function assessBatchSafety(args2) {
28164
28447
  const signalGetters = new Set(args2.graph.signals.map((s) => s.name));
28165
28448
  let sf;
28166
28449
  try {
28167
- sf = ts27.createSourceFile("__h.ts", `const __h = ${args2.handler}`, ts27.ScriptTarget.Latest, true);
28450
+ sf = ts28.createSourceFile("__h.ts", `const __h = ${args2.handler}`, ts28.ScriptTarget.Latest, true);
28168
28451
  } catch {
28169
28452
  return "unverified";
28170
28453
  }
28171
28454
  const calls = [];
28172
28455
  const visit3 = (node) => {
28173
- if (ts27.isCallExpression(node) && ts27.isIdentifier(node.expression)) {
28456
+ if (ts28.isCallExpression(node) && ts28.isIdentifier(node.expression)) {
28174
28457
  const name2 = node.expression.text;
28175
28458
  if (setters.has(name2)) calls.push({ pos: node.getStart(sf), kind: "write" });
28176
28459
  else if (D.has(name2) && node.arguments.length === 0) calls.push({ pos: node.getStart(sf), kind: "memoRead" });
28177
28460
  else if (!signalGetters.has(name2) && !memoNames.has(name2)) calls.push({ pos: node.getStart(sf), kind: "risky" });
28178
28461
  }
28179
- ts27.forEachChild(node, visit3);
28462
+ ts28.forEachChild(node, visit3);
28180
28463
  };
28181
28464
  visit3(sf);
28182
28465
  calls.sort((a, b) => a.pos - b.pos);
@@ -28832,6 +29115,7 @@ __export(src_exports, {
28832
29115
  BROWSER_ONLY_CLIENT_APIS: () => BROWSER_ONLY_CLIENT_APIS,
28833
29116
  BUILTIN_LOWERING_PLUGINS: () => BUILTIN_LOWERING_PLUGINS,
28834
29117
  BaseAdapter: () => BaseAdapter,
29118
+ BindingScope: () => BindingScope,
28835
29119
  CALLBACK_METHODS: () => CALLBACK_METHODS,
28836
29120
  ENV_SIGNAL_READERS: () => ENV_SIGNAL_READERS,
28837
29121
  ErrorCodes: () => ErrorCodes,
@@ -28980,6 +29264,7 @@ __export(src_exports, {
28980
29264
  resolveDangerousInnerHtml: () => resolveDangerousInnerHtml,
28981
29265
  resolveSetters: () => resolveSetters,
28982
29266
  resolveStaticLoopSource: () => resolveStaticLoopSource,
29267
+ rewriteDynamicImportsInSource: () => rewriteDynamicImportsInSource,
28983
29268
  rewriteImportsForTemplate: () => rewriteImportsForTemplate,
28984
29269
  searchParamsLocalNames: () => searchParamsLocalNames,
28985
29270
  serializeParsedExpr: () => serializeParsedExpr,
@@ -29031,6 +29316,7 @@ var init_src2 = __esm({
29031
29316
  init_expression_parser();
29032
29317
  init_loop_chain();
29033
29318
  init_loop_destructure();
29319
+ init_binding_scope();
29034
29320
  init_debug();
29035
29321
  init_profiler();
29036
29322
  init_debug_profile();
@@ -109837,7 +110123,7 @@ __export(scenario_driver_exports, {
109837
110123
  import { writeFileSync as writeFileSync9, mkdtempSync, rmSync, readFileSync as readFileSync19, existsSync as existsSync23, statSync as statSync3 } from "node:fs";
109838
110124
  import { join as join2, dirname as dirname4, resolve as resolve6 } from "node:path";
109839
110125
  import { tmpdir } from "node:os";
109840
- import ts28 from "typescript";
110126
+ import ts29 from "typescript";
109841
110127
  function externalRuntimeImport(clientJs) {
109842
110128
  const chunks = Array.isArray(clientJs) ? clientJs : [clientJs];
109843
110129
  for (const chunk of chunks) {
@@ -109907,11 +110193,11 @@ function resolveLocalFile(spec) {
109907
110193
  }
109908
110194
  function rewriteLocalImports(js, chunkPath, inlined) {
109909
110195
  const chunkDir = dirname4(chunkPath);
109910
- const sf = ts28.createSourceFile("chunk.mjs", js, ts28.ScriptTarget.Latest, false, ts28.ScriptKind.JS);
110196
+ const sf = ts29.createSourceFile("chunk.mjs", js, ts29.ScriptTarget.Latest, false, ts29.ScriptKind.JS);
109911
110197
  const edits = [];
109912
110198
  for (const stmt of sf.statements) {
109913
- if (!ts28.isImportDeclaration(stmt)) continue;
109914
- if (!ts28.isStringLiteral(stmt.moduleSpecifier)) continue;
110199
+ if (!ts29.isImportDeclaration(stmt)) continue;
110200
+ if (!ts29.isStringLiteral(stmt.moduleSpecifier)) continue;
109915
110201
  const spec = stmt.moduleSpecifier.text;
109916
110202
  if (!spec.startsWith(".")) continue;
109917
110203
  const resolved = resolveLocalFile(join2(chunkDir, spec.replace(/\.client\.js$/, "")));
@@ -109923,13 +110209,13 @@ function rewriteLocalImports(js, chunkPath, inlined) {
109923
110209
  const abs = resolve6(resolved);
109924
110210
  if (inlined.has(abs)) {
109925
110211
  const clause = stmt.importClause;
109926
- if (clause && (clause.name || clause.namedBindings && ts28.isNamespaceImport(clause.namedBindings))) {
110212
+ if (clause && (clause.name || clause.namedBindings && ts29.isNamespaceImport(clause.namedBindings))) {
109927
110213
  throw new Error(
109928
110214
  `"${spec}" (imported by ${chunkPath}) uses a default or namespace import of a sibling client file, which the dynamic scenario runner cannot bind after inlining that file into the run. Import its exports by name, or use the static budget (\`bf debug profile <component>\`), which needs no run.`
109929
110215
  );
109930
110216
  }
109931
110217
  const shims = [];
109932
- if (clause?.namedBindings && ts28.isNamedImports(clause.namedBindings)) {
110218
+ if (clause?.namedBindings && ts29.isNamedImports(clause.namedBindings)) {
109933
110219
  for (const el of clause.namedBindings.elements) {
109934
110220
  if (el.propertyName) shims.push(`var ${el.name.text} = ${el.propertyName.text}`);
109935
110221
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/cli",
3
- "version": "0.31.2",
3
+ "version": "0.31.4",
4
4
  "description": "CLI for agent-driven UI component discovery and scaffolding",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,12 +30,12 @@
30
30
  "esbuild": "^0.25.0",
31
31
  "typescript": "^5.0.0",
32
32
  "vite": "^6.0.0",
33
- "@barefootjs/client": "0.31.2",
34
- "@barefootjs/shared": "0.31.2"
33
+ "@barefootjs/client": "0.31.4",
34
+ "@barefootjs/shared": "0.31.4"
35
35
  },
36
36
  "devDependencies": {
37
- "@barefootjs/jsx": "0.31.2",
38
- "@barefootjs/vite": "0.31.2",
37
+ "@barefootjs/jsx": "0.31.4",
38
+ "@barefootjs/vite": "0.31.4",
39
39
  "@happy-dom/global-registrator": "^20.0.11",
40
40
  "@types/node": "^22.0.0",
41
41
  "happy-dom": "^20.0.11"