@barefootjs/erb 0.31.4 → 0.31.6

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";
@@ -2527,7 +2527,7 @@ var REACTIVE_PRIMITIVES = new Set([
2527
2527
  ]);
2528
2528
 
2529
2529
  // ../jsx/src/jsx-to-ir.ts
2530
- import ts12 from "typescript";
2530
+ import ts13 from "typescript";
2531
2531
 
2532
2532
  // ../jsx/src/types.ts
2533
2533
  var SCOPE_FORBIDDEN = {
@@ -2577,6 +2577,7 @@ function preambleAnalysisTemplateText(p) {
2577
2577
  }
2578
2578
 
2579
2579
  // ../jsx/src/module-exports.ts
2580
+ import ts10 from "typescript";
2580
2581
  function formatParamWithType(p) {
2581
2582
  const rest = p.isRest ? "..." : "";
2582
2583
  const optional = p.optional ? "?" : "";
@@ -2607,12 +2608,55 @@ function findReachableNames(primaryRefs, declarations) {
2607
2608
  }
2608
2609
  return reachable;
2609
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
+ }
2610
2654
 
2611
2655
  // ../jsx/src/reactivity-checker.ts
2612
- import ts10 from "typescript";
2656
+ import ts11 from "typescript";
2613
2657
 
2614
2658
  // ../jsx/src/free-refs.ts
2615
- import ts11 from "typescript";
2659
+ import ts12 from "typescript";
2616
2660
  var _bindingMapCache = new WeakMap;
2617
2661
 
2618
2662
  // ../jsx/src/to-locale-date-lowering.ts
@@ -3026,13 +3070,13 @@ var KEYWORDS_AND_GLOBALS = new Set([
3026
3070
  ]);
3027
3071
 
3028
3072
  // ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
3029
- import ts13 from "typescript";
3073
+ import ts14 from "typescript";
3030
3074
 
3031
3075
  // ../jsx/src/value-references.ts
3032
- import ts14 from "typescript";
3076
+ import ts15 from "typescript";
3033
3077
 
3034
3078
  // ../jsx/src/relocate.ts
3035
- import ts15 from "typescript";
3079
+ import ts16 from "typescript";
3036
3080
 
3037
3081
  // ../jsx/src/lowering-registry.ts
3038
3082
  var plugins = [];
@@ -3249,10 +3293,10 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
3249
3293
  }
3250
3294
 
3251
3295
  // ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
3252
- import ts16 from "typescript";
3296
+ import ts17 from "typescript";
3253
3297
 
3254
3298
  // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3255
- import ts17 from "typescript";
3299
+ import ts18 from "typescript";
3256
3300
  var NO_PREAMBLE = {
3257
3301
  lazySafe: true,
3258
3302
  facts: { declaredNames: new Set, freeNames: new Set }
@@ -3302,7 +3346,7 @@ var INERT_BINDING_GLOBALS = new Set([
3302
3346
  ]);
3303
3347
 
3304
3348
  // ../jsx/src/ir-to-client-js/emit-reactive.ts
3305
- import ts18 from "typescript";
3349
+ import ts19 from "typescript";
3306
3350
 
3307
3351
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
3308
3352
  var NON_BUBBLING_EVENTS = new Set([
@@ -3317,7 +3361,7 @@ var NON_BUBBLING_EVENTS = new Set([
3317
3361
  ]);
3318
3362
 
3319
3363
  // ../jsx/src/ir-to-client-js/rewrite-props-object.ts
3320
- import ts19 from "typescript";
3364
+ import ts20 from "typescript";
3321
3365
 
3322
3366
  // ../jsx/src/ir-to-client-js/source-map.ts
3323
3367
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -3408,15 +3452,15 @@ class SourceMapGenerator {
3408
3452
  }
3409
3453
 
3410
3454
  // ../jsx/src/preprocess-inline-jsx-callbacks.ts
3411
- import ts20 from "typescript";
3455
+ import ts21 from "typescript";
3412
3456
 
3413
3457
  // ../jsx/src/ssr-defaults.ts
3414
- import ts21 from "typescript";
3458
+ import ts22 from "typescript";
3415
3459
  var UNRESOLVED = Symbol("unresolved");
3416
3460
  var NO_RETURN = Symbol("no-return");
3417
3461
 
3418
3462
  // ../jsx/src/augment-inherited-props.ts
3419
- import ts22 from "typescript";
3463
+ import ts23 from "typescript";
3420
3464
  function collectContextConsumers(metadata) {
3421
3465
  const constants = metadata.localConstants ?? [];
3422
3466
  const contextDefaults = new Map;
@@ -3448,47 +3492,47 @@ function collectContextConsumers(metadata) {
3448
3492
  }
3449
3493
  function parseUseContextArg(source) {
3450
3494
  const expr = parseSingleExpression(source);
3451
- if (!expr || !ts22.isCallExpression(expr))
3495
+ if (!expr || !ts23.isCallExpression(expr))
3452
3496
  return null;
3453
- if (!ts22.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
3497
+ if (!ts23.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
3454
3498
  return null;
3455
3499
  if (expr.arguments.length !== 1)
3456
3500
  return null;
3457
3501
  const arg = expr.arguments[0];
3458
- return ts22.isIdentifier(arg) ? arg.text : null;
3502
+ return ts23.isIdentifier(arg) ? arg.text : null;
3459
3503
  }
3460
3504
  function parseCreateContextDefault(source) {
3461
3505
  const expr = parseSingleExpression(source);
3462
- if (!expr || !ts22.isCallExpression(expr))
3506
+ if (!expr || !ts23.isCallExpression(expr))
3463
3507
  return null;
3464
3508
  if (expr.arguments.length === 0)
3465
3509
  return null;
3466
3510
  const arg = expr.arguments[0];
3467
- if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
3511
+ if (ts23.isStringLiteral(arg) || ts23.isNoSubstitutionTemplateLiteral(arg))
3468
3512
  return arg.text;
3469
- if (ts22.isNumericLiteral(arg))
3513
+ if (ts23.isNumericLiteral(arg))
3470
3514
  return Number(arg.text);
3471
- if (arg.kind === ts22.SyntaxKind.TrueKeyword)
3515
+ if (arg.kind === ts23.SyntaxKind.TrueKeyword)
3472
3516
  return true;
3473
- if (arg.kind === ts22.SyntaxKind.FalseKeyword)
3517
+ if (arg.kind === ts23.SyntaxKind.FalseKeyword)
3474
3518
  return false;
3475
3519
  return null;
3476
3520
  }
3477
3521
  function isObjectLiteralCreateContextDefault(source) {
3478
3522
  const expr = parseSingleExpression(source);
3479
- if (!expr || !ts22.isCallExpression(expr))
3523
+ if (!expr || !ts23.isCallExpression(expr))
3480
3524
  return false;
3481
3525
  if (expr.arguments.length === 0)
3482
3526
  return false;
3483
- return ts22.isObjectLiteralExpression(expr.arguments[0]);
3527
+ return ts23.isObjectLiteralExpression(expr.arguments[0]);
3484
3528
  }
3485
3529
  function parseSingleExpression(source) {
3486
- const sf = ts22.createSourceFile("__ctx.ts", `(${source})`, ts22.ScriptTarget.Latest, false);
3530
+ const sf = ts23.createSourceFile("__ctx.ts", `(${source})`, ts23.ScriptTarget.Latest, false);
3487
3531
  const stmt = sf.statements[0];
3488
- if (!stmt || !ts22.isExpressionStatement(stmt))
3532
+ if (!stmt || !ts23.isExpressionStatement(stmt))
3489
3533
  return null;
3490
3534
  let e = stmt.expression;
3491
- while (ts22.isParenthesizedExpression(e))
3535
+ while (ts23.isParenthesizedExpression(e))
3492
3536
  e = e.expression;
3493
3537
  return e;
3494
3538
  }
@@ -3513,25 +3557,25 @@ function augmentInheritedPropAccesses(ir) {
3513
3557
  const pinCoalesceLiterals = (s) => {
3514
3558
  if (!s || !s.includes(propsObj))
3515
3559
  return;
3516
- const sf = ts22.createSourceFile("__aug.ts", `(${s})`, ts22.ScriptTarget.Latest, false);
3560
+ const sf = ts23.createSourceFile("__aug.ts", `(${s})`, ts23.ScriptTarget.Latest, false);
3517
3561
  const visit = (n) => {
3518
- 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)) {
3519
3563
  let left = n.left;
3520
- while (ts22.isParenthesizedExpression(left))
3564
+ while (ts23.isParenthesizedExpression(left))
3521
3565
  left = left.expression;
3522
- 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) {
3523
3567
  const name = left.name.text;
3524
3568
  let right = n.right;
3525
- while (ts22.isParenthesizedExpression(right))
3569
+ while (ts23.isParenthesizedExpression(right))
3526
3570
  right = right.expression;
3527
- if (ts22.isPrefixUnaryExpression(right))
3571
+ if (ts23.isPrefixUnaryExpression(right))
3528
3572
  right = right.operand;
3529
- 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;
3530
3574
  if (kind && !coalesceLiteralTypes.has(name))
3531
3575
  coalesceLiteralTypes.set(name, kind);
3532
3576
  }
3533
3577
  }
3534
- ts22.forEachChild(n, visit);
3578
+ ts23.forEachChild(n, visit);
3535
3579
  };
3536
3580
  visit(sf);
3537
3581
  };
@@ -3642,33 +3686,33 @@ function augmentInheritedPropAccesses(ir) {
3642
3686
  }
3643
3687
  }
3644
3688
  function parseStaticStringConst(source) {
3645
- 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);
3646
3690
  const stmt = sf.statements[0];
3647
- if (!stmt || !ts22.isVariableStatement(stmt))
3691
+ if (!stmt || !ts23.isVariableStatement(stmt))
3648
3692
  return null;
3649
3693
  let init = stmt.declarationList.declarations[0]?.initializer;
3650
- while (init && ts22.isParenthesizedExpression(init))
3694
+ while (init && ts23.isParenthesizedExpression(init))
3651
3695
  init = init.expression;
3652
3696
  if (!init)
3653
3697
  return null;
3654
- if (ts22.isStringLiteral(init) || ts22.isNoSubstitutionTemplateLiteral(init)) {
3698
+ if (ts23.isStringLiteral(init) || ts23.isNoSubstitutionTemplateLiteral(init)) {
3655
3699
  return init.text;
3656
3700
  }
3657
3701
  return evalStringArrayJoin(source);
3658
3702
  }
3659
3703
  function evalTemplateOfStringConsts(source, resolved) {
3660
- 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);
3661
3705
  const stmt = sf.statements[0];
3662
- if (!stmt || !ts22.isVariableStatement(stmt))
3706
+ if (!stmt || !ts23.isVariableStatement(stmt))
3663
3707
  return null;
3664
3708
  let init = stmt.declarationList.declarations[0]?.initializer;
3665
- while (init && ts22.isParenthesizedExpression(init))
3709
+ while (init && ts23.isParenthesizedExpression(init))
3666
3710
  init = init.expression;
3667
- if (!init || !ts22.isTemplateExpression(init))
3711
+ if (!init || !ts23.isTemplateExpression(init))
3668
3712
  return null;
3669
3713
  let out = init.head.text;
3670
3714
  for (const span of init.templateSpans) {
3671
- if (!ts22.isIdentifier(span.expression))
3715
+ if (!ts23.isIdentifier(span.expression))
3672
3716
  return null;
3673
3717
  const value = resolved.get(span.expression.text);
3674
3718
  if (value === undefined)
@@ -3695,34 +3739,36 @@ function collectModuleStringConsts(constants) {
3695
3739
  }
3696
3740
  return map;
3697
3741
  }
3698
- function lookupStaticRecordLiteral(objectName, key, constants) {
3742
+ function lookupStaticRecordLiteral(objectName, key, constants, isShadowed) {
3743
+ if (isShadowed(objectName))
3744
+ return null;
3699
3745
  const constInfo = (constants ?? []).find((c) => c.name === objectName && c.isModule);
3700
3746
  if (constInfo?.value === undefined)
3701
3747
  return null;
3702
- 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);
3703
3749
  if (sf.statements.length !== 1)
3704
3750
  return null;
3705
3751
  const stmt = sf.statements[0];
3706
- if (!ts22.isExpressionStatement(stmt))
3752
+ if (!ts23.isExpressionStatement(stmt))
3707
3753
  return null;
3708
3754
  let parsed = stmt.expression;
3709
- while (ts22.isParenthesizedExpression(parsed))
3755
+ while (ts23.isParenthesizedExpression(parsed))
3710
3756
  parsed = parsed.expression;
3711
- if (!ts22.isObjectLiteralExpression(parsed))
3757
+ if (!ts23.isObjectLiteralExpression(parsed))
3712
3758
  return null;
3713
3759
  for (const prop of parsed.properties) {
3714
- if (!ts22.isPropertyAssignment(prop))
3760
+ if (!ts23.isPropertyAssignment(prop))
3715
3761
  continue;
3716
3762
  const name = prop.name;
3717
- 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;
3718
3764
  if (propKey !== key)
3719
3765
  continue;
3720
3766
  let v = prop.initializer;
3721
- while (ts22.isParenthesizedExpression(v))
3767
+ while (ts23.isParenthesizedExpression(v))
3722
3768
  v = v.expression;
3723
- if (ts22.isNumericLiteral(v))
3769
+ if (ts23.isNumericLiteral(v))
3724
3770
  return { kind: "number", text: v.text };
3725
- if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
3771
+ if (ts23.isStringLiteral(v) || ts23.isNoSubstitutionTemplateLiteral(v)) {
3726
3772
  return { kind: "string", text: v.text };
3727
3773
  }
3728
3774
  return null;
@@ -3730,28 +3776,28 @@ function lookupStaticRecordLiteral(objectName, key, constants) {
3730
3776
  return null;
3731
3777
  }
3732
3778
  function evalStringArrayJoin(source) {
3733
- 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);
3734
3780
  const stmt = sf.statements[0];
3735
- if (!stmt || !ts22.isVariableStatement(stmt))
3781
+ if (!stmt || !ts23.isVariableStatement(stmt))
3736
3782
  return null;
3737
3783
  let node = stmt.declarationList.declarations[0]?.initializer;
3738
- while (node && ts22.isParenthesizedExpression(node))
3784
+ while (node && ts23.isParenthesizedExpression(node))
3739
3785
  node = node.expression;
3740
- if (!node || !ts22.isCallExpression(node))
3786
+ if (!node || !ts23.isCallExpression(node))
3741
3787
  return null;
3742
3788
  const callee = node.expression;
3743
- if (!ts22.isPropertyAccessExpression(callee))
3789
+ if (!ts23.isPropertyAccessExpression(callee))
3744
3790
  return null;
3745
3791
  if (callee.name.text !== "join")
3746
3792
  return null;
3747
3793
  let recv = callee.expression;
3748
- while (ts22.isParenthesizedExpression(recv))
3794
+ while (ts23.isParenthesizedExpression(recv))
3749
3795
  recv = recv.expression;
3750
- if (!ts22.isArrayLiteralExpression(recv))
3796
+ if (!ts23.isArrayLiteralExpression(recv))
3751
3797
  return null;
3752
3798
  const parts = [];
3753
3799
  for (const el of recv.elements) {
3754
- if (ts22.isStringLiteral(el) || ts22.isNoSubstitutionTemplateLiteral(el)) {
3800
+ if (ts23.isStringLiteral(el) || ts23.isNoSubstitutionTemplateLiteral(el)) {
3755
3801
  parts.push(el.text);
3756
3802
  } else {
3757
3803
  return null;
@@ -3760,7 +3806,7 @@ function evalStringArrayJoin(source) {
3760
3806
  let sep = ",";
3761
3807
  if (node.arguments.length >= 1) {
3762
3808
  const arg = node.arguments[0];
3763
- if (ts22.isStringLiteral(arg) || ts22.isNoSubstitutionTemplateLiteral(arg))
3809
+ if (ts23.isStringLiteral(arg) || ts23.isNoSubstitutionTemplateLiteral(arg))
3764
3810
  sep = arg.text;
3765
3811
  else
3766
3812
  return null;
@@ -3768,11 +3814,11 @@ function evalStringArrayJoin(source) {
3768
3814
  return parts.join(sep);
3769
3815
  }
3770
3816
  function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3771
- if (!ts22.isElementAccessExpression(val))
3817
+ if (!ts23.isElementAccessExpression(val))
3772
3818
  return null;
3773
3819
  const obj = val.expression;
3774
3820
  const arg = val.argumentExpression;
3775
- if (!ts22.isIdentifier(obj) || !ts22.isIdentifier(arg))
3821
+ if (!ts23.isIdentifier(obj) || !ts23.isIdentifier(arg))
3776
3822
  return null;
3777
3823
  let indexPropName;
3778
3824
  let defaultKey;
@@ -3788,35 +3834,35 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3788
3834
  const constInfo = localConstants.find((c) => c.name === obj.text && c.isModule);
3789
3835
  if (constInfo?.value === undefined)
3790
3836
  return null;
3791
- 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);
3792
3838
  if (sf.statements.length !== 1)
3793
3839
  return null;
3794
3840
  const stmt = sf.statements[0];
3795
- if (!ts22.isExpressionStatement(stmt))
3841
+ if (!ts23.isExpressionStatement(stmt))
3796
3842
  return null;
3797
3843
  let parsed = stmt.expression;
3798
- while (ts22.isParenthesizedExpression(parsed))
3844
+ while (ts23.isParenthesizedExpression(parsed))
3799
3845
  parsed = parsed.expression;
3800
- if (!ts22.isObjectLiteralExpression(parsed))
3846
+ if (!ts23.isObjectLiteralExpression(parsed))
3801
3847
  return null;
3802
3848
  const entries = [];
3803
3849
  for (const prop of parsed.properties) {
3804
- if (!ts22.isPropertyAssignment(prop))
3850
+ if (!ts23.isPropertyAssignment(prop))
3805
3851
  return null;
3806
3852
  let key;
3807
- if (ts22.isIdentifier(prop.name)) {
3853
+ if (ts23.isIdentifier(prop.name)) {
3808
3854
  key = prop.name.text;
3809
- } else if (ts22.isStringLiteral(prop.name) || ts22.isNoSubstitutionTemplateLiteral(prop.name)) {
3855
+ } else if (ts23.isStringLiteral(prop.name) || ts23.isNoSubstitutionTemplateLiteral(prop.name)) {
3810
3856
  key = prop.name.text;
3811
3857
  } else {
3812
3858
  return null;
3813
3859
  }
3814
3860
  let v = prop.initializer;
3815
- while (ts22.isParenthesizedExpression(v))
3861
+ while (ts23.isParenthesizedExpression(v))
3816
3862
  v = v.expression;
3817
- if (ts22.isNumericLiteral(v)) {
3863
+ if (ts23.isNumericLiteral(v)) {
3818
3864
  entries.push({ key, value: { kind: "number", text: v.text } });
3819
- } else if (ts22.isStringLiteral(v) || ts22.isNoSubstitutionTemplateLiteral(v)) {
3865
+ } else if (ts23.isStringLiteral(v) || ts23.isNoSubstitutionTemplateLiteral(v)) {
3820
3866
  entries.push({ key, value: { kind: "string", text: v.text } });
3821
3867
  } else {
3822
3868
  return null;
@@ -3872,7 +3918,7 @@ function computeSsrSeedPlan(metadata) {
3872
3918
  // ../jsx/src/rich-type-refusal.ts
3873
3919
  var EMPTY_BINDINGS2 = new Map;
3874
3920
  // ../jsx/src/shared-program.ts
3875
- import ts24 from "typescript";
3921
+ import ts25 from "typescript";
3876
3922
  // ../jsx/src/adapters/interface.ts
3877
3923
  class BaseAdapter {
3878
3924
  renderChildren(children) {
@@ -3925,7 +3971,7 @@ class JsxAdapter extends BaseAdapter {
3925
3971
  ...localFunctions.map((f) => ({ name: f.name, body: f.body })),
3926
3972
  ...localConstants.map((c) => ({ name: c.name, body: c.value }))
3927
3973
  ];
3928
- 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)));
3929
3975
  const reachableBodies = [...reachable].map((name) => {
3930
3976
  const func = localFunctions.find((f) => f.name === name);
3931
3977
  if (func)
@@ -3957,7 +4003,8 @@ class JsxAdapter extends BaseAdapter {
3957
4003
  if (signal.setter) {
3958
4004
  const setterUsed = identifierPattern(signal.setter).test(setterRefText);
3959
4005
  if (setterUsed) {
3960
- 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[]) => {}`);
3961
4008
  }
3962
4009
  }
3963
4010
  }
@@ -4153,7 +4200,7 @@ class JsxAdapter extends BaseAdapter {
4153
4200
  }
4154
4201
 
4155
4202
  // ../jsx/src/adapters/template-imports.ts
4156
- import ts25 from "typescript";
4203
+ import ts26 from "typescript";
4157
4204
  var CLIENT_PACKAGE_SOURCES = new Set([
4158
4205
  "@barefootjs/client",
4159
4206
  "@barefootjs/client/runtime"
@@ -4292,7 +4339,8 @@ export default ${this.componentName}` : "";
4292
4339
  const noArgDefault = hasRequiredProps ? "" : ` = {} as ${propsTypeExpr}`;
4293
4340
  const lines = [];
4294
4341
  const exportPrefix = ir.metadata.isExported === false ? "" : "export ";
4295
- lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
4342
+ const typeParameters = ir.metadata.typeParameters ?? "";
4343
+ lines.push(`${exportPrefix}function ${name}${typeParameters}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
4296
4344
  if (hasClientInteractivity) {
4297
4345
  lines.push(` const __scopeId = (/_s\\d/.test(__bfScope || '') ? __bfScope : null) || __instanceId || \`${name}_\${Math.random().toString(36).slice(2, 8)}\``);
4298
4346
  } else {
@@ -4827,7 +4875,7 @@ function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
4827
4875
  };
4828
4876
  }
4829
4877
  // ../jsx/src/combine-client-js.ts
4830
- import ts26 from "typescript";
4878
+ import ts27 from "typescript";
4831
4879
  // ../jsx/src/loop-destructure.ts
4832
4880
  function isLowerableLoopDestructure(loop) {
4833
4881
  const bindings = loop.paramBindings;
@@ -4967,9 +5015,9 @@ function escapeRe(s) {
4967
5015
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4968
5016
  }
4969
5017
  // ../jsx/src/debug.ts
4970
- import ts27 from "typescript";
4971
- // ../jsx/src/profiler.ts
4972
5018
  import ts28 from "typescript";
5019
+ // ../jsx/src/profiler.ts
5020
+ import ts29 from "typescript";
4973
5021
 
4974
5022
  // ../jsx/src/index.ts
4975
5023
  registerBuiltinLoweringPlugins();
@@ -5840,7 +5888,7 @@ function collectImportedLoopChildComponentErrors(ir, componentName) {
5840
5888
  }
5841
5889
 
5842
5890
  // src/adapter/spread/spread-codegen.ts
5843
- import ts29 from "typescript";
5891
+ import ts30 from "typescript";
5844
5892
  function conditionalSpreadToRuby(ctx, expr) {
5845
5893
  if (!expr || expr.kind !== "conditional")
5846
5894
  return null;
@@ -5895,7 +5943,7 @@ function recordIndexAccessToRuby(ctx, val) {
5895
5943
  if (val.kind !== "index-access" || val.object.kind !== "identifier" || val.index.kind !== "identifier") {
5896
5944
  return null;
5897
5945
  }
5898
- const tsVal = ts29.factory.createElementAccessExpression(ts29.factory.createIdentifier(val.object.name), ts29.factory.createIdentifier(val.index.name));
5946
+ const tsVal = ts30.factory.createElementAccessExpression(ts30.factory.createIdentifier(val.object.name), ts30.factory.createIdentifier(val.index.name));
5899
5947
  const parsed = parseRecordIndexAccess(tsVal, ctx.localConstants, ctx.propsParams);
5900
5948
  if (!parsed)
5901
5949
  return null;
@@ -6008,7 +6056,7 @@ class ErbAdapter extends BaseAdapter {
6008
6056
  _loweringMatchers = [];
6009
6057
  moduleStringConsts = new Map;
6010
6058
  localConstants = [];
6011
- loopBoundNames = new Map;
6059
+ scope = BindingScope.EMPTY;
6012
6060
  nullableOptionalProps = new Set;
6013
6061
  constructor(options = {}) {
6014
6062
  super();
@@ -6030,7 +6078,7 @@ class ErbAdapter extends BaseAdapter {
6030
6078
  this._searchParamsLocals = searchParamsLocalNames(ir.metadata);
6031
6079
  this._loweringMatchers = prepareLoweringMatchers(ir.metadata);
6032
6080
  this.localConstants = ir.metadata.localConstants ?? [];
6033
- this.loopBoundNames.clear();
6081
+ this.scope = BindingScope.EMPTY;
6034
6082
  this.errors = [];
6035
6083
  this.childrenCaptureCounter = 0;
6036
6084
  if (!options?.siblingTemplatesRegistered) {
@@ -6088,7 +6136,7 @@ class ErbAdapter extends BaseAdapter {
6088
6136
  };
6089
6137
  }
6090
6138
  resolveLiteralConst(name) {
6091
- if (this.loopBoundNames?.has?.(name))
6139
+ if (this.scope.isBound(name))
6092
6140
  return null;
6093
6141
  const c = (this.localConstants ?? []).find((lc) => lc.name === name);
6094
6142
  if (c?.value === undefined)
@@ -6102,15 +6150,13 @@ class ErbAdapter extends BaseAdapter {
6102
6150
  return null;
6103
6151
  }
6104
6152
  resolveStaticRecordLiteral(objectName, key) {
6105
- if (this.loopBoundNames?.has?.(objectName))
6106
- return null;
6107
- const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants);
6153
+ const hit = lookupStaticRecordLiteral(objectName, key, this.localConstants, (name) => this.scope.isBound(name));
6108
6154
  if (!hit)
6109
6155
  return null;
6110
6156
  return hit.kind === "number" ? hit.text : rubyStringLiteral(hit.text);
6111
6157
  }
6112
6158
  resolveModuleStringConst(name) {
6113
- if (this.loopBoundNames.has(name))
6159
+ if (this.scope.isBound(name))
6114
6160
  return null;
6115
6161
  const value = this.moduleStringConsts.get(name);
6116
6162
  if (value === undefined)
@@ -6118,7 +6164,7 @@ class ErbAdapter extends BaseAdapter {
6118
6164
  return rubyStringLiteral(value);
6119
6165
  }
6120
6166
  isLoopBoundName(name) {
6121
- return this.loopBoundNames.has(name);
6167
+ return this.scope.isBound(name);
6122
6168
  }
6123
6169
  generateScriptRegistrations(ir, scriptBaseName, scriptAssets, preloadAssets) {
6124
6170
  if (scriptAssets) {
@@ -6395,17 +6441,17 @@ ${whenTrue}
6395
6441
  });
6396
6442
  }
6397
6443
  const staticItems = resolveStaticLoopSource(loop.arrayParsed, this.localConstants, {
6398
- isNameShadowed: (name) => this.loopBoundNames.has(name)
6444
+ isNameShadowed: this.scope.asShadowPredicate()
6399
6445
  });
6400
6446
  const staticArray = staticItems !== null ? staticValueToRuby(staticItems) : null;
6401
6447
  if (staticArray === null && loop.arrayParsed?.kind === "identifier") {
6402
6448
  const arrayName = loop.arrayParsed.name;
6403
- 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);
6404
6450
  if (isUnresolvableLocalConst) {
6405
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:
6406
6452
  1. Inline the array expression directly in the .map() call instead of a preceding const.
6407
6453
  2. Mark the loop position as @client-only so the array materialises on the client.
6408
- 3. Precompute the value server-side and pass it in as a prop.`);
6454
+ 3. Precompute the value server-side and pass it in as a prop.`, [{ kind: "prop-precompute" }, { kind: "client-directive" }]);
6409
6455
  }
6410
6456
  }
6411
6457
  const rawArray = staticArray ?? this.convertExpressionToRuby(loop.array);
@@ -6417,13 +6463,9 @@ ${whenTrue}
6417
6463
  }
6418
6464
  const param = loop.param;
6419
6465
  const indexVar = loop.iterationShape === "keys" ? rubyLocal(param) : rubyLocal(loop.index ?? "_i");
6420
- 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"];
6421
6466
  const preambleDecls = loop.preamble?.declarations ?? [];
6422
- for (const d of preambleDecls)
6423
- loopBound.push(d.name);
6424
- for (const n of loopBound) {
6425
- this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
6426
- }
6467
+ const prevScope = this.scope;
6468
+ this.scope = prevScope.enterLoopRow(loop);
6427
6469
  const prevLoopKeyDepth = this.currentLoopKeyDepth;
6428
6470
  this.currentLoopKeyDepth = loop.depth;
6429
6471
  const renderedChildren = this.renderChildren(loop.children);
@@ -6433,13 +6475,7 @@ ${renderedChildren}` : renderedChildren;
6433
6475
  const lines = [];
6434
6476
  lines.push(`<%= bf.comment("loop:${loop.markerId}") %>`);
6435
6477
  if (sortedHoist && loop.sortComparator) {
6436
- for (const n of loopBound) {
6437
- const c = (this.loopBoundNames.get(n) ?? 1) - 1;
6438
- if (c <= 0)
6439
- this.loopBoundNames.delete(n);
6440
- else
6441
- this.loopBoundNames.set(n, c);
6442
- }
6478
+ this.scope = prevScope;
6443
6479
  const sortEmit = (e) => this.convertExpressionToRuby("", e);
6444
6480
  const sortArrow = loop.sortComparator.arrow;
6445
6481
  let sorted = null;
@@ -6455,9 +6491,7 @@ ${renderedChildren}` : renderedChildren;
6455
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.`);
6456
6492
  sorted = rawArray;
6457
6493
  }
6458
- for (const n of loopBound) {
6459
- this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
6460
- }
6494
+ this.scope = prevScope.enterLoopRow(loop);
6461
6495
  lines.push(`<%- ${sortedHoist} = ${sorted} -%>`);
6462
6496
  }
6463
6497
  if (loop.objectIteration) {
@@ -6503,13 +6537,7 @@ ${renderedChildren}` : renderedChildren;
6503
6537
  lines.push(...preambleLines);
6504
6538
  lines.push(children);
6505
6539
  }
6506
- for (const n of loopBound) {
6507
- const c = (this.loopBoundNames.get(n) ?? 1) - 1;
6508
- if (c <= 0)
6509
- this.loopBoundNames.delete(n);
6510
- else
6511
- this.loopBoundNames.set(n, c);
6512
- }
6540
+ this.scope = prevScope;
6513
6541
  lines.push(`<%- end -%>`);
6514
6542
  lines.push(`<%= bf.comment("/loop:${loop.markerId}") %>`);
6515
6543
  return lines.join(`
@@ -6671,7 +6699,7 @@ ${children}`;
6671
6699
  if (ternaryHash !== null) {
6672
6700
  return `<%= bf.spread_attrs(${ternaryHash}) %>`;
6673
6701
  }
6674
- 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)) {
6675
6703
  const localConst = this.localConstants.find((c) => c.name === trimmed && !c.isModule);
6676
6704
  if (localConst?.value !== undefined) {
6677
6705
  const initTrimmed = localConst.value.trim();
@@ -6872,7 +6900,7 @@ Options:
6872
6900
  _isStringValueName(name) {
6873
6901
  return this.stringValueNames.has(name);
6874
6902
  }
6875
- _recordExprBF101(message, reason) {
6903
+ _recordExprBF101(message, reason, escape) {
6876
6904
  this.errors.push({
6877
6905
  code: "BF101",
6878
6906
  severity: "error",
@@ -6885,7 +6913,8 @@ Options:
6885
6913
  1. Use /* @client */ for client-side evaluation
6886
6914
  2. Pre-compute the value in Ruby` : `Options:
6887
6915
  1. Use /* @client */ for client-side evaluation
6888
- 2. Pre-compute the value in Ruby`
6916
+ 2. Pre-compute the value in Ruby`,
6917
+ ...escape ? { escape } : {}
6889
6918
  }
6890
6919
  });
6891
6920
  }