@barefootjs/erb 0.31.3 → 0.31.5

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.
package/dist/vite.js CHANGED
@@ -5,7 +5,7 @@ import { barefoot as coreBarefoot } from "@barefootjs/vite";
5
5
  import { devModuleUrl, loadManifest, resolveDevOrigin, resolveScriptAssets, toPosixRelative } from "@barefootjs/vite";
6
6
 
7
7
  // ../jsx/src/compiler.ts
8
- import ts23 from "typescript";
8
+ import ts24 from "typescript";
9
9
 
10
10
  // ../jsx/src/analyzer.ts
11
11
  import ts9 from "typescript";
@@ -1948,6 +1948,20 @@ function templatePartsToJsExpr(parts, opts) {
1948
1948
  return result;
1949
1949
  }
1950
1950
 
1951
+ // ../jsx/src/identifier-pattern.ts
1952
+ function withUnicodeFlag(flags) {
1953
+ return flags.includes("u") ? flags : `${flags}u`;
1954
+ }
1955
+ function escapeIdentifierForRegex(name) {
1956
+ return name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1957
+ }
1958
+ var ID_BOUNDARY_BEFORE = "(?<![\\p{ID_Continue}$])";
1959
+ var ID_BOUNDARY_AFTER = "(?![\\p{ID_Continue}$])";
1960
+ function identifierPattern(name, flags = "") {
1961
+ const esc = escapeIdentifierForRegex(name);
1962
+ return new RegExp(`${ID_BOUNDARY_BEFORE}${esc}${ID_BOUNDARY_AFTER}`, withUnicodeFlag(flags));
1963
+ }
1964
+
1951
1965
  // ../jsx/src/scanner/js-scanner.ts
1952
1966
  import ts2 from "typescript";
1953
1967
 
@@ -2065,6 +2079,83 @@ function derivesScopeFromSlot(comp) {
2065
2079
  return comp.slotId != null && comp.loopItemRoot !== true;
2066
2080
  }
2067
2081
 
2082
+ // ../jsx/src/scope/binding-scope.ts
2083
+ class BindingScope {
2084
+ frames;
2085
+ static EMPTY = new BindingScope([]);
2086
+ constructor(frames) {
2087
+ this.frames = frames;
2088
+ }
2089
+ enterLoopRow(loop) {
2090
+ const bindings = new Map;
2091
+ if (loop.paramBindings && loop.paramBindings.length > 0) {
2092
+ for (const b of loop.paramBindings)
2093
+ bindings.set(b.name, { source: "destructure" });
2094
+ } else {
2095
+ bindings.set(loop.param, { source: "item" });
2096
+ }
2097
+ if (loop.index != null)
2098
+ bindings.set(loop.index, { source: "index" });
2099
+ for (const name of loop.preamble?.declaredNames ?? [])
2100
+ bindings.set(name, { source: "preamble" });
2101
+ const frame = { kind: "loop-row", bindings };
2102
+ return new BindingScope([frame, ...this.frames]);
2103
+ }
2104
+ enterCallback(params) {
2105
+ const bindings = new Map;
2106
+ for (const name of params)
2107
+ bindings.set(name, { source: "param" });
2108
+ const frame = { kind: "callback", bindings };
2109
+ return new BindingScope([frame, ...this.frames]);
2110
+ }
2111
+ isBound(name) {
2112
+ for (const frame of this.frames) {
2113
+ if (frame.bindings.has(name))
2114
+ return true;
2115
+ }
2116
+ return false;
2117
+ }
2118
+ lookup(name) {
2119
+ for (let depth = 0;depth < this.frames.length; depth++) {
2120
+ const frame = this.frames[depth];
2121
+ const binding = frame.bindings.get(name);
2122
+ if (binding)
2123
+ return { depth, frame, binding };
2124
+ }
2125
+ return null;
2126
+ }
2127
+ boundNames() {
2128
+ if (this.boundNamesCache)
2129
+ return this.boundNamesCache;
2130
+ const names = new Set;
2131
+ for (const frame of this.frames) {
2132
+ for (const name of frame.bindings.keys())
2133
+ names.add(name);
2134
+ }
2135
+ this.boundNamesCache = names;
2136
+ return names;
2137
+ }
2138
+ boundNamesCache;
2139
+ valueBoundNamesCache;
2140
+ valueBoundNames() {
2141
+ if (this.valueBoundNamesCache)
2142
+ return this.valueBoundNamesCache;
2143
+ const names = new Set;
2144
+ for (const frame of this.frames) {
2145
+ for (const [name, binding] of frame.bindings) {
2146
+ if (binding.source === "item" || binding.source === "index" || binding.source === "destructure") {
2147
+ names.add(name);
2148
+ }
2149
+ }
2150
+ }
2151
+ this.valueBoundNamesCache = names;
2152
+ return names;
2153
+ }
2154
+ asShadowPredicate() {
2155
+ return (name) => this.isBound(name);
2156
+ }
2157
+ }
2158
+
2068
2159
  // ../jsx/src/ir-to-client-js/html-template.ts
2069
2160
  var VOID_ELEMENTS = new Set([
2070
2161
  "area",
@@ -2436,7 +2527,7 @@ var REACTIVE_PRIMITIVES = new Set([
2436
2527
  ]);
2437
2528
 
2438
2529
  // ../jsx/src/jsx-to-ir.ts
2439
- import ts12 from "typescript";
2530
+ import ts13 from "typescript";
2440
2531
 
2441
2532
  // ../jsx/src/types.ts
2442
2533
  var SCOPE_FORBIDDEN = {
@@ -2486,6 +2577,7 @@ function preambleAnalysisTemplateText(p) {
2486
2577
  }
2487
2578
 
2488
2579
  // ../jsx/src/module-exports.ts
2580
+ import ts10 from "typescript";
2489
2581
  function formatParamWithType(p) {
2490
2582
  const rest = p.isRest ? "..." : "";
2491
2583
  const optional = p.optional ? "?" : "";
@@ -2499,7 +2591,7 @@ function findReachableNames(primaryRefs, declarations) {
2499
2591
  const reachable = new Set;
2500
2592
  const queue = [];
2501
2593
  for (const name of allNames) {
2502
- if (new RegExp(`\\b${name}\\b`).test(primaryRefs)) {
2594
+ if (identifierPattern(name).test(primaryRefs)) {
2503
2595
  reachable.add(name);
2504
2596
  queue.push(name);
2505
2597
  }
@@ -2508,7 +2600,7 @@ function findReachableNames(primaryRefs, declarations) {
2508
2600
  const current = queue.shift();
2509
2601
  const body = bodyMap.get(current) || "";
2510
2602
  for (const name of allNames) {
2511
- if (!reachable.has(name) && new RegExp(`\\b${name}\\b`).test(body)) {
2603
+ if (!reachable.has(name) && identifierPattern(name).test(body)) {
2512
2604
  reachable.add(name);
2513
2605
  queue.push(name);
2514
2606
  }
@@ -2516,12 +2608,55 @@ function findReachableNames(primaryRefs, declarations) {
2516
2608
  }
2517
2609
  return reachable;
2518
2610
  }
2611
+ function findAssignedNames(bodyText, candidates) {
2612
+ const assigned = new Set;
2613
+ if (candidates.size === 0)
2614
+ return assigned;
2615
+ const sf = ts10.createSourceFile("bf-assignment-scan.tsx", bodyText, ts10.ScriptTarget.Latest, false, ts10.ScriptKind.TSX);
2616
+ const record = (target) => {
2617
+ if (ts10.isIdentifier(target) && candidates.has(target.text)) {
2618
+ assigned.add(target.text);
2619
+ }
2620
+ };
2621
+ const visit = (node) => {
2622
+ if (ts10.isBinaryExpression(node) && isAssignmentOperator(node.operatorToken.kind)) {
2623
+ record(node.left);
2624
+ } else if ((ts10.isPrefixUnaryExpression(node) || ts10.isPostfixUnaryExpression(node)) && (node.operator === ts10.SyntaxKind.PlusPlusToken || node.operator === ts10.SyntaxKind.MinusMinusToken)) {
2625
+ record(node.operand);
2626
+ }
2627
+ ts10.forEachChild(node, visit);
2628
+ };
2629
+ ts10.forEachChild(sf, visit);
2630
+ return assigned;
2631
+ }
2632
+ function closeOverWritersOfMutableBindings(primaryRefs, declarations, mutableNames) {
2633
+ let reachable = findReachableNames(primaryRefs, declarations);
2634
+ if (mutableNames.size === 0)
2635
+ return reachable;
2636
+ let seedText = primaryRefs;
2637
+ for (let round = 0;round <= declarations.length; round++) {
2638
+ const survivingMutables = new Set([...reachable].filter((name) => mutableNames.has(name)));
2639
+ if (survivingMutables.size === 0)
2640
+ return reachable;
2641
+ const added = declarations.filter((d) => !reachable.has(d.name)).filter((d) => findAssignedNames(d.body, survivingMutables).size > 0).map((d) => d.name);
2642
+ if (added.length === 0)
2643
+ return reachable;
2644
+ seedText += `
2645
+ ` + added.join(`
2646
+ `);
2647
+ reachable = findReachableNames(seedText, declarations);
2648
+ }
2649
+ return reachable;
2650
+ }
2651
+ function isAssignmentOperator(kind) {
2652
+ return kind >= ts10.SyntaxKind.FirstAssignment && kind <= ts10.SyntaxKind.LastAssignment;
2653
+ }
2519
2654
 
2520
2655
  // ../jsx/src/reactivity-checker.ts
2521
- import ts10 from "typescript";
2656
+ import ts11 from "typescript";
2522
2657
 
2523
2658
  // ../jsx/src/free-refs.ts
2524
- import ts11 from "typescript";
2659
+ import ts12 from "typescript";
2525
2660
  var _bindingMapCache = new WeakMap;
2526
2661
 
2527
2662
  // ../jsx/src/to-locale-date-lowering.ts
@@ -2839,83 +2974,6 @@ var toLocaleDatePlugin = {
2839
2974
  }
2840
2975
  };
2841
2976
 
2842
- // ../jsx/src/scope/binding-scope.ts
2843
- class BindingScope {
2844
- frames;
2845
- static EMPTY = new BindingScope([]);
2846
- constructor(frames) {
2847
- this.frames = frames;
2848
- }
2849
- enterLoopRow(loop) {
2850
- const bindings = new Map;
2851
- if (loop.paramBindings && loop.paramBindings.length > 0) {
2852
- for (const b of loop.paramBindings)
2853
- bindings.set(b.name, { source: "destructure" });
2854
- } else {
2855
- bindings.set(loop.param, { source: "item" });
2856
- }
2857
- if (loop.index != null)
2858
- bindings.set(loop.index, { source: "index" });
2859
- for (const name of loop.preamble?.declaredNames ?? [])
2860
- bindings.set(name, { source: "preamble" });
2861
- const frame = { kind: "loop-row", bindings };
2862
- return new BindingScope([frame, ...this.frames]);
2863
- }
2864
- enterCallback(params) {
2865
- const bindings = new Map;
2866
- for (const name of params)
2867
- bindings.set(name, { source: "param" });
2868
- const frame = { kind: "callback", bindings };
2869
- return new BindingScope([frame, ...this.frames]);
2870
- }
2871
- isBound(name) {
2872
- for (const frame of this.frames) {
2873
- if (frame.bindings.has(name))
2874
- return true;
2875
- }
2876
- return false;
2877
- }
2878
- lookup(name) {
2879
- for (let depth = 0;depth < this.frames.length; depth++) {
2880
- const frame = this.frames[depth];
2881
- const binding = frame.bindings.get(name);
2882
- if (binding)
2883
- return { depth, frame, binding };
2884
- }
2885
- return null;
2886
- }
2887
- boundNames() {
2888
- if (this.boundNamesCache)
2889
- return this.boundNamesCache;
2890
- const names = new Set;
2891
- for (const frame of this.frames) {
2892
- for (const name of frame.bindings.keys())
2893
- names.add(name);
2894
- }
2895
- this.boundNamesCache = names;
2896
- return names;
2897
- }
2898
- boundNamesCache;
2899
- valueBoundNamesCache;
2900
- valueBoundNames() {
2901
- if (this.valueBoundNamesCache)
2902
- return this.valueBoundNamesCache;
2903
- const names = new Set;
2904
- for (const frame of this.frames) {
2905
- for (const [name, binding] of frame.bindings) {
2906
- if (binding.source === "item" || binding.source === "index" || binding.source === "destructure") {
2907
- names.add(name);
2908
- }
2909
- }
2910
- }
2911
- this.valueBoundNamesCache = names;
2912
- return names;
2913
- }
2914
- asShadowPredicate() {
2915
- return (name) => this.isBound(name);
2916
- }
2917
- }
2918
-
2919
2977
  // ../jsx/src/jsx-to-ir.ts
2920
2978
  var EMPTY_BOUND = new Set;
2921
2979
  var constInitializerCache = new WeakMap;
@@ -3012,13 +3070,13 @@ var KEYWORDS_AND_GLOBALS = new Set([
3012
3070
  ]);
3013
3071
 
3014
3072
  // ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
3015
- import ts13 from "typescript";
3073
+ import ts14 from "typescript";
3016
3074
 
3017
3075
  // ../jsx/src/value-references.ts
3018
- import ts14 from "typescript";
3076
+ import ts15 from "typescript";
3019
3077
 
3020
3078
  // ../jsx/src/relocate.ts
3021
- import ts15 from "typescript";
3079
+ import ts16 from "typescript";
3022
3080
 
3023
3081
  // ../jsx/src/lowering-registry.ts
3024
3082
  var plugins = [];
@@ -3235,10 +3293,10 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
3235
3293
  }
3236
3294
 
3237
3295
  // ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
3238
- import ts16 from "typescript";
3296
+ import ts17 from "typescript";
3239
3297
 
3240
3298
  // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3241
- import ts17 from "typescript";
3299
+ import ts18 from "typescript";
3242
3300
  var NO_PREAMBLE = {
3243
3301
  lazySafe: true,
3244
3302
  facts: { declaredNames: new Set, freeNames: new Set }
@@ -3288,7 +3346,7 @@ var INERT_BINDING_GLOBALS = new Set([
3288
3346
  ]);
3289
3347
 
3290
3348
  // ../jsx/src/ir-to-client-js/emit-reactive.ts
3291
- import ts18 from "typescript";
3349
+ import ts19 from "typescript";
3292
3350
 
3293
3351
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
3294
3352
  var NON_BUBBLING_EVENTS = new Set([
@@ -3303,7 +3361,7 @@ var NON_BUBBLING_EVENTS = new Set([
3303
3361
  ]);
3304
3362
 
3305
3363
  // ../jsx/src/ir-to-client-js/rewrite-props-object.ts
3306
- import ts19 from "typescript";
3364
+ import ts20 from "typescript";
3307
3365
 
3308
3366
  // ../jsx/src/ir-to-client-js/source-map.ts
3309
3367
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -3394,15 +3452,15 @@ class SourceMapGenerator {
3394
3452
  }
3395
3453
 
3396
3454
  // ../jsx/src/preprocess-inline-jsx-callbacks.ts
3397
- import ts20 from "typescript";
3455
+ import ts21 from "typescript";
3398
3456
 
3399
3457
  // ../jsx/src/ssr-defaults.ts
3400
- import ts21 from "typescript";
3458
+ import ts22 from "typescript";
3401
3459
  var UNRESOLVED = Symbol("unresolved");
3402
3460
  var NO_RETURN = Symbol("no-return");
3403
3461
 
3404
3462
  // ../jsx/src/augment-inherited-props.ts
3405
- import ts22 from "typescript";
3463
+ import ts23 from "typescript";
3406
3464
  function collectContextConsumers(metadata) {
3407
3465
  const constants = metadata.localConstants ?? [];
3408
3466
  const contextDefaults = new Map;
@@ -3434,47 +3492,47 @@ function collectContextConsumers(metadata) {
3434
3492
  }
3435
3493
  function parseUseContextArg(source) {
3436
3494
  const expr = parseSingleExpression(source);
3437
- if (!expr || !ts22.isCallExpression(expr))
3495
+ if (!expr || !ts23.isCallExpression(expr))
3438
3496
  return null;
3439
- if (!ts22.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
3497
+ if (!ts23.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
3440
3498
  return null;
3441
3499
  if (expr.arguments.length !== 1)
3442
3500
  return null;
3443
3501
  const arg = expr.arguments[0];
3444
- return ts22.isIdentifier(arg) ? arg.text : null;
3502
+ return ts23.isIdentifier(arg) ? arg.text : null;
3445
3503
  }
3446
3504
  function parseCreateContextDefault(source) {
3447
3505
  const expr = parseSingleExpression(source);
3448
- if (!expr || !ts22.isCallExpression(expr))
3506
+ if (!expr || !ts23.isCallExpression(expr))
3449
3507
  return null;
3450
3508
  if (expr.arguments.length === 0)
3451
3509
  return null;
3452
3510
  const arg = expr.arguments[0];
3453
- if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
3511
+ if (ts23.isStringLiteral(arg) || ts23.isNoSubstitutionTemplateLiteral(arg))
3454
3512
  return arg.text;
3455
- if (ts22.isNumericLiteral(arg))
3513
+ if (ts23.isNumericLiteral(arg))
3456
3514
  return Number(arg.text);
3457
- if (arg.kind === ts22.SyntaxKind.TrueKeyword)
3515
+ if (arg.kind === ts23.SyntaxKind.TrueKeyword)
3458
3516
  return true;
3459
- if (arg.kind === ts22.SyntaxKind.FalseKeyword)
3517
+ if (arg.kind === ts23.SyntaxKind.FalseKeyword)
3460
3518
  return false;
3461
3519
  return null;
3462
3520
  }
3463
3521
  function isObjectLiteralCreateContextDefault(source) {
3464
3522
  const expr = parseSingleExpression(source);
3465
- if (!expr || !ts22.isCallExpression(expr))
3523
+ if (!expr || !ts23.isCallExpression(expr))
3466
3524
  return false;
3467
3525
  if (expr.arguments.length === 0)
3468
3526
  return false;
3469
- return ts22.isObjectLiteralExpression(expr.arguments[0]);
3527
+ return ts23.isObjectLiteralExpression(expr.arguments[0]);
3470
3528
  }
3471
3529
  function parseSingleExpression(source) {
3472
- const sf = ts22.createSourceFile("__ctx.ts", `(${source})`, ts22.ScriptTarget.Latest, false);
3530
+ const sf = ts23.createSourceFile("__ctx.ts", `(${source})`, ts23.ScriptTarget.Latest, false);
3473
3531
  const stmt = sf.statements[0];
3474
- if (!stmt || !ts22.isExpressionStatement(stmt))
3532
+ if (!stmt || !ts23.isExpressionStatement(stmt))
3475
3533
  return null;
3476
3534
  let e = stmt.expression;
3477
- while (ts22.isParenthesizedExpression(e))
3535
+ while (ts23.isParenthesizedExpression(e))
3478
3536
  e = e.expression;
3479
3537
  return e;
3480
3538
  }
@@ -3499,25 +3557,25 @@ function augmentInheritedPropAccesses(ir) {
3499
3557
  const pinCoalesceLiterals = (s) => {
3500
3558
  if (!s || !s.includes(propsObj))
3501
3559
  return;
3502
- const sf = ts22.createSourceFile("__aug.ts", `(${s})`, ts22.ScriptTarget.Latest, false);
3560
+ const sf = ts23.createSourceFile("__aug.ts", `(${s})`, ts23.ScriptTarget.Latest, false);
3503
3561
  const visit = (n) => {
3504
- if (ts22.isBinaryExpression(n) && (n.operatorToken.kind === ts22.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts22.SyntaxKind.BarBarToken)) {
3562
+ if (ts23.isBinaryExpression(n) && (n.operatorToken.kind === ts23.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts23.SyntaxKind.BarBarToken)) {
3505
3563
  let left = n.left;
3506
- while (ts22.isParenthesizedExpression(left))
3564
+ while (ts23.isParenthesizedExpression(left))
3507
3565
  left = left.expression;
3508
- if (ts22.isPropertyAccessExpression(left) && ts22.isIdentifier(left.expression) && left.expression.text === propsObj) {
3566
+ if (ts23.isPropertyAccessExpression(left) && ts23.isIdentifier(left.expression) && left.expression.text === propsObj) {
3509
3567
  const name = left.name.text;
3510
3568
  let right = n.right;
3511
- while (ts22.isParenthesizedExpression(right))
3569
+ while (ts23.isParenthesizedExpression(right))
3512
3570
  right = right.expression;
3513
- if (ts22.isPrefixUnaryExpression(right))
3571
+ if (ts23.isPrefixUnaryExpression(right))
3514
3572
  right = right.operand;
3515
- const kind = ts22.isNumericLiteral(right) ? "number" : right.kind === ts22.SyntaxKind.TrueKeyword || right.kind === ts22.SyntaxKind.FalseKeyword ? "boolean" : ts22.isStringLiteralLike(right) ? "string" : null;
3573
+ const kind = ts23.isNumericLiteral(right) ? "number" : right.kind === ts23.SyntaxKind.TrueKeyword || right.kind === ts23.SyntaxKind.FalseKeyword ? "boolean" : ts23.isStringLiteralLike(right) ? "string" : null;
3516
3574
  if (kind && !coalesceLiteralTypes.has(name))
3517
3575
  coalesceLiteralTypes.set(name, kind);
3518
3576
  }
3519
3577
  }
3520
- ts22.forEachChild(n, visit);
3578
+ ts23.forEachChild(n, visit);
3521
3579
  };
3522
3580
  visit(sf);
3523
3581
  };
@@ -3628,33 +3686,33 @@ function augmentInheritedPropAccesses(ir) {
3628
3686
  }
3629
3687
  }
3630
3688
  function parseStaticStringConst(source) {
3631
- const sf = ts22.createSourceFile("__const.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
3689
+ const sf = ts23.createSourceFile("__const.ts", `const __x = (${source});`, ts23.ScriptTarget.Latest, false);
3632
3690
  const stmt = sf.statements[0];
3633
- if (!stmt || !ts22.isVariableStatement(stmt))
3691
+ if (!stmt || !ts23.isVariableStatement(stmt))
3634
3692
  return null;
3635
3693
  let init = stmt.declarationList.declarations[0]?.initializer;
3636
- while (init && ts22.isParenthesizedExpression(init))
3694
+ while (init && ts23.isParenthesizedExpression(init))
3637
3695
  init = init.expression;
3638
3696
  if (!init)
3639
3697
  return null;
3640
- if (ts22.isStringLiteral(init) || ts22.isNoSubstitutionTemplateLiteral(init)) {
3698
+ if (ts23.isStringLiteral(init) || ts23.isNoSubstitutionTemplateLiteral(init)) {
3641
3699
  return init.text;
3642
3700
  }
3643
3701
  return evalStringArrayJoin(source);
3644
3702
  }
3645
3703
  function evalTemplateOfStringConsts(source, resolved) {
3646
- const sf = ts22.createSourceFile("__const.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
3704
+ const sf = ts23.createSourceFile("__const.ts", `const __x = (${source});`, ts23.ScriptTarget.Latest, false);
3647
3705
  const stmt = sf.statements[0];
3648
- if (!stmt || !ts22.isVariableStatement(stmt))
3706
+ if (!stmt || !ts23.isVariableStatement(stmt))
3649
3707
  return null;
3650
3708
  let init = stmt.declarationList.declarations[0]?.initializer;
3651
- while (init && ts22.isParenthesizedExpression(init))
3709
+ while (init && ts23.isParenthesizedExpression(init))
3652
3710
  init = init.expression;
3653
- if (!init || !ts22.isTemplateExpression(init))
3711
+ if (!init || !ts23.isTemplateExpression(init))
3654
3712
  return null;
3655
3713
  let out = init.head.text;
3656
3714
  for (const span of init.templateSpans) {
3657
- if (!ts22.isIdentifier(span.expression))
3715
+ if (!ts23.isIdentifier(span.expression))
3658
3716
  return null;
3659
3717
  const value = resolved.get(span.expression.text);
3660
3718
  if (value === undefined)
@@ -3681,34 +3739,36 @@ function collectModuleStringConsts(constants) {
3681
3739
  }
3682
3740
  return map;
3683
3741
  }
3684
- function lookupStaticRecordLiteral(objectName, key, constants) {
3742
+ function lookupStaticRecordLiteral(objectName, key, constants, isShadowed) {
3743
+ if (isShadowed(objectName))
3744
+ return null;
3685
3745
  const constInfo = (constants ?? []).find((c) => c.name === objectName && c.isModule);
3686
3746
  if (constInfo?.value === undefined)
3687
3747
  return null;
3688
- const sf = ts22.createSourceFile("__rec.ts", `(${constInfo.value})`, ts22.ScriptTarget.Latest, true);
3748
+ const sf = ts23.createSourceFile("__rec.ts", `(${constInfo.value})`, ts23.ScriptTarget.Latest, true);
3689
3749
  if (sf.statements.length !== 1)
3690
3750
  return null;
3691
3751
  const stmt = sf.statements[0];
3692
- if (!ts22.isExpressionStatement(stmt))
3752
+ if (!ts23.isExpressionStatement(stmt))
3693
3753
  return null;
3694
3754
  let parsed = stmt.expression;
3695
- while (ts22.isParenthesizedExpression(parsed))
3755
+ while (ts23.isParenthesizedExpression(parsed))
3696
3756
  parsed = parsed.expression;
3697
- if (!ts22.isObjectLiteralExpression(parsed))
3757
+ if (!ts23.isObjectLiteralExpression(parsed))
3698
3758
  return null;
3699
3759
  for (const prop of parsed.properties) {
3700
- if (!ts22.isPropertyAssignment(prop))
3760
+ if (!ts23.isPropertyAssignment(prop))
3701
3761
  continue;
3702
3762
  const name = prop.name;
3703
- const propKey = ts22.isIdentifier(name) || ts22.isStringLiteral(name) || ts22.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
3763
+ const propKey = ts23.isIdentifier(name) || ts23.isStringLiteral(name) || ts23.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
3704
3764
  if (propKey !== key)
3705
3765
  continue;
3706
3766
  let v = prop.initializer;
3707
- while (ts22.isParenthesizedExpression(v))
3767
+ while (ts23.isParenthesizedExpression(v))
3708
3768
  v = v.expression;
3709
- if (ts22.isNumericLiteral(v))
3769
+ if (ts23.isNumericLiteral(v))
3710
3770
  return { kind: "number", text: v.text };
3711
- if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
3771
+ if (ts23.isStringLiteral(v) || ts23.isNoSubstitutionTemplateLiteral(v)) {
3712
3772
  return { kind: "string", text: v.text };
3713
3773
  }
3714
3774
  return null;
@@ -3716,28 +3776,28 @@ function lookupStaticRecordLiteral(objectName, key, constants) {
3716
3776
  return null;
3717
3777
  }
3718
3778
  function evalStringArrayJoin(source) {
3719
- const sf = ts22.createSourceFile("__join.ts", `const __x = (${source});`, ts22.ScriptTarget.Latest, false);
3779
+ const sf = ts23.createSourceFile("__join.ts", `const __x = (${source});`, ts23.ScriptTarget.Latest, false);
3720
3780
  const stmt = sf.statements[0];
3721
- if (!stmt || !ts22.isVariableStatement(stmt))
3781
+ if (!stmt || !ts23.isVariableStatement(stmt))
3722
3782
  return null;
3723
3783
  let node = stmt.declarationList.declarations[0]?.initializer;
3724
- while (node && ts22.isParenthesizedExpression(node))
3784
+ while (node && ts23.isParenthesizedExpression(node))
3725
3785
  node = node.expression;
3726
- if (!node || !ts22.isCallExpression(node))
3786
+ if (!node || !ts23.isCallExpression(node))
3727
3787
  return null;
3728
3788
  const callee = node.expression;
3729
- if (!ts22.isPropertyAccessExpression(callee))
3789
+ if (!ts23.isPropertyAccessExpression(callee))
3730
3790
  return null;
3731
3791
  if (callee.name.text !== "join")
3732
3792
  return null;
3733
3793
  let recv = callee.expression;
3734
- while (ts22.isParenthesizedExpression(recv))
3794
+ while (ts23.isParenthesizedExpression(recv))
3735
3795
  recv = recv.expression;
3736
- if (!ts22.isArrayLiteralExpression(recv))
3796
+ if (!ts23.isArrayLiteralExpression(recv))
3737
3797
  return null;
3738
3798
  const parts = [];
3739
3799
  for (const el of recv.elements) {
3740
- if (ts22.isStringLiteral(el) || ts22.isNoSubstitutionTemplateLiteral(el)) {
3800
+ if (ts23.isStringLiteral(el) || ts23.isNoSubstitutionTemplateLiteral(el)) {
3741
3801
  parts.push(el.text);
3742
3802
  } else {
3743
3803
  return null;
@@ -3746,7 +3806,7 @@ function evalStringArrayJoin(source) {
3746
3806
  let sep = ",";
3747
3807
  if (node.arguments.length >= 1) {
3748
3808
  const arg = node.arguments[0];
3749
- if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
3809
+ if (ts23.isStringLiteral(arg) || ts23.isNoSubstitutionTemplateLiteral(arg))
3750
3810
  sep = arg.text;
3751
3811
  else
3752
3812
  return null;
@@ -3754,11 +3814,11 @@ function evalStringArrayJoin(source) {
3754
3814
  return parts.join(sep);
3755
3815
  }
3756
3816
  function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3757
- if (!ts22.isElementAccessExpression(val))
3817
+ if (!ts23.isElementAccessExpression(val))
3758
3818
  return null;
3759
3819
  const obj = val.expression;
3760
3820
  const arg = val.argumentExpression;
3761
- if (!ts22.isIdentifier(obj) || !ts22.isIdentifier(arg))
3821
+ if (!ts23.isIdentifier(obj) || !ts23.isIdentifier(arg))
3762
3822
  return null;
3763
3823
  let indexPropName;
3764
3824
  let defaultKey;
@@ -3774,35 +3834,35 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3774
3834
  const constInfo = localConstants.find((c) => c.name === obj.text && c.isModule);
3775
3835
  if (constInfo?.value === undefined)
3776
3836
  return null;
3777
- const sf = ts22.createSourceFile("__rec.ts", `(${constInfo.value})`, ts22.ScriptTarget.Latest, true);
3837
+ const sf = ts23.createSourceFile("__rec.ts", `(${constInfo.value})`, ts23.ScriptTarget.Latest, true);
3778
3838
  if (sf.statements.length !== 1)
3779
3839
  return null;
3780
3840
  const stmt = sf.statements[0];
3781
- if (!ts22.isExpressionStatement(stmt))
3841
+ if (!ts23.isExpressionStatement(stmt))
3782
3842
  return null;
3783
3843
  let parsed = stmt.expression;
3784
- while (ts22.isParenthesizedExpression(parsed))
3844
+ while (ts23.isParenthesizedExpression(parsed))
3785
3845
  parsed = parsed.expression;
3786
- if (!ts22.isObjectLiteralExpression(parsed))
3846
+ if (!ts23.isObjectLiteralExpression(parsed))
3787
3847
  return null;
3788
3848
  const entries = [];
3789
3849
  for (const prop of parsed.properties) {
3790
- if (!ts22.isPropertyAssignment(prop))
3850
+ if (!ts23.isPropertyAssignment(prop))
3791
3851
  return null;
3792
3852
  let key;
3793
- if (ts22.isIdentifier(prop.name)) {
3853
+ if (ts23.isIdentifier(prop.name)) {
3794
3854
  key = prop.name.text;
3795
- } else if (ts22.isStringLiteral(prop.name) || ts22.isNoSubstitutionTemplateLiteral(prop.name)) {
3855
+ } else if (ts23.isStringLiteral(prop.name) || ts23.isNoSubstitutionTemplateLiteral(prop.name)) {
3796
3856
  key = prop.name.text;
3797
3857
  } else {
3798
3858
  return null;
3799
3859
  }
3800
3860
  let v = prop.initializer;
3801
- while (ts22.isParenthesizedExpression(v))
3861
+ while (ts23.isParenthesizedExpression(v))
3802
3862
  v = v.expression;
3803
- if (ts22.isNumericLiteral(v)) {
3863
+ if (ts23.isNumericLiteral(v)) {
3804
3864
  entries.push({ key, value: { kind: "number", text: v.text } });
3805
- } else if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
3865
+ } else if (ts23.isStringLiteral(v) || ts23.isNoSubstitutionTemplateLiteral(v)) {
3806
3866
  entries.push({ key, value: { kind: "string", text: v.text } });
3807
3867
  } else {
3808
3868
  return null;
@@ -3858,7 +3918,7 @@ function computeSsrSeedPlan(metadata) {
3858
3918
  // ../jsx/src/rich-type-refusal.ts
3859
3919
  var EMPTY_BINDINGS2 = new Map;
3860
3920
  // ../jsx/src/shared-program.ts
3861
- import ts24 from "typescript";
3921
+ import ts25 from "typescript";
3862
3922
  // ../jsx/src/adapters/interface.ts
3863
3923
  class BaseAdapter {
3864
3924
  renderChildren(children) {
@@ -3911,7 +3971,7 @@ class JsxAdapter extends BaseAdapter {
3911
3971
  ...localFunctions.map((f) => ({ name: f.name, body: f.body })),
3912
3972
  ...localConstants.map((c) => ({ name: c.name, body: c.value }))
3913
3973
  ];
3914
- const reachable = findReachableNames(primaryRefText, declarations);
3974
+ const reachable = closeOverWritersOfMutableBindings(primaryRefText, declarations, new Set(ir.metadata.localConstants.filter((c) => (c.declarationKind ?? "const") !== "const").map((c) => c.name)));
3915
3975
  const reachableBodies = [...reachable].map((name) => {
3916
3976
  const func = localFunctions.find((f) => f.name === name);
3917
3977
  if (func)
@@ -3941,9 +4001,10 @@ class JsxAdapter extends BaseAdapter {
3941
4001
  lines.push(` const ${signal.getter} = () => ${initialValue}`);
3942
4002
  }
3943
4003
  if (signal.setter) {
3944
- const setterUsed = new RegExp(`\\b${signal.setter}\\b`).test(setterRefText);
4004
+ const setterUsed = identifierPattern(signal.setter).test(setterRefText);
3945
4005
  if (setterUsed) {
3946
- lines.push(` const ${signal.setter} = (..._args: any[]) => {}`);
4006
+ const setterType = preserveTypes && signal.type.kind !== "unknown" ? `(valueOrFn: ${signal.type.raw} | ((prev: ${signal.type.raw}) => ${signal.type.raw})) => void` : null;
4007
+ lines.push(setterType ? ` const ${signal.setter}: ${setterType} = () => {}` : ` const ${signal.setter} = (..._args: any[]) => {}`);
3947
4008
  }
3948
4009
  }
3949
4010
  }
@@ -4139,6 +4200,7 @@ class JsxAdapter extends BaseAdapter {
4139
4200
  }
4140
4201
 
4141
4202
  // ../jsx/src/adapters/template-imports.ts
4203
+ import ts26 from "typescript";
4142
4204
  var CLIENT_PACKAGE_SOURCES = new Set([
4143
4205
  "@barefootjs/client",
4144
4206
  "@barefootjs/client/runtime"
@@ -4277,7 +4339,8 @@ export default ${this.componentName}` : "";
4277
4339
  const noArgDefault = hasRequiredProps ? "" : ` = {} as ${propsTypeExpr}`;
4278
4340
  const lines = [];
4279
4341
  const exportPrefix = ir.metadata.isExported === false ? "" : "export ";
4280
- lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
4342
+ const typeParameters = ir.metadata.typeParameters ?? "";
4343
+ lines.push(`${exportPrefix}function ${name}${typeParameters}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
4281
4344
  if (hasClientInteractivity) {
4282
4345
  lines.push(` const __scopeId = (/_s\\d/.test(__bfScope || '') ? __bfScope : null) || __instanceId || \`${name}_\${Math.random().toString(36).slice(2, 8)}\``);
4283
4346
  } else {
@@ -4812,7 +4875,7 @@ function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
4812
4875
  };
4813
4876
  }
4814
4877
  // ../jsx/src/combine-client-js.ts
4815
- import ts25 from "typescript";
4878
+ import ts27 from "typescript";
4816
4879
  // ../jsx/src/loop-destructure.ts
4817
4880
  function isLowerableLoopDestructure(loop) {
4818
4881
  const bindings = loop.paramBindings;
@@ -4952,9 +5015,9 @@ function escapeRe(s) {
4952
5015
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4953
5016
  }
4954
5017
  // ../jsx/src/debug.ts
4955
- import ts26 from "typescript";
5018
+ import ts28 from "typescript";
4956
5019
  // ../jsx/src/profiler.ts
4957
- import ts27 from "typescript";
5020
+ import ts29 from "typescript";
4958
5021
 
4959
5022
  // ../jsx/src/index.ts
4960
5023
  registerBuiltinLoweringPlugins();
@@ -5825,7 +5888,7 @@ function collectImportedLoopChildComponentErrors(ir, componentName) {
5825
5888
  }
5826
5889
 
5827
5890
  // src/adapter/spread/spread-codegen.ts
5828
- import ts28 from "typescript";
5891
+ import ts30 from "typescript";
5829
5892
  function conditionalSpreadToRuby(ctx, expr) {
5830
5893
  if (!expr || expr.kind !== "conditional")
5831
5894
  return null;
@@ -5880,7 +5943,7 @@ function recordIndexAccessToRuby(ctx, val) {
5880
5943
  if (val.kind !== "index-access" || val.object.kind !== "identifier" || val.index.kind !== "identifier") {
5881
5944
  return null;
5882
5945
  }
5883
- const tsVal = ts28.factory.createElementAccessExpression(ts28.factory.createIdentifier(val.object.name), ts28.factory.createIdentifier(val.index.name));
5946
+ const tsVal = ts30.factory.createElementAccessExpression(ts30.factory.createIdentifier(val.object.name), ts30.factory.createIdentifier(val.index.name));
5884
5947
  const parsed = parseRecordIndexAccess(tsVal, ctx.localConstants, ctx.propsParams);
5885
5948
  if (!parsed)
5886
5949
  return null;
@@ -5993,7 +6056,7 @@ class ErbAdapter extends BaseAdapter {
5993
6056
  _loweringMatchers = [];
5994
6057
  moduleStringConsts = new Map;
5995
6058
  localConstants = [];
5996
- loopBoundNames = new Map;
6059
+ scope = BindingScope.EMPTY;
5997
6060
  nullableOptionalProps = new Set;
5998
6061
  constructor(options = {}) {
5999
6062
  super();
@@ -6015,7 +6078,7 @@ class ErbAdapter extends BaseAdapter {
6015
6078
  this._searchParamsLocals = searchParamsLocalNames(ir.metadata);
6016
6079
  this._loweringMatchers = prepareLoweringMatchers(ir.metadata);
6017
6080
  this.localConstants = ir.metadata.localConstants ?? [];
6018
- this.loopBoundNames.clear();
6081
+ this.scope = BindingScope.EMPTY;
6019
6082
  this.errors = [];
6020
6083
  this.childrenCaptureCounter = 0;
6021
6084
  if (!options?.siblingTemplatesRegistered) {
@@ -6073,7 +6136,7 @@ class ErbAdapter extends BaseAdapter {
6073
6136
  };
6074
6137
  }
6075
6138
  resolveLiteralConst(name) {
6076
- if (this.loopBoundNames?.has?.(name))
6139
+ if (this.scope.isBound(name))
6077
6140
  return null;
6078
6141
  const c = (this.localConstants ?? []).find((lc) => lc.name === name);
6079
6142
  if (c?.value === undefined)
@@ -6087,15 +6150,13 @@ class ErbAdapter extends BaseAdapter {
6087
6150
  return null;
6088
6151
  }
6089
6152
  resolveStaticRecordLiteral(objectName, key) {
6090
- if (this.loopBoundNames?.has?.(objectName))
6091
- return null;
6092
- const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
6153
+ const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants, (name) => this.scope.isBound(name));
6093
6154
  if (!hit)
6094
6155
  return null;
6095
6156
  return hit.kind === "number" ? hit.text : rubyStringLiteral(hit.text);
6096
6157
  }
6097
6158
  resolveModuleStringConst(name) {
6098
- if (this.loopBoundNames.has(name))
6159
+ if (this.scope.isBound(name))
6099
6160
  return null;
6100
6161
  const value = this.moduleStringConsts.get(name);
6101
6162
  if (value === undefined)
@@ -6103,7 +6164,7 @@ class ErbAdapter extends BaseAdapter {
6103
6164
  return rubyStringLiteral(value);
6104
6165
  }
6105
6166
  isLoopBoundName(name) {
6106
- return this.loopBoundNames.has(name);
6167
+ return this.scope.isBound(name);
6107
6168
  }
6108
6169
  generateScriptRegistrations(ir, scriptBaseName, scriptAssets, preloadAssets) {
6109
6170
  if (scriptAssets) {
@@ -6380,12 +6441,12 @@ ${whenTrue}
6380
6441
  });
6381
6442
  }
6382
6443
  const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
6383
- isNameShadowed: (name) => this.loopBoundNames.has(name)
6444
+ isNameShadowed: this.scope.asShadowPredicate()
6384
6445
  });
6385
6446
  const staticArray = staticItems !== null ? staticValueToRuby(staticItems) : null;
6386
6447
  if (staticArray === null && loop.arrayParsed?.kind === "identifier") {
6387
6448
  const arrayName = loop.arrayParsed.name;
6388
- const isUnresolvableLocalConst = !this.loopBoundNames.has(arrayName) && this.resolveModuleStringConst(arrayName) === null && this.resolveLiteralConst(arrayName) === null && this.localConstants.some((c) => c.name === arrayName && !c.isModule);
6449
+ const isUnresolvableLocalConst = !this.scope.isBound(arrayName) && this.resolveModuleStringConst(arrayName) === null && this.resolveLiteralConst(arrayName) === null && this.localConstants.some((c) => c.name === arrayName && !c.isModule);
6389
6450
  if (isUnresolvableLocalConst) {
6390
6451
  this._recordExprBF101(`Loop array \`${arrayName}\` is a component-scope const computed from a runtime expression the ERB adapter cannot evaluate at SSR render time.`, `Options:
6391
6452
  1. Inline the array expression directly in the .map() call instead of a preceding const.
@@ -6402,13 +6463,9 @@ ${whenTrue}
6402
6463
  }
6403
6464
  const param = loop.param;
6404
6465
  const indexVar = loop.iterationShape === "keys" ? rubyLocal(param) : rubyLocal(loop.index ?? "_i");
6405
- const loopBound = loop.objectIteration === "entries" ? [param, loop.index ?? "_k"] : loop.objectIteration === "keys" || loop.objectIteration === "values" || loop.iterationShape === "keys" ? [param] : supportableDestructure ? ["__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name), loop.index ?? "_i"] : [param, loop.index ?? "_i"];
6406
6466
  const preambleDecls = loop.preamble?.declarations ?? [];
6407
- for (const d of preambleDecls)
6408
- loopBound.push(d.name);
6409
- for (const n of loopBound) {
6410
- this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
6411
- }
6467
+ const prevScope = this.scope;
6468
+ this.scope = prevScope.enterLoopRow(loop);
6412
6469
  const prevLoopKeyDepth = this.currentLoopKeyDepth;
6413
6470
  this.currentLoopKeyDepth = loop.depth;
6414
6471
  const renderedChildren = this.renderChildren(loop.children);
@@ -6418,13 +6475,7 @@ ${renderedChildren}` : renderedChildren;
6418
6475
  const lines = [];
6419
6476
  lines.push(`<%= bf.comment("loop:${loop.markerId}") %>`);
6420
6477
  if (sortedHoist && loop.sortComparator) {
6421
- for (const n of loopBound) {
6422
- const c = (this.loopBoundNames.get(n) ?? 1) - 1;
6423
- if (c <= 0)
6424
- this.loopBoundNames.delete(n);
6425
- else
6426
- this.loopBoundNames.set(n, c);
6427
- }
6478
+ this.scope = prevScope;
6428
6479
  const sortEmit = (e) => this.convertExpressionToRuby("", e);
6429
6480
  const sortArrow = loop.sortComparator.arrow;
6430
6481
  let sorted = null;
@@ -6440,9 +6491,7 @@ ${renderedChildren}` : renderedChildren;
6440
6491
  this._recordExprBF101(`.sort(...) loop comparator is not lowerable to a template sort`, `Pre-sort the array in the route handler, or mark the loop @client-only.`);
6441
6492
  sorted = rawArray;
6442
6493
  }
6443
- for (const n of loopBound) {
6444
- this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
6445
- }
6494
+ this.scope = prevScope.enterLoopRow(loop);
6446
6495
  lines.push(`<%- ${sortedHoist} = ${sorted} -%>`);
6447
6496
  }
6448
6497
  if (loop.objectIteration) {
@@ -6488,13 +6537,7 @@ ${renderedChildren}` : renderedChildren;
6488
6537
  lines.push(...preambleLines);
6489
6538
  lines.push(children);
6490
6539
  }
6491
- for (const n of loopBound) {
6492
- const c = (this.loopBoundNames.get(n) ?? 1) - 1;
6493
- if (c <= 0)
6494
- this.loopBoundNames.delete(n);
6495
- else
6496
- this.loopBoundNames.set(n, c);
6497
- }
6540
+ this.scope = prevScope;
6498
6541
  lines.push(`<%- end -%>`);
6499
6542
  lines.push(`<%= bf.comment("/loop:${loop.markerId}") %>`);
6500
6543
  return lines.join(`
@@ -6656,7 +6699,7 @@ ${children}`;
6656
6699
  if (ternaryHash !== null) {
6657
6700
  return `<%= bf.spread_attrs(${ternaryHash}) %>`;
6658
6701
  }
6659
- if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed) && !this.loopBoundNames.has(trimmed)) {
6702
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed) && !this.scope.isBound(trimmed)) {
6660
6703
  const localConst = this.localConstants.find((c) => c.name === trimmed && !c.isModule);
6661
6704
  if (localConst?.value !== undefined) {
6662
6705
  const initTrimmed = localConst.value.trim();