@barefootjs/rust 0.33.2 → 0.33.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.
@@ -187377,7 +187377,7 @@ function isAriaBooleanAttr(name) {
187377
187377
  }
187378
187378
 
187379
187379
  // src/adapter/minijinja-adapter.ts
187380
- import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from "@barefootjs/shared";
187380
+ import { BF_SLOT, BF_COND, BF_REGION, escapeHtml, resolveJsxChildrenProp } from "@barefootjs/shared";
187381
187381
 
187382
187382
  // src/adapter/lib/constants.ts
187383
187383
  var JINJA_TEMPLATE_PRIMITIVES = {
@@ -187439,62 +187439,6 @@ function minijinjaIdent(name) {
187439
187439
  return RESERVED_WORDS.has(name) ? `${name}_` : name;
187440
187440
  }
187441
187441
 
187442
- // src/adapter/lib/ir-scope.ts
187443
- var NON_VAR_TOKENS = new Set([
187444
- "bf",
187445
- "if",
187446
- "else",
187447
- "is",
187448
- "not",
187449
- "and",
187450
- "or",
187451
- "in",
187452
- "none",
187453
- "true",
187454
- "false",
187455
- "defined"
187456
- ]);
187457
- function extractTopLevelIdentifiers(jinjaExpr) {
187458
- const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
187459
- const out = [];
187460
- for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
187461
- if (!NON_VAR_TOKENS.has(m[1]))
187462
- out.push(m[1]);
187463
- }
187464
- return out;
187465
- }
187466
- function resolveJsxChildrenProp(props) {
187467
- const prop = props.find((p) => p.name === "children");
187468
- if (!prop)
187469
- return [];
187470
- if (prop.value.kind !== "jsx-children")
187471
- return [];
187472
- return prop.value.children;
187473
- }
187474
- function collectRootScopeNodes(node) {
187475
- const out = new Set;
187476
- const visit = (n) => {
187477
- if (!n)
187478
- return;
187479
- if (n.type === "element") {
187480
- out.add(n);
187481
- return;
187482
- }
187483
- if (n.type === "if-statement") {
187484
- const s = n;
187485
- visit(s.consequent);
187486
- visit(s.alternate);
187487
- return;
187488
- }
187489
- if (n.type === "fragment") {
187490
- for (const c of n.children)
187491
- visit(c);
187492
- }
187493
- };
187494
- visit(node);
187495
- return out;
187496
- }
187497
-
187498
187442
  // src/adapter/expr/array-method.ts
187499
187443
  import {
187500
187444
  serializeParsedExpr,
@@ -188230,6 +188174,33 @@ import {
188230
188174
  computeSsrSeedPlan,
188231
188175
  materializeGetterCalls
188232
188176
  } from "@barefootjs/jsx";
188177
+
188178
+ // src/adapter/lib/ir-scope.ts
188179
+ var NON_VAR_TOKENS = new Set([
188180
+ "bf",
188181
+ "if",
188182
+ "else",
188183
+ "is",
188184
+ "not",
188185
+ "and",
188186
+ "or",
188187
+ "in",
188188
+ "none",
188189
+ "true",
188190
+ "false",
188191
+ "defined"
188192
+ ]);
188193
+ function extractTopLevelIdentifiers(jinjaExpr) {
188194
+ const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
188195
+ const out = [];
188196
+ for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
188197
+ if (!NON_VAR_TOKENS.has(m[1]))
188198
+ out.push(m[1]);
188199
+ }
188200
+ return out;
188201
+ }
188202
+
188203
+ // src/adapter/memo/seed.ts
188233
188204
  function contextDefaultJinja(c) {
188234
188205
  const d = c.defaultValue;
188235
188206
  if (d === null || d === undefined)
@@ -188319,11 +188290,9 @@ class MinijinjaAdapter extends BaseAdapter {
188319
188290
  templatesPerComponent = true;
188320
188291
  templatePrimitives = JINJA_PRIMITIVE_EMIT_MAP;
188321
188292
  componentName = "";
188322
- rootScopeNodes = new Set;
188323
188293
  options;
188324
188294
  errors = [];
188325
188295
  inLoop = false;
188326
- currentLoopKeyDepth = 0;
188327
188296
  propsObjectName = null;
188328
188297
  propsParams = [];
188329
188298
  booleanTypedProps = new Set;
@@ -188359,7 +188328,6 @@ class MinijinjaAdapter extends BaseAdapter {
188359
188328
  if (!options?.siblingTemplatesRegistered) {
188360
188329
  this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName));
188361
188330
  }
188362
- this.rootScopeNodes = collectRootScopeNodes(ir.root);
188363
188331
  const templateBody = ir.root.type === "if-statement" ? this.renderIfStatement(ir.root) : this.renderNode(ir.root);
188364
188332
  const scriptReg = options?.skipScriptRegistration ? "" : this.generateScriptRegistrations(ir, options?.scriptBaseName, options?.scriptAssets, options?.preloadAssets);
188365
188333
  const ctxSeed = generateContextConsumerSeed(ir);
@@ -188492,8 +188460,14 @@ class MinijinjaAdapter extends BaseAdapter {
188492
188460
  if (element.needsScope) {
188493
188461
  hydrationAttrs += ` ${this.renderScopeMarker("")}`;
188494
188462
  }
188495
- if (this.rootScopeNodes.has(element) && element.needsScope || element.carriesDataKey) {
188496
- hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
188463
+ if (element.keyAttr) {
188464
+ if (element.keyAttr.value !== undefined) {
188465
+ const lowered = emitAttrValue({ kind: "expression", expr: element.keyAttr.value }, this.elementAttrEmitter, element.keyAttr.name);
188466
+ if (lowered)
188467
+ hydrationAttrs += ` ${lowered}`;
188468
+ } else {
188469
+ hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
188470
+ }
188497
188471
  }
188498
188472
  if (element.slotId) {
188499
188473
  hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`;
@@ -188695,13 +188669,10 @@ ${whenTrue}
188695
188669
  }
188696
188670
  const prevInLoop = this.inLoop;
188697
188671
  this.inLoop = true;
188698
- const prevLoopKeyDepth = this.currentLoopKeyDepth;
188699
- this.currentLoopKeyDepth = loop.depth;
188700
188672
  const prevScope = this.scope;
188701
188673
  this.scope = prevScope.enterLoopRow(loop);
188702
188674
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
188703
188675
  const childrenUnderLoop = this.renderChildren(loop.children);
188704
- this.currentLoopKeyDepth = prevLoopKeyDepth;
188705
188676
  this.inLoop = prevInLoop;
188706
188677
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
188707
188678
  ${childrenUnderLoop}` : childrenUnderLoop;
@@ -188976,14 +188947,9 @@ ${name}="{{ bf.string(${val}) }}"
188976
188947
  continue;
188977
188948
  if (isDangerousInnerHtmlAttr(attr))
188978
188949
  continue;
188979
- let attrName;
188980
- if (attr.name === "className")
188981
- attrName = "class";
188982
- else if (attr.name === "key") {
188983
- const depth = this.currentLoopKeyDepth;
188984
- attrName = depth > 0 ? `data-key-${depth}` : "data-key";
188985
- } else
188986
- attrName = attr.name;
188950
+ if (attr.name === "key")
188951
+ continue;
188952
+ const attrName = attr.name === "className" ? "class" : attr.name;
188987
188953
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
188988
188954
  if (lowered)
188989
188955
  parts.push(lowered);
@@ -2,8 +2,16 @@
2
2
  * IR traversal helpers for the minijinja template adapter.
3
3
  *
4
4
  * Ported from `packages/adapter-xslate/src/adapter/lib/ir-scope.ts`.
5
- * `resolveJsxChildrenProp` and `collectRootScopeNodes` are byte-identical
6
- * (adapter-agnostic IR walks).
5
+ * `resolveJsxChildrenProp` used to live here too (byte-identical across
6
+ * every adapter carrying a copy of this file); it moved to
7
+ * `@barefootjs/shared` (#2773) so every adapter — DSL and Go template
8
+ * alike — calls the one implementation instead of each keeping a copy
9
+ * that can silently re-diverge. `collectRootScopeNodes` — the "which
10
+ * elements are this component's own render root(s)" walk this file used
11
+ * to duplicate too — moved into `jsx-to-ir.ts`'s `resolveRootKeyAttr`
12
+ * (#2753): the decision it fed (a `data-key` relay attribute) is resolved
13
+ * once, onto `IRElement.keyAttr`, instead of re-derived at emit time by
14
+ * every adapter.
7
15
  *
8
16
  * `extractTopLevelIdentifiers` scans the RENDERED template text (rather than
9
17
  * re-deriving free vars from the original JS AST) so it stays exactly in
@@ -25,7 +33,6 @@
25
33
  * AVAILABILITY itself is now the shared `computeSsrSeedPlan`'s job
26
34
  * (packages/jsx/src/ssr-seed-plan.ts), not this module's (#2075).
27
35
  */
28
- import type { IRNode, IRProp } from '@barefootjs/jsx';
29
36
  /**
30
37
  * Extract the set of "top-level identifier" tokens from a rendered Jinja
31
38
  * expression: bare words, excluding quoted-string content, dotted
@@ -33,18 +40,4 @@ import type { IRNode, IRProp } from '@barefootjs/jsx';
33
40
  * See the file header for why this replaces a direct `\w+` scan.
34
41
  */
35
42
  export declare function extractTopLevelIdentifiers(jinjaExpr: string): string[];
36
- /**
37
- * Find the `children` prop's `jsx-children` payload. Narrowed via the
38
- * AttrValue `kind` discriminator so adapter code stays type-safe if the IR
39
- * shape evolves.
40
- */
41
- export declare function resolveJsxChildrenProp(props: readonly IRProp[]): IRNode[];
42
- /**
43
- * Collect the component's root scope element node(s) — the elements that
44
- * become the rendered root and so carry `data-key` for a keyed loop item. A
45
- * plain element root is itself; an `if-statement` (early-return) root
46
- * contributes the top element of each branch, since exactly one renders at
47
- * runtime. (#1297)
48
- */
49
- export declare function collectRootScopeNodes(node: IRNode): Set<IRNode>;
50
43
  //# sourceMappingURL=ir-scope.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ir-scope.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/ir-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAA6B,MAAM,iBAAiB,CAAA;AAYhF;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAUtE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAKzE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAiB/D"}
1
+ {"version":3,"file":"ir-scope.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/ir-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAYH;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAUtE"}
@@ -129,22 +129,9 @@ export declare class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitt
129
129
  */
130
130
  templatePrimitives: TemplatePrimitiveRegistry;
131
131
  private componentName;
132
- /** Component root scope element(s) — each carries `data-key` for a keyed loop
133
- * item (set by the child renderer from the JSX `key` prop). A plain element
134
- * root is one node; an `if-statement` (early-return) root contributes the
135
- * top element of every branch. */
136
- private rootScopeNodes;
137
132
  private options;
138
133
  private errors;
139
134
  private inLoop;
140
- /**
141
- * `IRLoop.depth` of the loop currently being rendered (save/restore
142
- * around `renderChildren(loop.children)`, mirroring `inLoop` above).
143
- * `renderAttributes` reads this to derive the `key` → `data-key`/
144
- * `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
145
- * re-derived here (#2168 nested-loop-outer-binding).
146
- */
147
- private currentLoopKeyDepth;
148
135
  /**
149
136
  * SolidJS-style props identifier (`function(props: P)`) and the
150
137
  * analyzer-extracted prop names. Stashed at `generate()` entry so the
@@ -1 +1 @@
1
- {"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -187377,7 +187377,7 @@ function isAriaBooleanAttr(name) {
187377
187377
  }
187378
187378
 
187379
187379
  // src/adapter/minijinja-adapter.ts
187380
- import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from "@barefootjs/shared";
187380
+ import { BF_SLOT, BF_COND, BF_REGION, escapeHtml, resolveJsxChildrenProp } from "@barefootjs/shared";
187381
187381
 
187382
187382
  // src/adapter/lib/constants.ts
187383
187383
  var JINJA_TEMPLATE_PRIMITIVES = {
@@ -187439,62 +187439,6 @@ function minijinjaIdent(name) {
187439
187439
  return RESERVED_WORDS.has(name) ? `${name}_` : name;
187440
187440
  }
187441
187441
 
187442
- // src/adapter/lib/ir-scope.ts
187443
- var NON_VAR_TOKENS = new Set([
187444
- "bf",
187445
- "if",
187446
- "else",
187447
- "is",
187448
- "not",
187449
- "and",
187450
- "or",
187451
- "in",
187452
- "none",
187453
- "true",
187454
- "false",
187455
- "defined"
187456
- ]);
187457
- function extractTopLevelIdentifiers(jinjaExpr) {
187458
- const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
187459
- const out = [];
187460
- for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
187461
- if (!NON_VAR_TOKENS.has(m[1]))
187462
- out.push(m[1]);
187463
- }
187464
- return out;
187465
- }
187466
- function resolveJsxChildrenProp(props) {
187467
- const prop = props.find((p) => p.name === "children");
187468
- if (!prop)
187469
- return [];
187470
- if (prop.value.kind !== "jsx-children")
187471
- return [];
187472
- return prop.value.children;
187473
- }
187474
- function collectRootScopeNodes(node) {
187475
- const out = new Set;
187476
- const visit = (n) => {
187477
- if (!n)
187478
- return;
187479
- if (n.type === "element") {
187480
- out.add(n);
187481
- return;
187482
- }
187483
- if (n.type === "if-statement") {
187484
- const s = n;
187485
- visit(s.consequent);
187486
- visit(s.alternate);
187487
- return;
187488
- }
187489
- if (n.type === "fragment") {
187490
- for (const c of n.children)
187491
- visit(c);
187492
- }
187493
- };
187494
- visit(node);
187495
- return out;
187496
- }
187497
-
187498
187442
  // src/adapter/expr/array-method.ts
187499
187443
  import {
187500
187444
  serializeParsedExpr,
@@ -188230,6 +188174,33 @@ import {
188230
188174
  computeSsrSeedPlan,
188231
188175
  materializeGetterCalls
188232
188176
  } from "@barefootjs/jsx";
188177
+
188178
+ // src/adapter/lib/ir-scope.ts
188179
+ var NON_VAR_TOKENS = new Set([
188180
+ "bf",
188181
+ "if",
188182
+ "else",
188183
+ "is",
188184
+ "not",
188185
+ "and",
188186
+ "or",
188187
+ "in",
188188
+ "none",
188189
+ "true",
188190
+ "false",
188191
+ "defined"
188192
+ ]);
188193
+ function extractTopLevelIdentifiers(jinjaExpr) {
188194
+ const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
188195
+ const out = [];
188196
+ for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
188197
+ if (!NON_VAR_TOKENS.has(m[1]))
188198
+ out.push(m[1]);
188199
+ }
188200
+ return out;
188201
+ }
188202
+
188203
+ // src/adapter/memo/seed.ts
188233
188204
  function contextDefaultJinja(c) {
188234
188205
  const d = c.defaultValue;
188235
188206
  if (d === null || d === undefined)
@@ -188319,11 +188290,9 @@ class MinijinjaAdapter extends BaseAdapter {
188319
188290
  templatesPerComponent = true;
188320
188291
  templatePrimitives = JINJA_PRIMITIVE_EMIT_MAP;
188321
188292
  componentName = "";
188322
- rootScopeNodes = new Set;
188323
188293
  options;
188324
188294
  errors = [];
188325
188295
  inLoop = false;
188326
- currentLoopKeyDepth = 0;
188327
188296
  propsObjectName = null;
188328
188297
  propsParams = [];
188329
188298
  booleanTypedProps = new Set;
@@ -188359,7 +188328,6 @@ class MinijinjaAdapter extends BaseAdapter {
188359
188328
  if (!options?.siblingTemplatesRegistered) {
188360
188329
  this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName));
188361
188330
  }
188362
- this.rootScopeNodes = collectRootScopeNodes(ir.root);
188363
188331
  const templateBody = ir.root.type === "if-statement" ? this.renderIfStatement(ir.root) : this.renderNode(ir.root);
188364
188332
  const scriptReg = options?.skipScriptRegistration ? "" : this.generateScriptRegistrations(ir, options?.scriptBaseName, options?.scriptAssets, options?.preloadAssets);
188365
188333
  const ctxSeed = generateContextConsumerSeed(ir);
@@ -188492,8 +188460,14 @@ class MinijinjaAdapter extends BaseAdapter {
188492
188460
  if (element.needsScope) {
188493
188461
  hydrationAttrs += ` ${this.renderScopeMarker("")}`;
188494
188462
  }
188495
- if (this.rootScopeNodes.has(element) && element.needsScope || element.carriesDataKey) {
188496
- hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
188463
+ if (element.keyAttr) {
188464
+ if (element.keyAttr.value !== undefined) {
188465
+ const lowered = emitAttrValue({ kind: "expression", expr: element.keyAttr.value }, this.elementAttrEmitter, element.keyAttr.name);
188466
+ if (lowered)
188467
+ hydrationAttrs += ` ${lowered}`;
188468
+ } else {
188469
+ hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
188470
+ }
188497
188471
  }
188498
188472
  if (element.slotId) {
188499
188473
  hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`;
@@ -188695,13 +188669,10 @@ ${whenTrue}
188695
188669
  }
188696
188670
  const prevInLoop = this.inLoop;
188697
188671
  this.inLoop = true;
188698
- const prevLoopKeyDepth = this.currentLoopKeyDepth;
188699
- this.currentLoopKeyDepth = loop.depth;
188700
188672
  const prevScope = this.scope;
188701
188673
  this.scope = prevScope.enterLoopRow(loop);
188702
188674
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
188703
188675
  const childrenUnderLoop = this.renderChildren(loop.children);
188704
- this.currentLoopKeyDepth = prevLoopKeyDepth;
188705
188676
  this.inLoop = prevInLoop;
188706
188677
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
188707
188678
  ${childrenUnderLoop}` : childrenUnderLoop;
@@ -188976,14 +188947,9 @@ ${name}="{{ bf.string(${val}) }}"
188976
188947
  continue;
188977
188948
  if (isDangerousInnerHtmlAttr(attr))
188978
188949
  continue;
188979
- let attrName;
188980
- if (attr.name === "className")
188981
- attrName = "class";
188982
- else if (attr.name === "key") {
188983
- const depth = this.currentLoopKeyDepth;
188984
- attrName = depth > 0 ? `data-key-${depth}` : "data-key";
188985
- } else
188986
- attrName = attr.name;
188950
+ if (attr.name === "key")
188951
+ continue;
188952
+ const attrName = attr.name === "className" ? "class" : attr.name;
188987
188953
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
188988
188954
  if (lowered)
188989
188955
  parts.push(lowered);
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 ts24 from "typescript";
8
+ import ts25 from "typescript";
9
9
 
10
10
  // ../jsx/src/analyzer.ts
11
11
  import ts9 from "typescript";
@@ -2134,6 +2134,15 @@ function isBooleanAttr(name) {
2134
2134
  function escapeHtml(text) {
2135
2135
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2136
2136
  }
2137
+ // ../shared/src/jsx-children-prop.ts
2138
+ function resolveJsxChildrenProp(props) {
2139
+ const prop = props.find((p) => p.name === "children");
2140
+ if (!prop)
2141
+ return [];
2142
+ if (prop.value.kind !== "jsx-children")
2143
+ return [];
2144
+ return prop.value.children ?? [];
2145
+ }
2137
2146
  // ../jsx/src/ir-to-client-js/csr-substitute.ts
2138
2147
  import ts4 from "typescript";
2139
2148
  function extractFreeIdentifiersFromText(text) {
@@ -3185,11 +3194,14 @@ var KEYWORDS_AND_GLOBALS = new Set([
3185
3194
  // ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
3186
3195
  import ts14 from "typescript";
3187
3196
 
3197
+ // ../jsx/src/ir-to-client-js/imports.ts
3198
+ import ts16 from "typescript";
3199
+
3188
3200
  // ../jsx/src/value-references.ts
3189
3201
  import ts15 from "typescript";
3190
3202
 
3191
3203
  // ../jsx/src/relocate.ts
3192
- import ts16 from "typescript";
3204
+ import ts17 from "typescript";
3193
3205
 
3194
3206
  // ../jsx/src/lowering-registry.ts
3195
3207
  var plugins = [];
@@ -3406,10 +3418,10 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
3406
3418
  }
3407
3419
 
3408
3420
  // ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
3409
- import ts17 from "typescript";
3421
+ import ts18 from "typescript";
3410
3422
 
3411
3423
  // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3412
- import ts18 from "typescript";
3424
+ import ts19 from "typescript";
3413
3425
  var NO_PREAMBLE = {
3414
3426
  lazySafe: true,
3415
3427
  facts: { declaredNames: new Set, freeNames: new Set }
@@ -3459,7 +3471,7 @@ var INERT_BINDING_GLOBALS = new Set([
3459
3471
  ]);
3460
3472
 
3461
3473
  // ../jsx/src/ir-to-client-js/emit-reactive.ts
3462
- import ts19 from "typescript";
3474
+ import ts20 from "typescript";
3463
3475
 
3464
3476
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
3465
3477
  var NON_BUBBLING_EVENTS = new Set([
@@ -3474,7 +3486,7 @@ var NON_BUBBLING_EVENTS = new Set([
3474
3486
  ]);
3475
3487
 
3476
3488
  // ../jsx/src/ir-to-client-js/rewrite-props-object.ts
3477
- import ts20 from "typescript";
3489
+ import ts21 from "typescript";
3478
3490
 
3479
3491
  // ../jsx/src/ir-to-client-js/source-map.ts
3480
3492
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -3565,15 +3577,15 @@ class SourceMapGenerator {
3565
3577
  }
3566
3578
 
3567
3579
  // ../jsx/src/preprocess-inline-jsx-callbacks.ts
3568
- import ts21 from "typescript";
3580
+ import ts22 from "typescript";
3569
3581
 
3570
3582
  // ../jsx/src/ssr-defaults.ts
3571
- import ts22 from "typescript";
3583
+ import ts23 from "typescript";
3572
3584
  var UNRESOLVED = Symbol("unresolved");
3573
3585
  var NO_RETURN = Symbol("no-return");
3574
3586
 
3575
3587
  // ../jsx/src/augment-inherited-props.ts
3576
- import ts23 from "typescript";
3588
+ import ts24 from "typescript";
3577
3589
  function collectContextConsumers(metadata) {
3578
3590
  const constants = metadata.localConstants ?? [];
3579
3591
  const contextDefaults = new Map;
@@ -3605,47 +3617,47 @@ function collectContextConsumers(metadata) {
3605
3617
  }
3606
3618
  function parseUseContextArg(source) {
3607
3619
  const expr = parseSingleExpression(source);
3608
- if (!expr || !ts23.isCallExpression(expr))
3620
+ if (!expr || !ts24.isCallExpression(expr))
3609
3621
  return null;
3610
- if (!ts23.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
3622
+ if (!ts24.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
3611
3623
  return null;
3612
3624
  if (expr.arguments.length !== 1)
3613
3625
  return null;
3614
3626
  const arg = expr.arguments[0];
3615
- return ts23.isIdentifier(arg) ? arg.text : null;
3627
+ return ts24.isIdentifier(arg) ? arg.text : null;
3616
3628
  }
3617
3629
  function parseCreateContextDefault(source) {
3618
3630
  const expr = parseSingleExpression(source);
3619
- if (!expr || !ts23.isCallExpression(expr))
3631
+ if (!expr || !ts24.isCallExpression(expr))
3620
3632
  return null;
3621
3633
  if (expr.arguments.length === 0)
3622
3634
  return null;
3623
3635
  const arg = expr.arguments[0];
3624
- if (ts23.isStringLiteral(arg) || ts23.isNoSubstitutionTemplateLiteral(arg))
3636
+ if (ts24.isStringLiteral(arg) || ts24.isNoSubstitutionTemplateLiteral(arg))
3625
3637
  return arg.text;
3626
- if (ts23.isNumericLiteral(arg))
3638
+ if (ts24.isNumericLiteral(arg))
3627
3639
  return Number(arg.text);
3628
- if (arg.kind === ts23.SyntaxKind.TrueKeyword)
3640
+ if (arg.kind === ts24.SyntaxKind.TrueKeyword)
3629
3641
  return true;
3630
- if (arg.kind === ts23.SyntaxKind.FalseKeyword)
3642
+ if (arg.kind === ts24.SyntaxKind.FalseKeyword)
3631
3643
  return false;
3632
3644
  return null;
3633
3645
  }
3634
3646
  function isObjectLiteralCreateContextDefault(source) {
3635
3647
  const expr = parseSingleExpression(source);
3636
- if (!expr || !ts23.isCallExpression(expr))
3648
+ if (!expr || !ts24.isCallExpression(expr))
3637
3649
  return false;
3638
3650
  if (expr.arguments.length === 0)
3639
3651
  return false;
3640
- return ts23.isObjectLiteralExpression(expr.arguments[0]);
3652
+ return ts24.isObjectLiteralExpression(expr.arguments[0]);
3641
3653
  }
3642
3654
  function parseSingleExpression(source) {
3643
- const sf = ts23.createSourceFile("__ctx.ts", `(${source})`, ts23.ScriptTarget.Latest, false);
3655
+ const sf = ts24.createSourceFile("__ctx.ts", `(${source})`, ts24.ScriptTarget.Latest, false);
3644
3656
  const stmt = sf.statements[0];
3645
- if (!stmt || !ts23.isExpressionStatement(stmt))
3657
+ if (!stmt || !ts24.isExpressionStatement(stmt))
3646
3658
  return null;
3647
3659
  let e = stmt.expression;
3648
- while (ts23.isParenthesizedExpression(e))
3660
+ while (ts24.isParenthesizedExpression(e))
3649
3661
  e = e.expression;
3650
3662
  return e;
3651
3663
  }
@@ -3670,25 +3682,25 @@ function augmentInheritedPropAccesses(ir) {
3670
3682
  const pinCoalesceLiterals = (s) => {
3671
3683
  if (!s || !s.includes(propsObj))
3672
3684
  return;
3673
- const sf = ts23.createSourceFile("__aug.ts", `(${s})`, ts23.ScriptTarget.Latest, false);
3685
+ const sf = ts24.createSourceFile("__aug.ts", `(${s})`, ts24.ScriptTarget.Latest, false);
3674
3686
  const visit = (n) => {
3675
- if (ts23.isBinaryExpression(n) && (n.operatorToken.kind === ts23.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts23.SyntaxKind.BarBarToken)) {
3687
+ if (ts24.isBinaryExpression(n) && (n.operatorToken.kind === ts24.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts24.SyntaxKind.BarBarToken)) {
3676
3688
  let left = n.left;
3677
- while (ts23.isParenthesizedExpression(left))
3689
+ while (ts24.isParenthesizedExpression(left))
3678
3690
  left = left.expression;
3679
- if (ts23.isPropertyAccessExpression(left) && ts23.isIdentifier(left.expression) && left.expression.text === propsObj) {
3691
+ if (ts24.isPropertyAccessExpression(left) && ts24.isIdentifier(left.expression) && left.expression.text === propsObj) {
3680
3692
  const name = left.name.text;
3681
3693
  let right = n.right;
3682
- while (ts23.isParenthesizedExpression(right))
3694
+ while (ts24.isParenthesizedExpression(right))
3683
3695
  right = right.expression;
3684
- if (ts23.isPrefixUnaryExpression(right))
3696
+ if (ts24.isPrefixUnaryExpression(right))
3685
3697
  right = right.operand;
3686
- const kind = ts23.isNumericLiteral(right) ? "number" : right.kind === ts23.SyntaxKind.TrueKeyword || right.kind === ts23.SyntaxKind.FalseKeyword ? "boolean" : ts23.isStringLiteralLike(right) ? "string" : null;
3698
+ const kind = ts24.isNumericLiteral(right) ? "number" : right.kind === ts24.SyntaxKind.TrueKeyword || right.kind === ts24.SyntaxKind.FalseKeyword ? "boolean" : ts24.isStringLiteralLike(right) ? "string" : null;
3687
3699
  if (kind && !coalesceLiteralTypes.has(name))
3688
3700
  coalesceLiteralTypes.set(name, kind);
3689
3701
  }
3690
3702
  }
3691
- ts23.forEachChild(n, visit);
3703
+ ts24.forEachChild(n, visit);
3692
3704
  };
3693
3705
  visit(sf);
3694
3706
  };
@@ -3799,33 +3811,33 @@ function augmentInheritedPropAccesses(ir) {
3799
3811
  }
3800
3812
  }
3801
3813
  function parseStaticStringConst(source) {
3802
- const sf = ts23.createSourceFile("__const.ts", `const __x = (${source});`, ts23.ScriptTarget.Latest, false);
3814
+ const sf = ts24.createSourceFile("__const.ts", `const __x = (${source});`, ts24.ScriptTarget.Latest, false);
3803
3815
  const stmt = sf.statements[0];
3804
- if (!stmt || !ts23.isVariableStatement(stmt))
3816
+ if (!stmt || !ts24.isVariableStatement(stmt))
3805
3817
  return null;
3806
3818
  let init = stmt.declarationList.declarations[0]?.initializer;
3807
- while (init && ts23.isParenthesizedExpression(init))
3819
+ while (init && ts24.isParenthesizedExpression(init))
3808
3820
  init = init.expression;
3809
3821
  if (!init)
3810
3822
  return null;
3811
- if (ts23.isStringLiteral(init) || ts23.isNoSubstitutionTemplateLiteral(init)) {
3823
+ if (ts24.isStringLiteral(init) || ts24.isNoSubstitutionTemplateLiteral(init)) {
3812
3824
  return init.text;
3813
3825
  }
3814
3826
  return evalStringArrayJoin(source);
3815
3827
  }
3816
3828
  function evalTemplateOfStringConsts(source, resolved) {
3817
- const sf = ts23.createSourceFile("__const.ts", `const __x = (${source});`, ts23.ScriptTarget.Latest, false);
3829
+ const sf = ts24.createSourceFile("__const.ts", `const __x = (${source});`, ts24.ScriptTarget.Latest, false);
3818
3830
  const stmt = sf.statements[0];
3819
- if (!stmt || !ts23.isVariableStatement(stmt))
3831
+ if (!stmt || !ts24.isVariableStatement(stmt))
3820
3832
  return null;
3821
3833
  let init = stmt.declarationList.declarations[0]?.initializer;
3822
- while (init && ts23.isParenthesizedExpression(init))
3834
+ while (init && ts24.isParenthesizedExpression(init))
3823
3835
  init = init.expression;
3824
- if (!init || !ts23.isTemplateExpression(init))
3836
+ if (!init || !ts24.isTemplateExpression(init))
3825
3837
  return null;
3826
3838
  let out = init.head.text;
3827
3839
  for (const span of init.templateSpans) {
3828
- if (!ts23.isIdentifier(span.expression))
3840
+ if (!ts24.isIdentifier(span.expression))
3829
3841
  return null;
3830
3842
  const value = resolved.get(span.expression.text);
3831
3843
  if (value === undefined)
@@ -3858,30 +3870,30 @@ function lookupStaticRecordLiteral(objectName, key, constants, isShadowed) {
3858
3870
  const constInfo = (constants ?? []).find((c) => c.name === objectName && c.isModule);
3859
3871
  if (constInfo?.value === undefined)
3860
3872
  return null;
3861
- const sf = ts23.createSourceFile("__rec.ts", `(${constInfo.value})`, ts23.ScriptTarget.Latest, true);
3873
+ const sf = ts24.createSourceFile("__rec.ts", `(${constInfo.value})`, ts24.ScriptTarget.Latest, true);
3862
3874
  if (sf.statements.length !== 1)
3863
3875
  return null;
3864
3876
  const stmt = sf.statements[0];
3865
- if (!ts23.isExpressionStatement(stmt))
3877
+ if (!ts24.isExpressionStatement(stmt))
3866
3878
  return null;
3867
3879
  let parsed = stmt.expression;
3868
- while (ts23.isParenthesizedExpression(parsed))
3880
+ while (ts24.isParenthesizedExpression(parsed))
3869
3881
  parsed = parsed.expression;
3870
- if (!ts23.isObjectLiteralExpression(parsed))
3882
+ if (!ts24.isObjectLiteralExpression(parsed))
3871
3883
  return null;
3872
3884
  for (const prop of parsed.properties) {
3873
- if (!ts23.isPropertyAssignment(prop))
3885
+ if (!ts24.isPropertyAssignment(prop))
3874
3886
  continue;
3875
3887
  const name = prop.name;
3876
- const propKey = ts23.isIdentifier(name) || ts23.isStringLiteral(name) || ts23.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
3888
+ const propKey = ts24.isIdentifier(name) || ts24.isStringLiteral(name) || ts24.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
3877
3889
  if (propKey !== key)
3878
3890
  continue;
3879
3891
  let v = prop.initializer;
3880
- while (ts23.isParenthesizedExpression(v))
3892
+ while (ts24.isParenthesizedExpression(v))
3881
3893
  v = v.expression;
3882
- if (ts23.isNumericLiteral(v))
3894
+ if (ts24.isNumericLiteral(v))
3883
3895
  return { kind: "number", text: v.text };
3884
- if (ts23.isStringLiteral(v) || ts23.isNoSubstitutionTemplateLiteral(v)) {
3896
+ if (ts24.isStringLiteral(v) || ts24.isNoSubstitutionTemplateLiteral(v)) {
3885
3897
  return { kind: "string", text: v.text };
3886
3898
  }
3887
3899
  return null;
@@ -3889,28 +3901,28 @@ function lookupStaticRecordLiteral(objectName, key, constants, isShadowed) {
3889
3901
  return null;
3890
3902
  }
3891
3903
  function evalStringArrayJoin(source) {
3892
- const sf = ts23.createSourceFile("__join.ts", `const __x = (${source});`, ts23.ScriptTarget.Latest, false);
3904
+ const sf = ts24.createSourceFile("__join.ts", `const __x = (${source});`, ts24.ScriptTarget.Latest, false);
3893
3905
  const stmt = sf.statements[0];
3894
- if (!stmt || !ts23.isVariableStatement(stmt))
3906
+ if (!stmt || !ts24.isVariableStatement(stmt))
3895
3907
  return null;
3896
3908
  let node = stmt.declarationList.declarations[0]?.initializer;
3897
- while (node && ts23.isParenthesizedExpression(node))
3909
+ while (node && ts24.isParenthesizedExpression(node))
3898
3910
  node = node.expression;
3899
- if (!node || !ts23.isCallExpression(node))
3911
+ if (!node || !ts24.isCallExpression(node))
3900
3912
  return null;
3901
3913
  const callee = node.expression;
3902
- if (!ts23.isPropertyAccessExpression(callee))
3914
+ if (!ts24.isPropertyAccessExpression(callee))
3903
3915
  return null;
3904
3916
  if (callee.name.text !== "join")
3905
3917
  return null;
3906
3918
  let recv = callee.expression;
3907
- while (ts23.isParenthesizedExpression(recv))
3919
+ while (ts24.isParenthesizedExpression(recv))
3908
3920
  recv = recv.expression;
3909
- if (!ts23.isArrayLiteralExpression(recv))
3921
+ if (!ts24.isArrayLiteralExpression(recv))
3910
3922
  return null;
3911
3923
  const parts = [];
3912
3924
  for (const el of recv.elements) {
3913
- if (ts23.isStringLiteral(el) || ts23.isNoSubstitutionTemplateLiteral(el)) {
3925
+ if (ts24.isStringLiteral(el) || ts24.isNoSubstitutionTemplateLiteral(el)) {
3914
3926
  parts.push(el.text);
3915
3927
  } else {
3916
3928
  return null;
@@ -3919,7 +3931,7 @@ function evalStringArrayJoin(source) {
3919
3931
  let sep = ",";
3920
3932
  if (node.arguments.length >= 1) {
3921
3933
  const arg = node.arguments[0];
3922
- if (ts23.isStringLiteral(arg) || ts23.isNoSubstitutionTemplateLiteral(arg))
3934
+ if (ts24.isStringLiteral(arg) || ts24.isNoSubstitutionTemplateLiteral(arg))
3923
3935
  sep = arg.text;
3924
3936
  else
3925
3937
  return null;
@@ -3927,11 +3939,11 @@ function evalStringArrayJoin(source) {
3927
3939
  return parts.join(sep);
3928
3940
  }
3929
3941
  function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3930
- if (!ts23.isElementAccessExpression(val))
3942
+ if (!ts24.isElementAccessExpression(val))
3931
3943
  return null;
3932
3944
  const obj = val.expression;
3933
3945
  const arg = val.argumentExpression;
3934
- if (!ts23.isIdentifier(obj) || !ts23.isIdentifier(arg))
3946
+ if (!ts24.isIdentifier(obj) || !ts24.isIdentifier(arg))
3935
3947
  return null;
3936
3948
  let indexPropName;
3937
3949
  let defaultKey;
@@ -3947,35 +3959,35 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3947
3959
  const constInfo = localConstants.find((c) => c.name === obj.text && c.isModule);
3948
3960
  if (constInfo?.value === undefined)
3949
3961
  return null;
3950
- const sf = ts23.createSourceFile("__rec.ts", `(${constInfo.value})`, ts23.ScriptTarget.Latest, true);
3962
+ const sf = ts24.createSourceFile("__rec.ts", `(${constInfo.value})`, ts24.ScriptTarget.Latest, true);
3951
3963
  if (sf.statements.length !== 1)
3952
3964
  return null;
3953
3965
  const stmt = sf.statements[0];
3954
- if (!ts23.isExpressionStatement(stmt))
3966
+ if (!ts24.isExpressionStatement(stmt))
3955
3967
  return null;
3956
3968
  let parsed = stmt.expression;
3957
- while (ts23.isParenthesizedExpression(parsed))
3969
+ while (ts24.isParenthesizedExpression(parsed))
3958
3970
  parsed = parsed.expression;
3959
- if (!ts23.isObjectLiteralExpression(parsed))
3971
+ if (!ts24.isObjectLiteralExpression(parsed))
3960
3972
  return null;
3961
3973
  const entries = [];
3962
3974
  for (const prop of parsed.properties) {
3963
- if (!ts23.isPropertyAssignment(prop))
3975
+ if (!ts24.isPropertyAssignment(prop))
3964
3976
  return null;
3965
3977
  let key;
3966
- if (ts23.isIdentifier(prop.name)) {
3978
+ if (ts24.isIdentifier(prop.name)) {
3967
3979
  key = prop.name.text;
3968
- } else if (ts23.isStringLiteral(prop.name) || ts23.isNoSubstitutionTemplateLiteral(prop.name)) {
3980
+ } else if (ts24.isStringLiteral(prop.name) || ts24.isNoSubstitutionTemplateLiteral(prop.name)) {
3969
3981
  key = prop.name.text;
3970
3982
  } else {
3971
3983
  return null;
3972
3984
  }
3973
3985
  let v = prop.initializer;
3974
- while (ts23.isParenthesizedExpression(v))
3986
+ while (ts24.isParenthesizedExpression(v))
3975
3987
  v = v.expression;
3976
- if (ts23.isNumericLiteral(v)) {
3988
+ if (ts24.isNumericLiteral(v)) {
3977
3989
  entries.push({ key, value: { kind: "number", text: v.text } });
3978
- } else if (ts23.isStringLiteral(v) || ts23.isNoSubstitutionTemplateLiteral(v)) {
3990
+ } else if (ts24.isStringLiteral(v) || ts24.isNoSubstitutionTemplateLiteral(v)) {
3979
3991
  entries.push({ key, value: { kind: "string", text: v.text } });
3980
3992
  } else {
3981
3993
  return null;
@@ -4064,7 +4076,7 @@ function computeSsrSeedPlan(metadata) {
4064
4076
  // ../jsx/src/rich-type-refusal.ts
4065
4077
  var EMPTY_BINDINGS2 = new Map;
4066
4078
  // ../jsx/src/shared-program.ts
4067
- import ts25 from "typescript";
4079
+ import ts26 from "typescript";
4068
4080
  // ../jsx/src/adapters/interface.ts
4069
4081
  class BaseAdapter {
4070
4082
  renderChildren(children) {
@@ -4346,7 +4358,7 @@ class JsxAdapter extends BaseAdapter {
4346
4358
  }
4347
4359
 
4348
4360
  // ../jsx/src/adapters/template-imports.ts
4349
- import ts26 from "typescript";
4361
+ import ts27 from "typescript";
4350
4362
  var CLIENT_PACKAGE_SOURCES = new Set([
4351
4363
  "@barefootjs/client",
4352
4364
  "@barefootjs/client/runtime"
@@ -5039,7 +5051,7 @@ function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
5039
5051
  };
5040
5052
  }
5041
5053
  // ../jsx/src/combine-client-js.ts
5042
- import ts27 from "typescript";
5054
+ import ts28 from "typescript";
5043
5055
  // ../jsx/src/loop-destructure.ts
5044
5056
  function isLowerableLoopDestructure(loop) {
5045
5057
  const bindings = loop.paramBindings;
@@ -5179,9 +5191,9 @@ function escapeRe(s) {
5179
5191
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5180
5192
  }
5181
5193
  // ../jsx/src/debug.ts
5182
- import ts28 from "typescript";
5183
- // ../jsx/src/profiler.ts
5184
5194
  import ts29 from "typescript";
5195
+ // ../jsx/src/profiler.ts
5196
+ import ts30 from "typescript";
5185
5197
 
5186
5198
  // ../jsx/src/index.ts
5187
5199
  registerBuiltinLoweringPlugins();
@@ -5302,62 +5314,6 @@ function minijinjaIdent(name) {
5302
5314
  return RESERVED_WORDS2.has(name) ? `${name}_` : name;
5303
5315
  }
5304
5316
 
5305
- // src/adapter/lib/ir-scope.ts
5306
- var NON_VAR_TOKENS = new Set([
5307
- "bf",
5308
- "if",
5309
- "else",
5310
- "is",
5311
- "not",
5312
- "and",
5313
- "or",
5314
- "in",
5315
- "none",
5316
- "true",
5317
- "false",
5318
- "defined"
5319
- ]);
5320
- function extractTopLevelIdentifiers(jinjaExpr) {
5321
- const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
5322
- const out = [];
5323
- for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
5324
- if (!NON_VAR_TOKENS.has(m[1]))
5325
- out.push(m[1]);
5326
- }
5327
- return out;
5328
- }
5329
- function resolveJsxChildrenProp(props) {
5330
- const prop = props.find((p) => p.name === "children");
5331
- if (!prop)
5332
- return [];
5333
- if (prop.value.kind !== "jsx-children")
5334
- return [];
5335
- return prop.value.children;
5336
- }
5337
- function collectRootScopeNodes(node) {
5338
- const out = new Set;
5339
- const visit = (n) => {
5340
- if (!n)
5341
- return;
5342
- if (n.type === "element") {
5343
- out.add(n);
5344
- return;
5345
- }
5346
- if (n.type === "if-statement") {
5347
- const s = n;
5348
- visit(s.consequent);
5349
- visit(s.alternate);
5350
- return;
5351
- }
5352
- if (n.type === "fragment") {
5353
- for (const c of n.children)
5354
- visit(c);
5355
- }
5356
- };
5357
- visit(node);
5358
- return out;
5359
- }
5360
-
5361
5317
  // src/adapter/expr/array-method.ts
5362
5318
  function renderArrayMethod(method, object, args, emit) {
5363
5319
  switch (method) {
@@ -6008,7 +5964,7 @@ function collectImportedLoopChildComponentErrors(ir, componentName) {
6008
5964
  }
6009
5965
 
6010
5966
  // src/adapter/spread/spread-codegen.ts
6011
- import ts30 from "typescript";
5967
+ import ts31 from "typescript";
6012
5968
  function conditionalSpreadToJinja(ctx, expr) {
6013
5969
  if (!expr || expr.kind !== "conditional")
6014
5970
  return null;
@@ -6065,7 +6021,7 @@ function recordIndexAccessToJinja(ctx, val) {
6065
6021
  if (val.kind !== "index-access" || val.object.kind !== "identifier" || val.index.kind !== "identifier") {
6066
6022
  return null;
6067
6023
  }
6068
- const tsVal = ts30.factory.createElementAccessExpression(ts30.factory.createIdentifier(val.object.name), ts30.factory.createIdentifier(val.index.name));
6024
+ const tsVal = ts31.factory.createElementAccessExpression(ts31.factory.createIdentifier(val.object.name), ts31.factory.createIdentifier(val.index.name));
6069
6025
  const parsed = parseRecordIndexAccess(tsVal, ctx.localConstants ?? [], ctx.propsParams);
6070
6026
  if (!parsed)
6071
6027
  return null;
@@ -6076,6 +6032,31 @@ function recordIndexAccessToJinja(ctx, val) {
6076
6032
  return `{${entries.join(", ")}}[${minijinjaIdent(parsed.indexPropName)}]`;
6077
6033
  }
6078
6034
 
6035
+ // src/adapter/lib/ir-scope.ts
6036
+ var NON_VAR_TOKENS = new Set([
6037
+ "bf",
6038
+ "if",
6039
+ "else",
6040
+ "is",
6041
+ "not",
6042
+ "and",
6043
+ "or",
6044
+ "in",
6045
+ "none",
6046
+ "true",
6047
+ "false",
6048
+ "defined"
6049
+ ]);
6050
+ function extractTopLevelIdentifiers(jinjaExpr) {
6051
+ const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
6052
+ const out = [];
6053
+ for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
6054
+ if (!NON_VAR_TOKENS.has(m[1]))
6055
+ out.push(m[1]);
6056
+ }
6057
+ return out;
6058
+ }
6059
+
6079
6060
  // src/adapter/memo/seed.ts
6080
6061
  function contextDefaultJinja(c) {
6081
6062
  const d = c.defaultValue;
@@ -6165,11 +6146,9 @@ class MinijinjaAdapter extends BaseAdapter {
6165
6146
  templatesPerComponent = true;
6166
6147
  templatePrimitives = JINJA_PRIMITIVE_EMIT_MAP;
6167
6148
  componentName = "";
6168
- rootScopeNodes = new Set;
6169
6149
  options;
6170
6150
  errors = [];
6171
6151
  inLoop = false;
6172
- currentLoopKeyDepth = 0;
6173
6152
  propsObjectName = null;
6174
6153
  propsParams = [];
6175
6154
  booleanTypedProps = new Set;
@@ -6205,7 +6184,6 @@ class MinijinjaAdapter extends BaseAdapter {
6205
6184
  if (!options?.siblingTemplatesRegistered) {
6206
6185
  this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName));
6207
6186
  }
6208
- this.rootScopeNodes = collectRootScopeNodes(ir.root);
6209
6187
  const templateBody = ir.root.type === "if-statement" ? this.renderIfStatement(ir.root) : this.renderNode(ir.root);
6210
6188
  const scriptReg = options?.skipScriptRegistration ? "" : this.generateScriptRegistrations(ir, options?.scriptBaseName, options?.scriptAssets, options?.preloadAssets);
6211
6189
  const ctxSeed = generateContextConsumerSeed(ir);
@@ -6338,8 +6316,14 @@ class MinijinjaAdapter extends BaseAdapter {
6338
6316
  if (element.needsScope) {
6339
6317
  hydrationAttrs += ` ${this.renderScopeMarker("")}`;
6340
6318
  }
6341
- if (this.rootScopeNodes.has(element) && element.needsScope || element.carriesDataKey) {
6342
- hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
6319
+ if (element.keyAttr) {
6320
+ if (element.keyAttr.value !== undefined) {
6321
+ const lowered = emitAttrValue({ kind: "expression", expr: element.keyAttr.value }, this.elementAttrEmitter, element.keyAttr.name);
6322
+ if (lowered)
6323
+ hydrationAttrs += ` ${lowered}`;
6324
+ } else {
6325
+ hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
6326
+ }
6343
6327
  }
6344
6328
  if (element.slotId) {
6345
6329
  hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`;
@@ -6541,13 +6525,10 @@ ${whenTrue}
6541
6525
  }
6542
6526
  const prevInLoop = this.inLoop;
6543
6527
  this.inLoop = true;
6544
- const prevLoopKeyDepth = this.currentLoopKeyDepth;
6545
- this.currentLoopKeyDepth = loop.depth;
6546
6528
  const prevScope = this.scope;
6547
6529
  this.scope = prevScope.enterLoopRow(loop);
6548
6530
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
6549
6531
  const childrenUnderLoop = this.renderChildren(loop.children);
6550
- this.currentLoopKeyDepth = prevLoopKeyDepth;
6551
6532
  this.inLoop = prevInLoop;
6552
6533
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
6553
6534
  ${childrenUnderLoop}` : childrenUnderLoop;
@@ -6822,14 +6803,9 @@ ${name}="{{ bf.string(${val}) }}"
6822
6803
  continue;
6823
6804
  if (isDangerousInnerHtmlAttr(attr))
6824
6805
  continue;
6825
- let attrName;
6826
- if (attr.name === "className")
6827
- attrName = "class";
6828
- else if (attr.name === "key") {
6829
- const depth = this.currentLoopKeyDepth;
6830
- attrName = depth > 0 ? `data-key-${depth}` : "data-key";
6831
- } else
6832
- attrName = attr.name;
6806
+ if (attr.name === "key")
6807
+ continue;
6808
+ const attrName = attr.name === "className" ? "class" : attr.name;
6833
6809
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
6834
6810
  if (lowered)
6835
6811
  parts.push(lowered);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/rust",
3
- "version": "0.33.2",
3
+ "version": "0.33.4",
4
4
  "description": "minijinja (Rust) adapter for BarefootJS — compiles IR to .j2 templates and ships a Rust rendering runtime (packages/adapter-rust/runtime/); runs under any Rust web framework (axum, etc.)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,7 +54,7 @@
54
54
  "directory": "packages/adapter-rust"
55
55
  },
56
56
  "dependencies": {
57
- "@barefootjs/shared": "0.33.2"
57
+ "@barefootjs/shared": "0.33.4"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "@barefootjs/jsx": ">=0.2.0",
@@ -71,9 +71,9 @@
71
71
  },
72
72
  "devDependencies": {
73
73
  "@barefootjs/adapter-tests": "0.1.0",
74
- "@barefootjs/jsx": "0.33.2",
75
- "@barefootjs/vite": "0.33.2",
76
- "@barefootjs/client": "0.33.2",
74
+ "@barefootjs/jsx": "0.33.4",
75
+ "@barefootjs/vite": "0.33.4",
76
+ "@barefootjs/client": "0.33.4",
77
77
  "typescript": "^5.0.0",
78
78
  "vite": "^6.0.0"
79
79
  }
@@ -2,8 +2,16 @@
2
2
  * IR traversal helpers for the minijinja template adapter.
3
3
  *
4
4
  * Ported from `packages/adapter-xslate/src/adapter/lib/ir-scope.ts`.
5
- * `resolveJsxChildrenProp` and `collectRootScopeNodes` are byte-identical
6
- * (adapter-agnostic IR walks).
5
+ * `resolveJsxChildrenProp` used to live here too (byte-identical across
6
+ * every adapter carrying a copy of this file); it moved to
7
+ * `@barefootjs/shared` (#2773) so every adapter — DSL and Go template
8
+ * alike — calls the one implementation instead of each keeping a copy
9
+ * that can silently re-diverge. `collectRootScopeNodes` — the "which
10
+ * elements are this component's own render root(s)" walk this file used
11
+ * to duplicate too — moved into `jsx-to-ir.ts`'s `resolveRootKeyAttr`
12
+ * (#2753): the decision it fed (a `data-key` relay attribute) is resolved
13
+ * once, onto `IRElement.keyAttr`, instead of re-derived at emit time by
14
+ * every adapter.
7
15
  *
8
16
  * `extractTopLevelIdentifiers` scans the RENDERED template text (rather than
9
17
  * re-deriving free vars from the original JS AST) so it stays exactly in
@@ -26,8 +34,6 @@
26
34
  * (packages/jsx/src/ssr-seed-plan.ts), not this module's (#2075).
27
35
  */
28
36
 
29
- import type { IRNode, IRProp, IRIfStatement, IRFragment } from '@barefootjs/jsx'
30
-
31
37
  /** Tokens this adapter's own codegen can emit that are never context vars. */
32
38
  const NON_VAR_TOKENS = new Set([
33
39
  'bf', 'if', 'else', 'is', 'not', 'and', 'or', 'in', 'none', 'true', 'false',
@@ -55,41 +61,3 @@ export function extractTopLevelIdentifiers(jinjaExpr: string): string[] {
55
61
  }
56
62
  return out
57
63
  }
58
-
59
- /**
60
- * Find the `children` prop's `jsx-children` payload. Narrowed via the
61
- * AttrValue `kind` discriminator so adapter code stays type-safe if the IR
62
- * shape evolves.
63
- */
64
- export function resolveJsxChildrenProp(props: readonly IRProp[]): IRNode[] {
65
- const prop = props.find(p => p.name === 'children')
66
- if (!prop) return []
67
- if (prop.value.kind !== 'jsx-children') return []
68
- return prop.value.children
69
- }
70
-
71
- /**
72
- * Collect the component's root scope element node(s) — the elements that
73
- * become the rendered root and so carry `data-key` for a keyed loop item. A
74
- * plain element root is itself; an `if-statement` (early-return) root
75
- * contributes the top element of each branch, since exactly one renders at
76
- * runtime. (#1297)
77
- */
78
- export function collectRootScopeNodes(node: IRNode): Set<IRNode> {
79
- const out = new Set<IRNode>()
80
- const visit = (n: IRNode | null): void => {
81
- if (!n) return
82
- if (n.type === 'element') { out.add(n); return }
83
- if (n.type === 'if-statement') {
84
- const s = n as IRIfStatement
85
- visit(s.consequent)
86
- visit(s.alternate)
87
- return
88
- }
89
- if (n.type === 'fragment') {
90
- for (const c of (n as IRFragment).children) visit(c)
91
- }
92
- }
93
- visit(node)
94
- return out
95
- }
@@ -176,15 +176,11 @@ import {
176
176
  } from '@barefootjs/jsx'
177
177
  import { isAriaBooleanAttr, isBooleanResultExpr, isExplicitStringCall } from './boolean-result.ts'
178
178
  import type { ParsedExpr, LoweringMatcher, LoopBindingPathSegment } from '@barefootjs/jsx'
179
- import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from '@barefootjs/shared'
179
+ import { BF_SLOT, BF_COND, BF_REGION, escapeHtml, resolveJsxChildrenProp } from '@barefootjs/shared'
180
180
 
181
181
  import type { JinjaRenderCtx } from './lib/types.ts'
182
182
  import { JINJA_PRIMITIVE_EMIT_MAP } from './lib/constants.ts'
183
183
  import { minijinjaHashKey, minijinjaIdent, escapeMinijinjaSingleQuoted } from './lib/minijinja-naming.ts'
184
- import {
185
- resolveJsxChildrenProp,
186
- collectRootScopeNodes,
187
- } from './lib/ir-scope.ts'
188
184
  import { renderSortMethod, renderSortEval } from './expr/array-method.ts'
189
185
  import { staticValueToMinijinja } from './lib/static-value.ts'
190
186
  import { JinjaFilterEmitter, JinjaTopLevelEmitter, truthyTest } from './expr/emitters.ts'
@@ -252,22 +248,9 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
252
248
  templatePrimitives: TemplatePrimitiveRegistry = JINJA_PRIMITIVE_EMIT_MAP
253
249
 
254
250
  private componentName: string = ''
255
- /** Component root scope element(s) — each carries `data-key` for a keyed loop
256
- * item (set by the child renderer from the JSX `key` prop). A plain element
257
- * root is one node; an `if-statement` (early-return) root contributes the
258
- * top element of every branch. */
259
- private rootScopeNodes: Set<IRNode> = new Set()
260
251
  private options: Required<MinijinjaAdapterOptions>
261
252
  private errors: CompilerError[] = []
262
253
  private inLoop: boolean = false
263
- /**
264
- * `IRLoop.depth` of the loop currently being rendered (save/restore
265
- * around `renderChildren(loop.children)`, mirroring `inLoop` above).
266
- * `renderAttributes` reads this to derive the `key` → `data-key`/
267
- * `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
268
- * re-derived here (#2168 nested-loop-outer-binding).
269
- */
270
- private currentLoopKeyDepth = 0
271
254
  /**
272
255
  * SolidJS-style props identifier (`function(props: P)`) and the
273
256
  * analyzer-extracted prop names. Stashed at `generate()` entry so the
@@ -391,7 +374,6 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
391
374
  this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName))
392
375
  }
393
376
 
394
- this.rootScopeNodes = collectRootScopeNodes(ir.root)
395
377
  const templateBody = ir.root.type === 'if-statement'
396
378
  ? this.renderIfStatement(ir.root as IRIfStatement)
397
379
  : this.renderNode(ir.root)
@@ -630,18 +612,30 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
630
612
  if (element.needsScope) {
631
613
  hydrationAttrs += ` ${this.renderScopeMarker('')}`
632
614
  }
633
- // A root scope element carries `data-key` for a keyed loop item (set on the
634
- // bf instance by the child renderer from the JSX `key` prop); non-keyed
635
- // renders add nothing. Mirrors Hono stamping data-key on each loop item's
636
- // root, including early-return (if-statement) roots. (#1297)
637
- // `carriesDataKey` is an INDEPENDENT reason to emit, not a refinement of
638
- // the root-scope test above (#2732): a fragment root clears `needsScope` on
639
- // its wrapped child and moves the other hydration markers onto the
640
- // `<!--bf-scope:-->` comment, but `data-key` must stay a real attribute —
641
- // the client's `mapArray` adopt loop reads `primaryEl.dataset.key`, never
642
- // the comment. Mirrors the same branch in hono-adapter.ts.
643
- if ((this.rootScopeNodes.has(element) && element.needsScope) || element.carriesDataKey) {
644
- hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`
615
+ // #2753: `element.keyAttr` is the ONE IR-resolved decision for this
616
+ // element's row-key attribute replacing both the `carriesDataKey`
617
+ // boolean and this adapter's own `rootScopeNodes`/`needsScope` check
618
+ // (mechanism 2: a render-root relay, including the #2732 fragment-root
619
+ // case) and the separate `currentLoopKeyDepth`-driven rewrite of a
620
+ // literal `key` attribute this adapter used to do in `renderAttributes`
621
+ // (mechanism 1: a `.map()` row root compiled inline here).
622
+ if (element.keyAttr) {
623
+ if (element.keyAttr.value !== undefined) {
624
+ const lowered = emitAttrValue(
625
+ { kind: 'expression', expr: element.keyAttr.value },
626
+ this.elementAttrEmitter,
627
+ element.keyAttr.name,
628
+ )
629
+ if (lowered) hydrationAttrs += ` ${lowered}`
630
+ } else {
631
+ // Relay: this element is one of THIS component's own render roots,
632
+ // carrying whatever key its OWN caller supplies at runtime (the `bf`
633
+ // instance's `data_key` field) when this component is itself
634
+ // invoked as a caller's keyed loop row. Mirrors Hono stamping
635
+ // data-key on each loop item's root, including early-return
636
+ // (if-statement) roots (#1297), and #2732's fragment-root case.
637
+ hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`
638
+ }
645
639
  }
646
640
  if (element.slotId) {
647
641
  hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`
@@ -982,8 +976,6 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
982
976
 
983
977
  const prevInLoop = this.inLoop
984
978
  this.inLoop = true
985
- const prevLoopKeyDepth = this.currentLoopKeyDepth
986
- this.currentLoopKeyDepth = loop.depth
987
979
  // Re-render children now that inLoop is set (so nested components use the
988
980
  // loop-child naming convention). renderedChildren above was computed with
989
981
  // the previous flag; recompute under the loop flag.
@@ -1025,7 +1017,6 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
1025
1017
  d => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`,
1026
1018
  )
1027
1019
  const childrenUnderLoop = this.renderChildren(loop.children)
1028
- this.currentLoopKeyDepth = prevLoopKeyDepth
1029
1020
  this.inLoop = prevInLoop
1030
1021
  void renderedChildren
1031
1022
 
@@ -1601,14 +1592,15 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
1601
1592
  // literal never reaches the generic object-literal BF101 refusal
1602
1593
  // (which would double-report alongside the purpose-built one).
1603
1594
  if (isDangerousInnerHtmlAttr(attr)) continue
1595
+ // `key` never renders as a literal HTML attribute — #2753 resolves it
1596
+ // onto `element.keyAttr` (name AND value) at IR-build time, emitted
1597
+ // separately in `renderElement`. A stray `key` that jsx-to-ir.ts did
1598
+ // NOT recognize as a loop row root (so `keyAttr` was never set) has no
1599
+ // defined rendering outside a `.map()` anyway; drop it rather than
1600
+ // leak an invalid `key="..."` HTML attribute.
1601
+ if (attr.name === 'key') continue
1604
1602
  // Rewrite JSX special-prop names to their HTML-attribute counterparts.
1605
- let attrName: string
1606
- if (attr.name === 'className') attrName = 'class'
1607
- else if (attr.name === 'key') {
1608
- const depth = this.currentLoopKeyDepth
1609
- attrName = depth > 0 ? `data-key-${depth}` : 'data-key'
1610
- }
1611
- else attrName = attr.name
1603
+ const attrName = attr.name === 'className' ? 'class' : attr.name
1612
1604
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName)
1613
1605
  if (lowered) parts.push(lowered)
1614
1606
  }