@barefootjs/jinja 0.33.1 → 0.33.3
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/adapter/index.js +39 -73
- package/dist/adapter/jinja-adapter.d.ts +0 -13
- package/dist/adapter/jinja-adapter.d.ts.map +1 -1
- package/dist/adapter/lib/ir-scope.d.ts +10 -17
- package/dist/adapter/lib/ir-scope.d.ts.map +1 -1
- package/dist/index.js +39 -73
- package/dist/vite.js +128 -148
- package/package.json +5 -5
- package/src/__tests__/jinja-adapter-unit.test.ts +9 -1
- package/src/adapter/jinja-adapter.ts +33 -35
- package/src/adapter/lib/ir-scope.ts +10 -42
package/dist/adapter/index.js
CHANGED
|
@@ -187377,7 +187377,7 @@ function isAriaBooleanAttr(name) {
|
|
|
187377
187377
|
}
|
|
187378
187378
|
|
|
187379
187379
|
// src/adapter/jinja-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 = {
|
|
@@ -187452,62 +187452,6 @@ function jinjaAccessorFromSegments(base, segments) {
|
|
|
187452
187452
|
return acc;
|
|
187453
187453
|
}
|
|
187454
187454
|
|
|
187455
|
-
// src/adapter/lib/ir-scope.ts
|
|
187456
|
-
var NON_VAR_TOKENS = new Set([
|
|
187457
|
-
"bf",
|
|
187458
|
-
"if",
|
|
187459
|
-
"else",
|
|
187460
|
-
"is",
|
|
187461
|
-
"not",
|
|
187462
|
-
"and",
|
|
187463
|
-
"or",
|
|
187464
|
-
"in",
|
|
187465
|
-
"none",
|
|
187466
|
-
"true",
|
|
187467
|
-
"false",
|
|
187468
|
-
"defined"
|
|
187469
|
-
]);
|
|
187470
|
-
function extractTopLevelIdentifiers(jinjaExpr) {
|
|
187471
|
-
const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
|
|
187472
|
-
const out = [];
|
|
187473
|
-
for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
|
|
187474
|
-
if (!NON_VAR_TOKENS.has(m[1]))
|
|
187475
|
-
out.push(m[1]);
|
|
187476
|
-
}
|
|
187477
|
-
return out;
|
|
187478
|
-
}
|
|
187479
|
-
function resolveJsxChildrenProp(props) {
|
|
187480
|
-
const prop = props.find((p) => p.name === "children");
|
|
187481
|
-
if (!prop)
|
|
187482
|
-
return [];
|
|
187483
|
-
if (prop.value.kind !== "jsx-children")
|
|
187484
|
-
return [];
|
|
187485
|
-
return prop.value.children;
|
|
187486
|
-
}
|
|
187487
|
-
function collectRootScopeNodes(node) {
|
|
187488
|
-
const out = new Set;
|
|
187489
|
-
const visit = (n) => {
|
|
187490
|
-
if (!n)
|
|
187491
|
-
return;
|
|
187492
|
-
if (n.type === "element") {
|
|
187493
|
-
out.add(n);
|
|
187494
|
-
return;
|
|
187495
|
-
}
|
|
187496
|
-
if (n.type === "if-statement") {
|
|
187497
|
-
const s = n;
|
|
187498
|
-
visit(s.consequent);
|
|
187499
|
-
visit(s.alternate);
|
|
187500
|
-
return;
|
|
187501
|
-
}
|
|
187502
|
-
if (n.type === "fragment") {
|
|
187503
|
-
for (const c of n.children)
|
|
187504
|
-
visit(c);
|
|
187505
|
-
}
|
|
187506
|
-
};
|
|
187507
|
-
visit(node);
|
|
187508
|
-
return out;
|
|
187509
|
-
}
|
|
187510
|
-
|
|
187511
187455
|
// src/adapter/expr/array-method.ts
|
|
187512
187456
|
import {
|
|
187513
187457
|
serializeParsedExpr,
|
|
@@ -188237,6 +188181,33 @@ import {
|
|
|
188237
188181
|
computeSsrSeedPlan,
|
|
188238
188182
|
materializeGetterCalls
|
|
188239
188183
|
} from "@barefootjs/jsx";
|
|
188184
|
+
|
|
188185
|
+
// src/adapter/lib/ir-scope.ts
|
|
188186
|
+
var NON_VAR_TOKENS = new Set([
|
|
188187
|
+
"bf",
|
|
188188
|
+
"if",
|
|
188189
|
+
"else",
|
|
188190
|
+
"is",
|
|
188191
|
+
"not",
|
|
188192
|
+
"and",
|
|
188193
|
+
"or",
|
|
188194
|
+
"in",
|
|
188195
|
+
"none",
|
|
188196
|
+
"true",
|
|
188197
|
+
"false",
|
|
188198
|
+
"defined"
|
|
188199
|
+
]);
|
|
188200
|
+
function extractTopLevelIdentifiers(jinjaExpr) {
|
|
188201
|
+
const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
|
|
188202
|
+
const out = [];
|
|
188203
|
+
for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
|
|
188204
|
+
if (!NON_VAR_TOKENS.has(m[1]))
|
|
188205
|
+
out.push(m[1]);
|
|
188206
|
+
}
|
|
188207
|
+
return out;
|
|
188208
|
+
}
|
|
188209
|
+
|
|
188210
|
+
// src/adapter/memo/seed.ts
|
|
188240
188211
|
function contextDefaultJinja(c) {
|
|
188241
188212
|
const d = c.defaultValue;
|
|
188242
188213
|
if (d === null || d === undefined)
|
|
@@ -188318,11 +188289,9 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188318
188289
|
templatesPerComponent = true;
|
|
188319
188290
|
templatePrimitives = JINJA_PRIMITIVE_EMIT_MAP;
|
|
188320
188291
|
componentName = "";
|
|
188321
|
-
rootScopeNodes = new Set;
|
|
188322
188292
|
options;
|
|
188323
188293
|
errors = [];
|
|
188324
188294
|
inLoop = false;
|
|
188325
|
-
currentLoopKeyDepth = 0;
|
|
188326
188295
|
propsObjectName = null;
|
|
188327
188296
|
propsParams = [];
|
|
188328
188297
|
booleanTypedProps = new Set;
|
|
@@ -188358,7 +188327,6 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188358
188327
|
if (!options?.siblingTemplatesRegistered) {
|
|
188359
188328
|
this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName));
|
|
188360
188329
|
}
|
|
188361
|
-
this.rootScopeNodes = collectRootScopeNodes(ir.root);
|
|
188362
188330
|
const templateBody = ir.root.type === "if-statement" ? this.renderIfStatement(ir.root) : this.renderNode(ir.root);
|
|
188363
188331
|
const scriptReg = options?.skipScriptRegistration ? "" : this.generateScriptRegistrations(ir, options?.scriptBaseName, options?.scriptAssets, options?.preloadAssets);
|
|
188364
188332
|
const ctxSeed = generateContextConsumerSeed(ir);
|
|
@@ -188491,8 +188459,14 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188491
188459
|
if (element.needsScope) {
|
|
188492
188460
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
188493
188461
|
}
|
|
188494
|
-
if (
|
|
188495
|
-
|
|
188462
|
+
if (element.keyAttr) {
|
|
188463
|
+
if (element.keyAttr.value !== undefined) {
|
|
188464
|
+
const lowered = emitAttrValue({ kind: "expression", expr: element.keyAttr.value }, this.elementAttrEmitter, element.keyAttr.name);
|
|
188465
|
+
if (lowered)
|
|
188466
|
+
hydrationAttrs += ` ${lowered}`;
|
|
188467
|
+
} else {
|
|
188468
|
+
hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
|
|
188469
|
+
}
|
|
188496
188470
|
}
|
|
188497
188471
|
if (element.slotId) {
|
|
188498
188472
|
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 ${jinjaIdent(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
|
-
|
|
188980
|
-
|
|
188981
|
-
|
|
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);
|
|
@@ -104,22 +104,9 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
104
104
|
*/
|
|
105
105
|
templatePrimitives: TemplatePrimitiveRegistry;
|
|
106
106
|
private componentName;
|
|
107
|
-
/** Component root scope element(s) — each carries `data-key` for a keyed loop
|
|
108
|
-
* item (set by the child renderer from the JSX `key` prop). A plain element
|
|
109
|
-
* root is one node; an `if-statement` (early-return) root contributes the
|
|
110
|
-
* top element of every branch. */
|
|
111
|
-
private rootScopeNodes;
|
|
112
107
|
private options;
|
|
113
108
|
private errors;
|
|
114
109
|
private inLoop;
|
|
115
|
-
/**
|
|
116
|
-
* `IRLoop.depth` of the loop currently being rendered (save/restore
|
|
117
|
-
* around `renderChildren(loop.children)`, mirroring `inLoop` above).
|
|
118
|
-
* `renderAttributes` reads this to derive the `key` → `data-key`/
|
|
119
|
-
* `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
|
|
120
|
-
* re-derived here (#2168 nested-loop-outer-binding).
|
|
121
|
-
*/
|
|
122
|
-
private currentLoopKeyDepth;
|
|
123
110
|
/**
|
|
124
111
|
* SolidJS-style props identifier (`function(props: P)`) and the
|
|
125
112
|
* analyzer-extracted prop names. Stashed at `generate()` entry so the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAKP,yBAAyB,EAE1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,EAiChB,MAAM,iBAAiB,CAAA;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
* IR traversal helpers for the Jinja2 template adapter.
|
|
3
3
|
*
|
|
4
4
|
* Ported from `packages/adapter-xslate/src/adapter/lib/ir-scope.ts`.
|
|
5
|
-
* `resolveJsxChildrenProp`
|
|
6
|
-
*
|
|
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
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -187377,7 +187377,7 @@ function isAriaBooleanAttr(name) {
|
|
|
187377
187377
|
}
|
|
187378
187378
|
|
|
187379
187379
|
// src/adapter/jinja-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 = {
|
|
@@ -187452,62 +187452,6 @@ function jinjaAccessorFromSegments(base, segments) {
|
|
|
187452
187452
|
return acc;
|
|
187453
187453
|
}
|
|
187454
187454
|
|
|
187455
|
-
// src/adapter/lib/ir-scope.ts
|
|
187456
|
-
var NON_VAR_TOKENS = new Set([
|
|
187457
|
-
"bf",
|
|
187458
|
-
"if",
|
|
187459
|
-
"else",
|
|
187460
|
-
"is",
|
|
187461
|
-
"not",
|
|
187462
|
-
"and",
|
|
187463
|
-
"or",
|
|
187464
|
-
"in",
|
|
187465
|
-
"none",
|
|
187466
|
-
"true",
|
|
187467
|
-
"false",
|
|
187468
|
-
"defined"
|
|
187469
|
-
]);
|
|
187470
|
-
function extractTopLevelIdentifiers(jinjaExpr) {
|
|
187471
|
-
const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
|
|
187472
|
-
const out = [];
|
|
187473
|
-
for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
|
|
187474
|
-
if (!NON_VAR_TOKENS.has(m[1]))
|
|
187475
|
-
out.push(m[1]);
|
|
187476
|
-
}
|
|
187477
|
-
return out;
|
|
187478
|
-
}
|
|
187479
|
-
function resolveJsxChildrenProp(props) {
|
|
187480
|
-
const prop = props.find((p) => p.name === "children");
|
|
187481
|
-
if (!prop)
|
|
187482
|
-
return [];
|
|
187483
|
-
if (prop.value.kind !== "jsx-children")
|
|
187484
|
-
return [];
|
|
187485
|
-
return prop.value.children;
|
|
187486
|
-
}
|
|
187487
|
-
function collectRootScopeNodes(node) {
|
|
187488
|
-
const out = new Set;
|
|
187489
|
-
const visit = (n) => {
|
|
187490
|
-
if (!n)
|
|
187491
|
-
return;
|
|
187492
|
-
if (n.type === "element") {
|
|
187493
|
-
out.add(n);
|
|
187494
|
-
return;
|
|
187495
|
-
}
|
|
187496
|
-
if (n.type === "if-statement") {
|
|
187497
|
-
const s = n;
|
|
187498
|
-
visit(s.consequent);
|
|
187499
|
-
visit(s.alternate);
|
|
187500
|
-
return;
|
|
187501
|
-
}
|
|
187502
|
-
if (n.type === "fragment") {
|
|
187503
|
-
for (const c of n.children)
|
|
187504
|
-
visit(c);
|
|
187505
|
-
}
|
|
187506
|
-
};
|
|
187507
|
-
visit(node);
|
|
187508
|
-
return out;
|
|
187509
|
-
}
|
|
187510
|
-
|
|
187511
187455
|
// src/adapter/expr/array-method.ts
|
|
187512
187456
|
import {
|
|
187513
187457
|
serializeParsedExpr,
|
|
@@ -188237,6 +188181,33 @@ import {
|
|
|
188237
188181
|
computeSsrSeedPlan,
|
|
188238
188182
|
materializeGetterCalls
|
|
188239
188183
|
} from "@barefootjs/jsx";
|
|
188184
|
+
|
|
188185
|
+
// src/adapter/lib/ir-scope.ts
|
|
188186
|
+
var NON_VAR_TOKENS = new Set([
|
|
188187
|
+
"bf",
|
|
188188
|
+
"if",
|
|
188189
|
+
"else",
|
|
188190
|
+
"is",
|
|
188191
|
+
"not",
|
|
188192
|
+
"and",
|
|
188193
|
+
"or",
|
|
188194
|
+
"in",
|
|
188195
|
+
"none",
|
|
188196
|
+
"true",
|
|
188197
|
+
"false",
|
|
188198
|
+
"defined"
|
|
188199
|
+
]);
|
|
188200
|
+
function extractTopLevelIdentifiers(jinjaExpr) {
|
|
188201
|
+
const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
|
|
188202
|
+
const out = [];
|
|
188203
|
+
for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
|
|
188204
|
+
if (!NON_VAR_TOKENS.has(m[1]))
|
|
188205
|
+
out.push(m[1]);
|
|
188206
|
+
}
|
|
188207
|
+
return out;
|
|
188208
|
+
}
|
|
188209
|
+
|
|
188210
|
+
// src/adapter/memo/seed.ts
|
|
188240
188211
|
function contextDefaultJinja(c) {
|
|
188241
188212
|
const d = c.defaultValue;
|
|
188242
188213
|
if (d === null || d === undefined)
|
|
@@ -188318,11 +188289,9 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188318
188289
|
templatesPerComponent = true;
|
|
188319
188290
|
templatePrimitives = JINJA_PRIMITIVE_EMIT_MAP;
|
|
188320
188291
|
componentName = "";
|
|
188321
|
-
rootScopeNodes = new Set;
|
|
188322
188292
|
options;
|
|
188323
188293
|
errors = [];
|
|
188324
188294
|
inLoop = false;
|
|
188325
|
-
currentLoopKeyDepth = 0;
|
|
188326
188295
|
propsObjectName = null;
|
|
188327
188296
|
propsParams = [];
|
|
188328
188297
|
booleanTypedProps = new Set;
|
|
@@ -188358,7 +188327,6 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188358
188327
|
if (!options?.siblingTemplatesRegistered) {
|
|
188359
188328
|
this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName));
|
|
188360
188329
|
}
|
|
188361
|
-
this.rootScopeNodes = collectRootScopeNodes(ir.root);
|
|
188362
188330
|
const templateBody = ir.root.type === "if-statement" ? this.renderIfStatement(ir.root) : this.renderNode(ir.root);
|
|
188363
188331
|
const scriptReg = options?.skipScriptRegistration ? "" : this.generateScriptRegistrations(ir, options?.scriptBaseName, options?.scriptAssets, options?.preloadAssets);
|
|
188364
188332
|
const ctxSeed = generateContextConsumerSeed(ir);
|
|
@@ -188491,8 +188459,14 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188491
188459
|
if (element.needsScope) {
|
|
188492
188460
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
188493
188461
|
}
|
|
188494
|
-
if (
|
|
188495
|
-
|
|
188462
|
+
if (element.keyAttr) {
|
|
188463
|
+
if (element.keyAttr.value !== undefined) {
|
|
188464
|
+
const lowered = emitAttrValue({ kind: "expression", expr: element.keyAttr.value }, this.elementAttrEmitter, element.keyAttr.name);
|
|
188465
|
+
if (lowered)
|
|
188466
|
+
hydrationAttrs += ` ${lowered}`;
|
|
188467
|
+
} else {
|
|
188468
|
+
hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
|
|
188469
|
+
}
|
|
188496
188470
|
}
|
|
188497
188471
|
if (element.slotId) {
|
|
188498
188472
|
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 ${jinjaIdent(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
|
-
|
|
188980
|
-
|
|
188981
|
-
|
|
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
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
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) {
|
|
@@ -3060,6 +3069,10 @@ var EMPTY_BOUND = new Set;
|
|
|
3060
3069
|
var constInitializerCache = new WeakMap;
|
|
3061
3070
|
var functionInfoExprCache = new WeakMap;
|
|
3062
3071
|
|
|
3072
|
+
// ../jsx/src/ir-to-client-js/prop-handling.ts
|
|
3073
|
+
var _localConstantValuesCache = new WeakMap;
|
|
3074
|
+
var _restSpreadNamesCache = new WeakMap;
|
|
3075
|
+
|
|
3063
3076
|
// ../jsx/src/ir-to-client-js/control-flow/stringify/template-parse.ts
|
|
3064
3077
|
var SVG_ROOT_TAGS = new Set([
|
|
3065
3078
|
"svg",
|
|
@@ -3181,11 +3194,14 @@ var KEYWORDS_AND_GLOBALS = new Set([
|
|
|
3181
3194
|
// ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
|
|
3182
3195
|
import ts14 from "typescript";
|
|
3183
3196
|
|
|
3197
|
+
// ../jsx/src/ir-to-client-js/imports.ts
|
|
3198
|
+
import ts16 from "typescript";
|
|
3199
|
+
|
|
3184
3200
|
// ../jsx/src/value-references.ts
|
|
3185
3201
|
import ts15 from "typescript";
|
|
3186
3202
|
|
|
3187
3203
|
// ../jsx/src/relocate.ts
|
|
3188
|
-
import
|
|
3204
|
+
import ts17 from "typescript";
|
|
3189
3205
|
|
|
3190
3206
|
// ../jsx/src/lowering-registry.ts
|
|
3191
3207
|
var plugins = [];
|
|
@@ -3402,10 +3418,10 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
|
|
|
3402
3418
|
}
|
|
3403
3419
|
|
|
3404
3420
|
// ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
|
|
3405
|
-
import
|
|
3421
|
+
import ts18 from "typescript";
|
|
3406
3422
|
|
|
3407
3423
|
// ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
|
|
3408
|
-
import
|
|
3424
|
+
import ts19 from "typescript";
|
|
3409
3425
|
var NO_PREAMBLE = {
|
|
3410
3426
|
lazySafe: true,
|
|
3411
3427
|
facts: { declaredNames: new Set, freeNames: new Set }
|
|
@@ -3455,7 +3471,7 @@ var INERT_BINDING_GLOBALS = new Set([
|
|
|
3455
3471
|
]);
|
|
3456
3472
|
|
|
3457
3473
|
// ../jsx/src/ir-to-client-js/emit-reactive.ts
|
|
3458
|
-
import
|
|
3474
|
+
import ts20 from "typescript";
|
|
3459
3475
|
|
|
3460
3476
|
// ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
|
|
3461
3477
|
var NON_BUBBLING_EVENTS = new Set([
|
|
@@ -3470,7 +3486,7 @@ var NON_BUBBLING_EVENTS = new Set([
|
|
|
3470
3486
|
]);
|
|
3471
3487
|
|
|
3472
3488
|
// ../jsx/src/ir-to-client-js/rewrite-props-object.ts
|
|
3473
|
-
import
|
|
3489
|
+
import ts21 from "typescript";
|
|
3474
3490
|
|
|
3475
3491
|
// ../jsx/src/ir-to-client-js/source-map.ts
|
|
3476
3492
|
var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
@@ -3561,15 +3577,15 @@ class SourceMapGenerator {
|
|
|
3561
3577
|
}
|
|
3562
3578
|
|
|
3563
3579
|
// ../jsx/src/preprocess-inline-jsx-callbacks.ts
|
|
3564
|
-
import
|
|
3580
|
+
import ts22 from "typescript";
|
|
3565
3581
|
|
|
3566
3582
|
// ../jsx/src/ssr-defaults.ts
|
|
3567
|
-
import
|
|
3583
|
+
import ts23 from "typescript";
|
|
3568
3584
|
var UNRESOLVED = Symbol("unresolved");
|
|
3569
3585
|
var NO_RETURN = Symbol("no-return");
|
|
3570
3586
|
|
|
3571
3587
|
// ../jsx/src/augment-inherited-props.ts
|
|
3572
|
-
import
|
|
3588
|
+
import ts24 from "typescript";
|
|
3573
3589
|
function collectContextConsumers(metadata) {
|
|
3574
3590
|
const constants = metadata.localConstants ?? [];
|
|
3575
3591
|
const contextDefaults = new Map;
|
|
@@ -3601,47 +3617,47 @@ function collectContextConsumers(metadata) {
|
|
|
3601
3617
|
}
|
|
3602
3618
|
function parseUseContextArg(source) {
|
|
3603
3619
|
const expr = parseSingleExpression(source);
|
|
3604
|
-
if (!expr || !
|
|
3620
|
+
if (!expr || !ts24.isCallExpression(expr))
|
|
3605
3621
|
return null;
|
|
3606
|
-
if (!
|
|
3622
|
+
if (!ts24.isIdentifier(expr.expression) || expr.expression.text !== "useContext")
|
|
3607
3623
|
return null;
|
|
3608
3624
|
if (expr.arguments.length !== 1)
|
|
3609
3625
|
return null;
|
|
3610
3626
|
const arg = expr.arguments[0];
|
|
3611
|
-
return
|
|
3627
|
+
return ts24.isIdentifier(arg) ? arg.text : null;
|
|
3612
3628
|
}
|
|
3613
3629
|
function parseCreateContextDefault(source) {
|
|
3614
3630
|
const expr = parseSingleExpression(source);
|
|
3615
|
-
if (!expr || !
|
|
3631
|
+
if (!expr || !ts24.isCallExpression(expr))
|
|
3616
3632
|
return null;
|
|
3617
3633
|
if (expr.arguments.length === 0)
|
|
3618
3634
|
return null;
|
|
3619
3635
|
const arg = expr.arguments[0];
|
|
3620
|
-
if (
|
|
3636
|
+
if (ts24.isStringLiteral(arg) || ts24.isNoSubstitutionTemplateLiteral(arg))
|
|
3621
3637
|
return arg.text;
|
|
3622
|
-
if (
|
|
3638
|
+
if (ts24.isNumericLiteral(arg))
|
|
3623
3639
|
return Number(arg.text);
|
|
3624
|
-
if (arg.kind ===
|
|
3640
|
+
if (arg.kind === ts24.SyntaxKind.TrueKeyword)
|
|
3625
3641
|
return true;
|
|
3626
|
-
if (arg.kind ===
|
|
3642
|
+
if (arg.kind === ts24.SyntaxKind.FalseKeyword)
|
|
3627
3643
|
return false;
|
|
3628
3644
|
return null;
|
|
3629
3645
|
}
|
|
3630
3646
|
function isObjectLiteralCreateContextDefault(source) {
|
|
3631
3647
|
const expr = parseSingleExpression(source);
|
|
3632
|
-
if (!expr || !
|
|
3648
|
+
if (!expr || !ts24.isCallExpression(expr))
|
|
3633
3649
|
return false;
|
|
3634
3650
|
if (expr.arguments.length === 0)
|
|
3635
3651
|
return false;
|
|
3636
|
-
return
|
|
3652
|
+
return ts24.isObjectLiteralExpression(expr.arguments[0]);
|
|
3637
3653
|
}
|
|
3638
3654
|
function parseSingleExpression(source) {
|
|
3639
|
-
const sf =
|
|
3655
|
+
const sf = ts24.createSourceFile("__ctx.ts", `(${source})`, ts24.ScriptTarget.Latest, false);
|
|
3640
3656
|
const stmt = sf.statements[0];
|
|
3641
|
-
if (!stmt || !
|
|
3657
|
+
if (!stmt || !ts24.isExpressionStatement(stmt))
|
|
3642
3658
|
return null;
|
|
3643
3659
|
let e = stmt.expression;
|
|
3644
|
-
while (
|
|
3660
|
+
while (ts24.isParenthesizedExpression(e))
|
|
3645
3661
|
e = e.expression;
|
|
3646
3662
|
return e;
|
|
3647
3663
|
}
|
|
@@ -3666,25 +3682,25 @@ function augmentInheritedPropAccesses(ir) {
|
|
|
3666
3682
|
const pinCoalesceLiterals = (s) => {
|
|
3667
3683
|
if (!s || !s.includes(propsObj))
|
|
3668
3684
|
return;
|
|
3669
|
-
const sf =
|
|
3685
|
+
const sf = ts24.createSourceFile("__aug.ts", `(${s})`, ts24.ScriptTarget.Latest, false);
|
|
3670
3686
|
const visit = (n) => {
|
|
3671
|
-
if (
|
|
3687
|
+
if (ts24.isBinaryExpression(n) && (n.operatorToken.kind === ts24.SyntaxKind.QuestionQuestionToken || n.operatorToken.kind === ts24.SyntaxKind.BarBarToken)) {
|
|
3672
3688
|
let left = n.left;
|
|
3673
|
-
while (
|
|
3689
|
+
while (ts24.isParenthesizedExpression(left))
|
|
3674
3690
|
left = left.expression;
|
|
3675
|
-
if (
|
|
3691
|
+
if (ts24.isPropertyAccessExpression(left) && ts24.isIdentifier(left.expression) && left.expression.text === propsObj) {
|
|
3676
3692
|
const name = left.name.text;
|
|
3677
3693
|
let right = n.right;
|
|
3678
|
-
while (
|
|
3694
|
+
while (ts24.isParenthesizedExpression(right))
|
|
3679
3695
|
right = right.expression;
|
|
3680
|
-
if (
|
|
3696
|
+
if (ts24.isPrefixUnaryExpression(right))
|
|
3681
3697
|
right = right.operand;
|
|
3682
|
-
const kind =
|
|
3698
|
+
const kind = ts24.isNumericLiteral(right) ? "number" : right.kind === ts24.SyntaxKind.TrueKeyword || right.kind === ts24.SyntaxKind.FalseKeyword ? "boolean" : ts24.isStringLiteralLike(right) ? "string" : null;
|
|
3683
3699
|
if (kind && !coalesceLiteralTypes.has(name))
|
|
3684
3700
|
coalesceLiteralTypes.set(name, kind);
|
|
3685
3701
|
}
|
|
3686
3702
|
}
|
|
3687
|
-
|
|
3703
|
+
ts24.forEachChild(n, visit);
|
|
3688
3704
|
};
|
|
3689
3705
|
visit(sf);
|
|
3690
3706
|
};
|
|
@@ -3795,33 +3811,33 @@ function augmentInheritedPropAccesses(ir) {
|
|
|
3795
3811
|
}
|
|
3796
3812
|
}
|
|
3797
3813
|
function parseStaticStringConst(source) {
|
|
3798
|
-
const sf =
|
|
3814
|
+
const sf = ts24.createSourceFile("__const.ts", `const __x = (${source});`, ts24.ScriptTarget.Latest, false);
|
|
3799
3815
|
const stmt = sf.statements[0];
|
|
3800
|
-
if (!stmt || !
|
|
3816
|
+
if (!stmt || !ts24.isVariableStatement(stmt))
|
|
3801
3817
|
return null;
|
|
3802
3818
|
let init = stmt.declarationList.declarations[0]?.initializer;
|
|
3803
|
-
while (init &&
|
|
3819
|
+
while (init && ts24.isParenthesizedExpression(init))
|
|
3804
3820
|
init = init.expression;
|
|
3805
3821
|
if (!init)
|
|
3806
3822
|
return null;
|
|
3807
|
-
if (
|
|
3823
|
+
if (ts24.isStringLiteral(init) || ts24.isNoSubstitutionTemplateLiteral(init)) {
|
|
3808
3824
|
return init.text;
|
|
3809
3825
|
}
|
|
3810
3826
|
return evalStringArrayJoin(source);
|
|
3811
3827
|
}
|
|
3812
3828
|
function evalTemplateOfStringConsts(source, resolved) {
|
|
3813
|
-
const sf =
|
|
3829
|
+
const sf = ts24.createSourceFile("__const.ts", `const __x = (${source});`, ts24.ScriptTarget.Latest, false);
|
|
3814
3830
|
const stmt = sf.statements[0];
|
|
3815
|
-
if (!stmt || !
|
|
3831
|
+
if (!stmt || !ts24.isVariableStatement(stmt))
|
|
3816
3832
|
return null;
|
|
3817
3833
|
let init = stmt.declarationList.declarations[0]?.initializer;
|
|
3818
|
-
while (init &&
|
|
3834
|
+
while (init && ts24.isParenthesizedExpression(init))
|
|
3819
3835
|
init = init.expression;
|
|
3820
|
-
if (!init || !
|
|
3836
|
+
if (!init || !ts24.isTemplateExpression(init))
|
|
3821
3837
|
return null;
|
|
3822
3838
|
let out = init.head.text;
|
|
3823
3839
|
for (const span of init.templateSpans) {
|
|
3824
|
-
if (!
|
|
3840
|
+
if (!ts24.isIdentifier(span.expression))
|
|
3825
3841
|
return null;
|
|
3826
3842
|
const value = resolved.get(span.expression.text);
|
|
3827
3843
|
if (value === undefined)
|
|
@@ -3854,30 +3870,30 @@ function lookupStaticRecordLiteral(objectName, key, constants, isShadowed) {
|
|
|
3854
3870
|
const constInfo = (constants ?? []).find((c) => c.name === objectName && c.isModule);
|
|
3855
3871
|
if (constInfo?.value === undefined)
|
|
3856
3872
|
return null;
|
|
3857
|
-
const sf =
|
|
3873
|
+
const sf = ts24.createSourceFile("__rec.ts", `(${constInfo.value})`, ts24.ScriptTarget.Latest, true);
|
|
3858
3874
|
if (sf.statements.length !== 1)
|
|
3859
3875
|
return null;
|
|
3860
3876
|
const stmt = sf.statements[0];
|
|
3861
|
-
if (!
|
|
3877
|
+
if (!ts24.isExpressionStatement(stmt))
|
|
3862
3878
|
return null;
|
|
3863
3879
|
let parsed = stmt.expression;
|
|
3864
|
-
while (
|
|
3880
|
+
while (ts24.isParenthesizedExpression(parsed))
|
|
3865
3881
|
parsed = parsed.expression;
|
|
3866
|
-
if (!
|
|
3882
|
+
if (!ts24.isObjectLiteralExpression(parsed))
|
|
3867
3883
|
return null;
|
|
3868
3884
|
for (const prop of parsed.properties) {
|
|
3869
|
-
if (!
|
|
3885
|
+
if (!ts24.isPropertyAssignment(prop))
|
|
3870
3886
|
continue;
|
|
3871
3887
|
const name = prop.name;
|
|
3872
|
-
const propKey =
|
|
3888
|
+
const propKey = ts24.isIdentifier(name) || ts24.isStringLiteral(name) || ts24.isNoSubstitutionTemplateLiteral(name) ? name.text : null;
|
|
3873
3889
|
if (propKey !== key)
|
|
3874
3890
|
continue;
|
|
3875
3891
|
let v = prop.initializer;
|
|
3876
|
-
while (
|
|
3892
|
+
while (ts24.isParenthesizedExpression(v))
|
|
3877
3893
|
v = v.expression;
|
|
3878
|
-
if (
|
|
3894
|
+
if (ts24.isNumericLiteral(v))
|
|
3879
3895
|
return { kind: "number", text: v.text };
|
|
3880
|
-
if (
|
|
3896
|
+
if (ts24.isStringLiteral(v) || ts24.isNoSubstitutionTemplateLiteral(v)) {
|
|
3881
3897
|
return { kind: "string", text: v.text };
|
|
3882
3898
|
}
|
|
3883
3899
|
return null;
|
|
@@ -3885,28 +3901,28 @@ function lookupStaticRecordLiteral(objectName, key, constants, isShadowed) {
|
|
|
3885
3901
|
return null;
|
|
3886
3902
|
}
|
|
3887
3903
|
function evalStringArrayJoin(source) {
|
|
3888
|
-
const sf =
|
|
3904
|
+
const sf = ts24.createSourceFile("__join.ts", `const __x = (${source});`, ts24.ScriptTarget.Latest, false);
|
|
3889
3905
|
const stmt = sf.statements[0];
|
|
3890
|
-
if (!stmt || !
|
|
3906
|
+
if (!stmt || !ts24.isVariableStatement(stmt))
|
|
3891
3907
|
return null;
|
|
3892
3908
|
let node = stmt.declarationList.declarations[0]?.initializer;
|
|
3893
|
-
while (node &&
|
|
3909
|
+
while (node && ts24.isParenthesizedExpression(node))
|
|
3894
3910
|
node = node.expression;
|
|
3895
|
-
if (!node || !
|
|
3911
|
+
if (!node || !ts24.isCallExpression(node))
|
|
3896
3912
|
return null;
|
|
3897
3913
|
const callee = node.expression;
|
|
3898
|
-
if (!
|
|
3914
|
+
if (!ts24.isPropertyAccessExpression(callee))
|
|
3899
3915
|
return null;
|
|
3900
3916
|
if (callee.name.text !== "join")
|
|
3901
3917
|
return null;
|
|
3902
3918
|
let recv = callee.expression;
|
|
3903
|
-
while (
|
|
3919
|
+
while (ts24.isParenthesizedExpression(recv))
|
|
3904
3920
|
recv = recv.expression;
|
|
3905
|
-
if (!
|
|
3921
|
+
if (!ts24.isArrayLiteralExpression(recv))
|
|
3906
3922
|
return null;
|
|
3907
3923
|
const parts = [];
|
|
3908
3924
|
for (const el of recv.elements) {
|
|
3909
|
-
if (
|
|
3925
|
+
if (ts24.isStringLiteral(el) || ts24.isNoSubstitutionTemplateLiteral(el)) {
|
|
3910
3926
|
parts.push(el.text);
|
|
3911
3927
|
} else {
|
|
3912
3928
|
return null;
|
|
@@ -3915,7 +3931,7 @@ function evalStringArrayJoin(source) {
|
|
|
3915
3931
|
let sep = ",";
|
|
3916
3932
|
if (node.arguments.length >= 1) {
|
|
3917
3933
|
const arg = node.arguments[0];
|
|
3918
|
-
if (
|
|
3934
|
+
if (ts24.isStringLiteral(arg) || ts24.isNoSubstitutionTemplateLiteral(arg))
|
|
3919
3935
|
sep = arg.text;
|
|
3920
3936
|
else
|
|
3921
3937
|
return null;
|
|
@@ -3923,11 +3939,11 @@ function evalStringArrayJoin(source) {
|
|
|
3923
3939
|
return parts.join(sep);
|
|
3924
3940
|
}
|
|
3925
3941
|
function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
3926
|
-
if (!
|
|
3942
|
+
if (!ts24.isElementAccessExpression(val))
|
|
3927
3943
|
return null;
|
|
3928
3944
|
const obj = val.expression;
|
|
3929
3945
|
const arg = val.argumentExpression;
|
|
3930
|
-
if (!
|
|
3946
|
+
if (!ts24.isIdentifier(obj) || !ts24.isIdentifier(arg))
|
|
3931
3947
|
return null;
|
|
3932
3948
|
let indexPropName;
|
|
3933
3949
|
let defaultKey;
|
|
@@ -3943,35 +3959,35 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
|
3943
3959
|
const constInfo = localConstants.find((c) => c.name === obj.text && c.isModule);
|
|
3944
3960
|
if (constInfo?.value === undefined)
|
|
3945
3961
|
return null;
|
|
3946
|
-
const sf =
|
|
3962
|
+
const sf = ts24.createSourceFile("__rec.ts", `(${constInfo.value})`, ts24.ScriptTarget.Latest, true);
|
|
3947
3963
|
if (sf.statements.length !== 1)
|
|
3948
3964
|
return null;
|
|
3949
3965
|
const stmt = sf.statements[0];
|
|
3950
|
-
if (!
|
|
3966
|
+
if (!ts24.isExpressionStatement(stmt))
|
|
3951
3967
|
return null;
|
|
3952
3968
|
let parsed = stmt.expression;
|
|
3953
|
-
while (
|
|
3969
|
+
while (ts24.isParenthesizedExpression(parsed))
|
|
3954
3970
|
parsed = parsed.expression;
|
|
3955
|
-
if (!
|
|
3971
|
+
if (!ts24.isObjectLiteralExpression(parsed))
|
|
3956
3972
|
return null;
|
|
3957
3973
|
const entries = [];
|
|
3958
3974
|
for (const prop of parsed.properties) {
|
|
3959
|
-
if (!
|
|
3975
|
+
if (!ts24.isPropertyAssignment(prop))
|
|
3960
3976
|
return null;
|
|
3961
3977
|
let key;
|
|
3962
|
-
if (
|
|
3978
|
+
if (ts24.isIdentifier(prop.name)) {
|
|
3963
3979
|
key = prop.name.text;
|
|
3964
|
-
} else if (
|
|
3980
|
+
} else if (ts24.isStringLiteral(prop.name) || ts24.isNoSubstitutionTemplateLiteral(prop.name)) {
|
|
3965
3981
|
key = prop.name.text;
|
|
3966
3982
|
} else {
|
|
3967
3983
|
return null;
|
|
3968
3984
|
}
|
|
3969
3985
|
let v = prop.initializer;
|
|
3970
|
-
while (
|
|
3986
|
+
while (ts24.isParenthesizedExpression(v))
|
|
3971
3987
|
v = v.expression;
|
|
3972
|
-
if (
|
|
3988
|
+
if (ts24.isNumericLiteral(v)) {
|
|
3973
3989
|
entries.push({ key, value: { kind: "number", text: v.text } });
|
|
3974
|
-
} else if (
|
|
3990
|
+
} else if (ts24.isStringLiteral(v) || ts24.isNoSubstitutionTemplateLiteral(v)) {
|
|
3975
3991
|
entries.push({ key, value: { kind: "string", text: v.text } });
|
|
3976
3992
|
} else {
|
|
3977
3993
|
return null;
|
|
@@ -4060,7 +4076,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
4060
4076
|
// ../jsx/src/rich-type-refusal.ts
|
|
4061
4077
|
var EMPTY_BINDINGS2 = new Map;
|
|
4062
4078
|
// ../jsx/src/shared-program.ts
|
|
4063
|
-
import
|
|
4079
|
+
import ts26 from "typescript";
|
|
4064
4080
|
// ../jsx/src/adapters/interface.ts
|
|
4065
4081
|
class BaseAdapter {
|
|
4066
4082
|
renderChildren(children) {
|
|
@@ -4342,7 +4358,7 @@ class JsxAdapter extends BaseAdapter {
|
|
|
4342
4358
|
}
|
|
4343
4359
|
|
|
4344
4360
|
// ../jsx/src/adapters/template-imports.ts
|
|
4345
|
-
import
|
|
4361
|
+
import ts27 from "typescript";
|
|
4346
4362
|
var CLIENT_PACKAGE_SOURCES = new Set([
|
|
4347
4363
|
"@barefootjs/client",
|
|
4348
4364
|
"@barefootjs/client/runtime"
|
|
@@ -5055,7 +5071,7 @@ function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
|
|
|
5055
5071
|
};
|
|
5056
5072
|
}
|
|
5057
5073
|
// ../jsx/src/combine-client-js.ts
|
|
5058
|
-
import
|
|
5074
|
+
import ts28 from "typescript";
|
|
5059
5075
|
// ../jsx/src/loop-destructure.ts
|
|
5060
5076
|
function isLowerableLoopDestructure(loop) {
|
|
5061
5077
|
const bindings = loop.paramBindings;
|
|
@@ -5195,9 +5211,9 @@ function escapeRe(s) {
|
|
|
5195
5211
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5196
5212
|
}
|
|
5197
5213
|
// ../jsx/src/debug.ts
|
|
5198
|
-
import ts28 from "typescript";
|
|
5199
|
-
// ../jsx/src/profiler.ts
|
|
5200
5214
|
import ts29 from "typescript";
|
|
5215
|
+
// ../jsx/src/profiler.ts
|
|
5216
|
+
import ts30 from "typescript";
|
|
5201
5217
|
|
|
5202
5218
|
// ../jsx/src/index.ts
|
|
5203
5219
|
registerBuiltinLoweringPlugins();
|
|
@@ -5331,62 +5347,6 @@ function jinjaAccessorFromSegments(base, segments) {
|
|
|
5331
5347
|
return acc;
|
|
5332
5348
|
}
|
|
5333
5349
|
|
|
5334
|
-
// src/adapter/lib/ir-scope.ts
|
|
5335
|
-
var NON_VAR_TOKENS = new Set([
|
|
5336
|
-
"bf",
|
|
5337
|
-
"if",
|
|
5338
|
-
"else",
|
|
5339
|
-
"is",
|
|
5340
|
-
"not",
|
|
5341
|
-
"and",
|
|
5342
|
-
"or",
|
|
5343
|
-
"in",
|
|
5344
|
-
"none",
|
|
5345
|
-
"true",
|
|
5346
|
-
"false",
|
|
5347
|
-
"defined"
|
|
5348
|
-
]);
|
|
5349
|
-
function extractTopLevelIdentifiers(jinjaExpr) {
|
|
5350
|
-
const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
|
|
5351
|
-
const out = [];
|
|
5352
|
-
for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
|
|
5353
|
-
if (!NON_VAR_TOKENS.has(m[1]))
|
|
5354
|
-
out.push(m[1]);
|
|
5355
|
-
}
|
|
5356
|
-
return out;
|
|
5357
|
-
}
|
|
5358
|
-
function resolveJsxChildrenProp(props) {
|
|
5359
|
-
const prop = props.find((p) => p.name === "children");
|
|
5360
|
-
if (!prop)
|
|
5361
|
-
return [];
|
|
5362
|
-
if (prop.value.kind !== "jsx-children")
|
|
5363
|
-
return [];
|
|
5364
|
-
return prop.value.children;
|
|
5365
|
-
}
|
|
5366
|
-
function collectRootScopeNodes(node) {
|
|
5367
|
-
const out = new Set;
|
|
5368
|
-
const visit = (n) => {
|
|
5369
|
-
if (!n)
|
|
5370
|
-
return;
|
|
5371
|
-
if (n.type === "element") {
|
|
5372
|
-
out.add(n);
|
|
5373
|
-
return;
|
|
5374
|
-
}
|
|
5375
|
-
if (n.type === "if-statement") {
|
|
5376
|
-
const s = n;
|
|
5377
|
-
visit(s.consequent);
|
|
5378
|
-
visit(s.alternate);
|
|
5379
|
-
return;
|
|
5380
|
-
}
|
|
5381
|
-
if (n.type === "fragment") {
|
|
5382
|
-
for (const c of n.children)
|
|
5383
|
-
visit(c);
|
|
5384
|
-
}
|
|
5385
|
-
};
|
|
5386
|
-
visit(node);
|
|
5387
|
-
return out;
|
|
5388
|
-
}
|
|
5389
|
-
|
|
5390
5350
|
// src/adapter/expr/array-method.ts
|
|
5391
5351
|
function renderArrayMethod(method, object, args, emit) {
|
|
5392
5352
|
switch (method) {
|
|
@@ -6030,7 +5990,7 @@ function collectImportedLoopChildComponentErrors(ir, componentName) {
|
|
|
6030
5990
|
}
|
|
6031
5991
|
|
|
6032
5992
|
// src/adapter/spread/spread-codegen.ts
|
|
6033
|
-
import
|
|
5993
|
+
import ts31 from "typescript";
|
|
6034
5994
|
function conditionalSpreadToJinja(ctx, expr) {
|
|
6035
5995
|
if (!expr || expr.kind !== "conditional")
|
|
6036
5996
|
return null;
|
|
@@ -6087,7 +6047,7 @@ function recordIndexAccessToJinja(ctx, val) {
|
|
|
6087
6047
|
if (val.kind !== "index-access" || val.object.kind !== "identifier" || val.index.kind !== "identifier") {
|
|
6088
6048
|
return null;
|
|
6089
6049
|
}
|
|
6090
|
-
const tsVal =
|
|
6050
|
+
const tsVal = ts31.factory.createElementAccessExpression(ts31.factory.createIdentifier(val.object.name), ts31.factory.createIdentifier(val.index.name));
|
|
6091
6051
|
const parsed = parseRecordIndexAccess(tsVal, ctx.localConstants ?? [], ctx.propsParams);
|
|
6092
6052
|
if (!parsed)
|
|
6093
6053
|
return null;
|
|
@@ -6098,6 +6058,31 @@ function recordIndexAccessToJinja(ctx, val) {
|
|
|
6098
6058
|
return `{${entries.join(", ")}}[${jinjaIdent(parsed.indexPropName)}]`;
|
|
6099
6059
|
}
|
|
6100
6060
|
|
|
6061
|
+
// src/adapter/lib/ir-scope.ts
|
|
6062
|
+
var NON_VAR_TOKENS = new Set([
|
|
6063
|
+
"bf",
|
|
6064
|
+
"if",
|
|
6065
|
+
"else",
|
|
6066
|
+
"is",
|
|
6067
|
+
"not",
|
|
6068
|
+
"and",
|
|
6069
|
+
"or",
|
|
6070
|
+
"in",
|
|
6071
|
+
"none",
|
|
6072
|
+
"true",
|
|
6073
|
+
"false",
|
|
6074
|
+
"defined"
|
|
6075
|
+
]);
|
|
6076
|
+
function extractTopLevelIdentifiers(jinjaExpr) {
|
|
6077
|
+
const stripped = jinjaExpr.replace(/'(?:\\.|[^'\\])*'/g, " ");
|
|
6078
|
+
const out = [];
|
|
6079
|
+
for (const m of stripped.matchAll(/(?<!\.)\b([A-Za-z_]\w*)\b/g)) {
|
|
6080
|
+
if (!NON_VAR_TOKENS.has(m[1]))
|
|
6081
|
+
out.push(m[1]);
|
|
6082
|
+
}
|
|
6083
|
+
return out;
|
|
6084
|
+
}
|
|
6085
|
+
|
|
6101
6086
|
// src/adapter/memo/seed.ts
|
|
6102
6087
|
function contextDefaultJinja(c) {
|
|
6103
6088
|
const d = c.defaultValue;
|
|
@@ -6179,11 +6164,9 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
6179
6164
|
templatesPerComponent = true;
|
|
6180
6165
|
templatePrimitives = JINJA_PRIMITIVE_EMIT_MAP;
|
|
6181
6166
|
componentName = "";
|
|
6182
|
-
rootScopeNodes = new Set;
|
|
6183
6167
|
options;
|
|
6184
6168
|
errors = [];
|
|
6185
6169
|
inLoop = false;
|
|
6186
|
-
currentLoopKeyDepth = 0;
|
|
6187
6170
|
propsObjectName = null;
|
|
6188
6171
|
propsParams = [];
|
|
6189
6172
|
booleanTypedProps = new Set;
|
|
@@ -6219,7 +6202,6 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
6219
6202
|
if (!options?.siblingTemplatesRegistered) {
|
|
6220
6203
|
this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName));
|
|
6221
6204
|
}
|
|
6222
|
-
this.rootScopeNodes = collectRootScopeNodes(ir.root);
|
|
6223
6205
|
const templateBody = ir.root.type === "if-statement" ? this.renderIfStatement(ir.root) : this.renderNode(ir.root);
|
|
6224
6206
|
const scriptReg = options?.skipScriptRegistration ? "" : this.generateScriptRegistrations(ir, options?.scriptBaseName, options?.scriptAssets, options?.preloadAssets);
|
|
6225
6207
|
const ctxSeed = generateContextConsumerSeed(ir);
|
|
@@ -6352,8 +6334,14 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
6352
6334
|
if (element.needsScope) {
|
|
6353
6335
|
hydrationAttrs += ` ${this.renderScopeMarker("")}`;
|
|
6354
6336
|
}
|
|
6355
|
-
if (
|
|
6356
|
-
|
|
6337
|
+
if (element.keyAttr) {
|
|
6338
|
+
if (element.keyAttr.value !== undefined) {
|
|
6339
|
+
const lowered = emitAttrValue({ kind: "expression", expr: element.keyAttr.value }, this.elementAttrEmitter, element.keyAttr.name);
|
|
6340
|
+
if (lowered)
|
|
6341
|
+
hydrationAttrs += ` ${lowered}`;
|
|
6342
|
+
} else {
|
|
6343
|
+
hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`;
|
|
6344
|
+
}
|
|
6357
6345
|
}
|
|
6358
6346
|
if (element.slotId) {
|
|
6359
6347
|
hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`;
|
|
@@ -6556,13 +6544,10 @@ ${whenTrue}
|
|
|
6556
6544
|
}
|
|
6557
6545
|
const prevInLoop = this.inLoop;
|
|
6558
6546
|
this.inLoop = true;
|
|
6559
|
-
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
6560
|
-
this.currentLoopKeyDepth = loop.depth;
|
|
6561
6547
|
const prevScope = this.scope;
|
|
6562
6548
|
this.scope = prevScope.enterLoopRow(loop);
|
|
6563
6549
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
6564
6550
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
6565
|
-
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
6566
6551
|
this.inLoop = prevInLoop;
|
|
6567
6552
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
6568
6553
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
@@ -6837,14 +6822,9 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
6837
6822
|
continue;
|
|
6838
6823
|
if (isDangerousInnerHtmlAttr(attr))
|
|
6839
6824
|
continue;
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
else if (attr.name === "key") {
|
|
6844
|
-
const depth = this.currentLoopKeyDepth;
|
|
6845
|
-
attrName = depth > 0 ? `data-key-${depth}` : "data-key";
|
|
6846
|
-
} else
|
|
6847
|
-
attrName = attr.name;
|
|
6825
|
+
if (attr.name === "key")
|
|
6826
|
+
continue;
|
|
6827
|
+
const attrName = attr.name === "className" ? "class" : attr.name;
|
|
6848
6828
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
|
|
6849
6829
|
if (lowered)
|
|
6850
6830
|
parts.push(lowered);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jinja",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.3",
|
|
4
4
|
"description": "Jinja2 adapter for BarefootJS — compiles IR to .jinja templates and ships the Python BarefootJS rendering runtime; runs under any Python web framework (Flask, etc.)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"directory": "packages/adapter-jinja"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@barefootjs/shared": "0.33.
|
|
56
|
+
"@barefootjs/shared": "0.33.3"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
73
|
-
"@barefootjs/jsx": "0.33.
|
|
74
|
-
"@barefootjs/vite": "0.33.
|
|
75
|
-
"@barefootjs/client": "0.33.
|
|
73
|
+
"@barefootjs/jsx": "0.33.3",
|
|
74
|
+
"@barefootjs/vite": "0.33.3",
|
|
75
|
+
"@barefootjs/client": "0.33.3",
|
|
76
76
|
"typescript": "^5.0.0",
|
|
77
77
|
"vite": "^6.0.0"
|
|
78
78
|
}
|
|
@@ -588,12 +588,20 @@ export function ChildFragment() {
|
|
|
588
588
|
// last top-level node -- both read the same `bf._scope_id()` at render
|
|
589
589
|
// time, so the emitted scope ids are identical by construction.
|
|
590
590
|
const beginIdx = template.indexOf('bf.scope_comment() | safe')
|
|
591
|
-
const buttonIdx = template.indexOf('<button
|
|
591
|
+
const buttonIdx = template.indexOf('<button')
|
|
592
592
|
const pIdx = template.indexOf('<p>')
|
|
593
593
|
const endIdx = template.indexOf('bf.scope_comment_end() | safe')
|
|
594
594
|
expect(beginIdx).toBeLessThan(buttonIdx)
|
|
595
595
|
expect(buttonIdx).toBeLessThan(pIdx)
|
|
596
596
|
expect(pIdx).toBeLessThan(endIdx)
|
|
597
|
+
// #2732: the fragment's FIRST element carries `data-key` — the wrapping
|
|
598
|
+
// comment holds scope identity only, so the tag is no longer bare (which
|
|
599
|
+
// is why the locator above matches `<button` and not `<button>`). Pinned
|
|
600
|
+
// both ways so "first element" can never silently widen to "every
|
|
601
|
+
// element": a second carrier would put the loop key on two nodes and
|
|
602
|
+
// `mapArray`'s `primaryEl.dataset.key` read would pick an arbitrary one.
|
|
603
|
+
expect(template.slice(buttonIdx, pIdx)).toContain('data_key_attr')
|
|
604
|
+
expect(template.slice(pIdx)).not.toContain('data_key_attr')
|
|
597
605
|
})
|
|
598
606
|
|
|
599
607
|
test('a non-fragment (single element) root does NOT get scope_comment_end (element attrs bound the scope instead)', () => {
|
|
@@ -151,7 +151,7 @@ import {
|
|
|
151
151
|
} from '@barefootjs/jsx'
|
|
152
152
|
import { isAriaBooleanAttr, isBooleanResultExpr, isExplicitStringCall } from './boolean-result.ts'
|
|
153
153
|
import type { ParsedExpr, LoweringMatcher } from '@barefootjs/jsx'
|
|
154
|
-
import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from '@barefootjs/shared'
|
|
154
|
+
import { BF_SLOT, BF_COND, BF_REGION, escapeHtml, resolveJsxChildrenProp } from '@barefootjs/shared'
|
|
155
155
|
|
|
156
156
|
import type { JinjaRenderCtx } from './lib/types.ts'
|
|
157
157
|
import { JINJA_PRIMITIVE_EMIT_MAP } from './lib/constants.ts'
|
|
@@ -161,10 +161,6 @@ import {
|
|
|
161
161
|
escapeJinjaSingleQuoted,
|
|
162
162
|
jinjaAccessorFromSegments,
|
|
163
163
|
} from './lib/jinja-naming.ts'
|
|
164
|
-
import {
|
|
165
|
-
resolveJsxChildrenProp,
|
|
166
|
-
collectRootScopeNodes,
|
|
167
|
-
} from './lib/ir-scope.ts'
|
|
168
164
|
import { renderSortMethod, renderSortEval } from './expr/array-method.ts'
|
|
169
165
|
import { staticValueToJinja } from './lib/static-value.ts'
|
|
170
166
|
import { JinjaFilterEmitter, JinjaTopLevelEmitter, truthyTest } from './expr/emitters.ts'
|
|
@@ -204,22 +200,9 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
204
200
|
templatePrimitives: TemplatePrimitiveRegistry = JINJA_PRIMITIVE_EMIT_MAP
|
|
205
201
|
|
|
206
202
|
private componentName: string = ''
|
|
207
|
-
/** Component root scope element(s) — each carries `data-key` for a keyed loop
|
|
208
|
-
* item (set by the child renderer from the JSX `key` prop). A plain element
|
|
209
|
-
* root is one node; an `if-statement` (early-return) root contributes the
|
|
210
|
-
* top element of every branch. */
|
|
211
|
-
private rootScopeNodes: Set<IRNode> = new Set()
|
|
212
203
|
private options: Required<JinjaAdapterOptions>
|
|
213
204
|
private errors: CompilerError[] = []
|
|
214
205
|
private inLoop: boolean = false
|
|
215
|
-
/**
|
|
216
|
-
* `IRLoop.depth` of the loop currently being rendered (save/restore
|
|
217
|
-
* around `renderChildren(loop.children)`, mirroring `inLoop` above).
|
|
218
|
-
* `renderAttributes` reads this to derive the `key` → `data-key`/
|
|
219
|
-
* `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
|
|
220
|
-
* re-derived here (#2168 nested-loop-outer-binding).
|
|
221
|
-
*/
|
|
222
|
-
private currentLoopKeyDepth = 0
|
|
223
206
|
/**
|
|
224
207
|
* SolidJS-style props identifier (`function(props: P)`) and the
|
|
225
208
|
* analyzer-extracted prop names. Stashed at `generate()` entry so the
|
|
@@ -343,7 +326,6 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
343
326
|
this.errors.push(...collectImportedLoopChildComponentErrors(ir, this.componentName))
|
|
344
327
|
}
|
|
345
328
|
|
|
346
|
-
this.rootScopeNodes = collectRootScopeNodes(ir.root)
|
|
347
329
|
const templateBody = ir.root.type === 'if-statement'
|
|
348
330
|
? this.renderIfStatement(ir.root as IRIfStatement)
|
|
349
331
|
: this.renderNode(ir.root)
|
|
@@ -579,12 +561,30 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
579
561
|
if (element.needsScope) {
|
|
580
562
|
hydrationAttrs += ` ${this.renderScopeMarker('')}`
|
|
581
563
|
}
|
|
582
|
-
//
|
|
583
|
-
//
|
|
584
|
-
//
|
|
585
|
-
// root, including
|
|
586
|
-
|
|
587
|
-
|
|
564
|
+
// #2753: `element.keyAttr` is the ONE IR-resolved decision for this
|
|
565
|
+
// element's row-key attribute — replacing both the `carriesDataKey`
|
|
566
|
+
// boolean and this adapter's own `rootScopeNodes`/`needsScope` check
|
|
567
|
+
// (mechanism 2: a render-root relay, including the #2732 fragment-root
|
|
568
|
+
// case) and the separate `currentLoopKeyDepth`-driven rewrite of a
|
|
569
|
+
// literal `key` attribute this adapter used to do in `renderAttributes`
|
|
570
|
+
// (mechanism 1: a `.map()` row root compiled inline here).
|
|
571
|
+
if (element.keyAttr) {
|
|
572
|
+
if (element.keyAttr.value !== undefined) {
|
|
573
|
+
const lowered = emitAttrValue(
|
|
574
|
+
{ kind: 'expression', expr: element.keyAttr.value },
|
|
575
|
+
this.elementAttrEmitter,
|
|
576
|
+
element.keyAttr.name,
|
|
577
|
+
)
|
|
578
|
+
if (lowered) hydrationAttrs += ` ${lowered}`
|
|
579
|
+
} else {
|
|
580
|
+
// Relay: this element is one of THIS component's own render roots,
|
|
581
|
+
// carrying whatever key its OWN caller supplies at runtime (the `bf`
|
|
582
|
+
// instance's `data_key` field) when this component is itself
|
|
583
|
+
// invoked as a caller's keyed loop row. Mirrors Hono stamping
|
|
584
|
+
// data-key on each loop item's root, including early-return
|
|
585
|
+
// (if-statement) roots (#1297), and #2732's fragment-root case.
|
|
586
|
+
hydrationAttrs += ` {{ bf.data_key_attr() | safe }}`
|
|
587
|
+
}
|
|
588
588
|
}
|
|
589
589
|
if (element.slotId) {
|
|
590
590
|
hydrationAttrs += ` ${this.renderSlotMarker(element.slotId)}`
|
|
@@ -932,8 +932,6 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
932
932
|
|
|
933
933
|
const prevInLoop = this.inLoop
|
|
934
934
|
this.inLoop = true
|
|
935
|
-
const prevLoopKeyDepth = this.currentLoopKeyDepth
|
|
936
|
-
this.currentLoopKeyDepth = loop.depth
|
|
937
935
|
// Re-render children now that inLoop is set (so nested components use the
|
|
938
936
|
// loop-child naming convention). renderedChildren above was computed with
|
|
939
937
|
// the previous flag; recompute under the loop flag.
|
|
@@ -975,7 +973,6 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
975
973
|
d => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`,
|
|
976
974
|
)
|
|
977
975
|
const childrenUnderLoop = this.renderChildren(loop.children)
|
|
978
|
-
this.currentLoopKeyDepth = prevLoopKeyDepth
|
|
979
976
|
this.inLoop = prevInLoop
|
|
980
977
|
void renderedChildren
|
|
981
978
|
|
|
@@ -1543,14 +1540,15 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1543
1540
|
// literal never reaches the generic object-literal BF101 refusal
|
|
1544
1541
|
// (which would double-report alongside the purpose-built one).
|
|
1545
1542
|
if (isDangerousInnerHtmlAttr(attr)) continue
|
|
1543
|
+
// `key` never renders as a literal HTML attribute — #2753 resolves it
|
|
1544
|
+
// onto `element.keyAttr` (name AND value) at IR-build time, emitted
|
|
1545
|
+
// separately in `renderElement`. A stray `key` that jsx-to-ir.ts did
|
|
1546
|
+
// NOT recognize as a loop row root (so `keyAttr` was never set) has no
|
|
1547
|
+
// defined rendering outside a `.map()` anyway; drop it rather than
|
|
1548
|
+
// leak an invalid `key="..."` HTML attribute.
|
|
1549
|
+
if (attr.name === 'key') continue
|
|
1546
1550
|
// Rewrite JSX special-prop names to their HTML-attribute counterparts.
|
|
1547
|
-
|
|
1548
|
-
if (attr.name === 'className') attrName = 'class'
|
|
1549
|
-
else if (attr.name === 'key') {
|
|
1550
|
-
const depth = this.currentLoopKeyDepth
|
|
1551
|
-
attrName = depth > 0 ? `data-key-${depth}` : 'data-key'
|
|
1552
|
-
}
|
|
1553
|
-
else attrName = attr.name
|
|
1551
|
+
const attrName = attr.name === 'className' ? 'class' : attr.name
|
|
1554
1552
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName)
|
|
1555
1553
|
if (lowered) parts.push(lowered)
|
|
1556
1554
|
}
|
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
* IR traversal helpers for the Jinja2 template adapter.
|
|
3
3
|
*
|
|
4
4
|
* Ported from `packages/adapter-xslate/src/adapter/lib/ir-scope.ts`.
|
|
5
|
-
* `resolveJsxChildrenProp`
|
|
6
|
-
*
|
|
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
|
-
}
|