@barefootjs/jinja 0.30.2 → 0.30.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 +36 -1
- package/dist/adapter/jinja-adapter.d.ts +16 -0
- package/dist/adapter/jinja-adapter.d.ts.map +1 -1
- package/dist/build.js +36 -1
- package/dist/index.js +36 -2
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/adapter/jinja-adapter.ts +62 -1
- package/src/render-divergences.ts +0 -2
package/dist/adapter/index.js
CHANGED
|
@@ -188322,6 +188322,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188322
188322
|
_loweringMatchers = [];
|
|
188323
188323
|
localConstants = [];
|
|
188324
188324
|
staticLoopSourceBoundNames = new Set;
|
|
188325
|
+
loopBoundNames = new Map;
|
|
188325
188326
|
nullableOptionalProps = new Set;
|
|
188326
188327
|
constructor(options = {}) {
|
|
188327
188328
|
super();
|
|
@@ -188338,6 +188339,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188338
188339
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188339
188340
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188340
188341
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188342
|
+
this.loopBoundNames.clear();
|
|
188341
188343
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188342
188344
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188343
188345
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188671,7 +188673,35 @@ ${whenTrue}
|
|
|
188671
188673
|
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188672
188674
|
this.currentLoopKeyDepth = loop.depth;
|
|
188673
188675
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188676
|
+
const loopBound = [];
|
|
188677
|
+
if (loop.objectIteration === "entries") {
|
|
188678
|
+
loopBound.push(loop.index ?? param, param);
|
|
188679
|
+
} else if (loop.objectIteration === "keys" || loop.objectIteration === "values") {
|
|
188680
|
+
loopBound.push(param);
|
|
188681
|
+
} else if (loop.iterationShape === "keys") {
|
|
188682
|
+
loopBound.push("__bf_item", param);
|
|
188683
|
+
} else if (supportableDestructure) {
|
|
188684
|
+
loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
|
|
188685
|
+
if (loop.index)
|
|
188686
|
+
loopBound.push(loop.index);
|
|
188687
|
+
} else {
|
|
188688
|
+
loopBound.push(param);
|
|
188689
|
+
if (loop.index)
|
|
188690
|
+
loopBound.push(loop.index);
|
|
188691
|
+
}
|
|
188692
|
+
for (const d of loop.preamble?.declarations ?? [])
|
|
188693
|
+
loopBound.push(d.name);
|
|
188694
|
+
for (const n of loopBound) {
|
|
188695
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
|
|
188696
|
+
}
|
|
188674
188697
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188698
|
+
for (const n of loopBound) {
|
|
188699
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1;
|
|
188700
|
+
if (c <= 0)
|
|
188701
|
+
this.loopBoundNames.delete(n);
|
|
188702
|
+
else
|
|
188703
|
+
this.loopBoundNames.set(n, c);
|
|
188704
|
+
}
|
|
188675
188705
|
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188676
188706
|
this.inLoop = prevInLoop;
|
|
188677
188707
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
@@ -188850,7 +188880,7 @@ ${children}`;
|
|
|
188850
188880
|
}
|
|
188851
188881
|
const bareId = value.expr.trim();
|
|
188852
188882
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
188853
|
-
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
188883
|
+
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
|
|
188854
188884
|
const jinja2 = this.convertExpressionToJinja(value.expr);
|
|
188855
188885
|
const body = this.shouldBoolStr(value.expr, name) ? `${name}="{{ bf.bool_str(${jinja2}) }}"` : `${name}="{{ bf.string(${jinja2}) }}"`;
|
|
188856
188886
|
return `
|
|
@@ -189137,8 +189167,13 @@ Options:
|
|
|
189137
189167
|
}
|
|
189138
189168
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
189139
189169
|
return false;
|
|
189170
|
+
if (this.isLoopBoundName(bare))
|
|
189171
|
+
return false;
|
|
189140
189172
|
return this.booleanTypedProps.has(bare);
|
|
189141
189173
|
}
|
|
189174
|
+
isLoopBoundName(name) {
|
|
189175
|
+
return this.loopBoundNames.has(name);
|
|
189176
|
+
}
|
|
189142
189177
|
shouldBoolStr(expr, name) {
|
|
189143
189178
|
if (isExplicitStringCall(expr))
|
|
189144
189179
|
return false;
|
|
@@ -178,6 +178,20 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
178
178
|
* `collectLoopBoundNames` use in `collectStringValueNames`.
|
|
179
179
|
*/
|
|
180
180
|
private staticLoopSourceBoundNames;
|
|
181
|
+
/**
|
|
182
|
+
* Names currently bound by an enclosing loop body — the block-param
|
|
183
|
+
* locals `renderLoop` introduces (item, index, per-binding destructure
|
|
184
|
+
* fields, `.map()` preamble declarations) — ref-counted so nested loops
|
|
185
|
+
* compose. This is the POSITION-ACCURATE twin of the coarse
|
|
186
|
+
* `staticLoopSourceBoundNames` above: that set is a whole-component
|
|
187
|
+
* union used only to guard static-const inlining (safe to over-suppress
|
|
188
|
+
* there — the fallback is just "don't inline"), whereas the boolean-prop
|
|
189
|
+
* and nullable-optional classification sites need to know whether a name
|
|
190
|
+
* is loop-bound AT THIS POSITION, because for those two the coarse
|
|
191
|
+
* fallback would silently mis-render a genuine prop occurrence outside
|
|
192
|
+
* the loop too (#2488).
|
|
193
|
+
*/
|
|
194
|
+
private loopBoundNames;
|
|
181
195
|
/**
|
|
182
196
|
* Optional, no-default props that are `None` when the caller omits them.
|
|
183
197
|
* Their bare-reference attribute emission is guarded with a Jinja
|
|
@@ -390,6 +404,8 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
390
404
|
consequent: string;
|
|
391
405
|
} | null;
|
|
392
406
|
isBooleanTypedPropRef(expr: string): boolean;
|
|
407
|
+
/** Position-accurate loop-bound-name check — see `loopBoundNames`'s docstring. */
|
|
408
|
+
private isLoopBoundName;
|
|
393
409
|
/**
|
|
394
410
|
* Whether an attribute-value expression should route through
|
|
395
411
|
* `bf.bool_str` (vs. plain `bf.string`) at its interpolation site.
|
|
@@ -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,EAgChB,MAAM,iBAAiB,CAAA;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAkCpD,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAEzD,qBAAa,YAAa,SAAQ,WAAY,YAAW,aAAa,CAAC,cAAc,CAAC;IACpF,IAAI,SAAU;IACd,SAAS,SAAW;IACpB,qBAAqB,UAAO;IAG5B,kBAAkB,EAAG,cAAc,CAAS;IAE5C;;;;;OAKG;IACH,kBAAkB,EAAE,yBAAyB,CAA2B;IAExE,OAAO,CAAC,aAAa,CAAa;IAClC;;;uCAGmC;IACnC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,MAAM,CAAiB;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB,CAAI;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,iBAAiB,CAAyB;IAClD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAyB;IAEjD;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB,CAAiC;IAE3D;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB,CAAyB;IAEpD;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB,CAAwB;IAEjD;;;;;OAKG;IACH,OAAO,CAAC,cAAc,CAAmC;IAEzD;;;;;;;;OAQG;IACH,OAAO,CAAC,0BAA0B,CAAyB;IAE3D;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB,CAAyB;IAEtD,YAAY,OAAO,GAAE,mBAAwB,EAM5C;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/build.js
CHANGED
|
@@ -188322,6 +188322,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188322
188322
|
_loweringMatchers = [];
|
|
188323
188323
|
localConstants = [];
|
|
188324
188324
|
staticLoopSourceBoundNames = new Set;
|
|
188325
|
+
loopBoundNames = new Map;
|
|
188325
188326
|
nullableOptionalProps = new Set;
|
|
188326
188327
|
constructor(options = {}) {
|
|
188327
188328
|
super();
|
|
@@ -188338,6 +188339,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188338
188339
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188339
188340
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188340
188341
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188342
|
+
this.loopBoundNames.clear();
|
|
188341
188343
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188342
188344
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188343
188345
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188671,7 +188673,35 @@ ${whenTrue}
|
|
|
188671
188673
|
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188672
188674
|
this.currentLoopKeyDepth = loop.depth;
|
|
188673
188675
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188676
|
+
const loopBound = [];
|
|
188677
|
+
if (loop.objectIteration === "entries") {
|
|
188678
|
+
loopBound.push(loop.index ?? param, param);
|
|
188679
|
+
} else if (loop.objectIteration === "keys" || loop.objectIteration === "values") {
|
|
188680
|
+
loopBound.push(param);
|
|
188681
|
+
} else if (loop.iterationShape === "keys") {
|
|
188682
|
+
loopBound.push("__bf_item", param);
|
|
188683
|
+
} else if (supportableDestructure) {
|
|
188684
|
+
loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
|
|
188685
|
+
if (loop.index)
|
|
188686
|
+
loopBound.push(loop.index);
|
|
188687
|
+
} else {
|
|
188688
|
+
loopBound.push(param);
|
|
188689
|
+
if (loop.index)
|
|
188690
|
+
loopBound.push(loop.index);
|
|
188691
|
+
}
|
|
188692
|
+
for (const d of loop.preamble?.declarations ?? [])
|
|
188693
|
+
loopBound.push(d.name);
|
|
188694
|
+
for (const n of loopBound) {
|
|
188695
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
|
|
188696
|
+
}
|
|
188674
188697
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188698
|
+
for (const n of loopBound) {
|
|
188699
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1;
|
|
188700
|
+
if (c <= 0)
|
|
188701
|
+
this.loopBoundNames.delete(n);
|
|
188702
|
+
else
|
|
188703
|
+
this.loopBoundNames.set(n, c);
|
|
188704
|
+
}
|
|
188675
188705
|
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188676
188706
|
this.inLoop = prevInLoop;
|
|
188677
188707
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
@@ -188850,7 +188880,7 @@ ${children}`;
|
|
|
188850
188880
|
}
|
|
188851
188881
|
const bareId = value.expr.trim();
|
|
188852
188882
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
188853
|
-
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
188883
|
+
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
|
|
188854
188884
|
const jinja2 = this.convertExpressionToJinja(value.expr);
|
|
188855
188885
|
const body = this.shouldBoolStr(value.expr, name) ? `${name}="{{ bf.bool_str(${jinja2}) }}"` : `${name}="{{ bf.string(${jinja2}) }}"`;
|
|
188856
188886
|
return `
|
|
@@ -189137,8 +189167,13 @@ Options:
|
|
|
189137
189167
|
}
|
|
189138
189168
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
189139
189169
|
return false;
|
|
189170
|
+
if (this.isLoopBoundName(bare))
|
|
189171
|
+
return false;
|
|
189140
189172
|
return this.booleanTypedProps.has(bare);
|
|
189141
189173
|
}
|
|
189174
|
+
isLoopBoundName(name) {
|
|
189175
|
+
return this.loopBoundNames.has(name);
|
|
189176
|
+
}
|
|
189142
189177
|
shouldBoolStr(expr, name) {
|
|
189143
189178
|
if (isExplicitStringCall(expr))
|
|
189144
189179
|
return false;
|
package/dist/index.js
CHANGED
|
@@ -188322,6 +188322,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188322
188322
|
_loweringMatchers = [];
|
|
188323
188323
|
localConstants = [];
|
|
188324
188324
|
staticLoopSourceBoundNames = new Set;
|
|
188325
|
+
loopBoundNames = new Map;
|
|
188325
188326
|
nullableOptionalProps = new Set;
|
|
188326
188327
|
constructor(options = {}) {
|
|
188327
188328
|
super();
|
|
@@ -188338,6 +188339,7 @@ class JinjaAdapter extends BaseAdapter {
|
|
|
188338
188339
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188339
188340
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188340
188341
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188342
|
+
this.loopBoundNames.clear();
|
|
188341
188343
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188342
188344
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188343
188345
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188671,7 +188673,35 @@ ${whenTrue}
|
|
|
188671
188673
|
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188672
188674
|
this.currentLoopKeyDepth = loop.depth;
|
|
188673
188675
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188676
|
+
const loopBound = [];
|
|
188677
|
+
if (loop.objectIteration === "entries") {
|
|
188678
|
+
loopBound.push(loop.index ?? param, param);
|
|
188679
|
+
} else if (loop.objectIteration === "keys" || loop.objectIteration === "values") {
|
|
188680
|
+
loopBound.push(param);
|
|
188681
|
+
} else if (loop.iterationShape === "keys") {
|
|
188682
|
+
loopBound.push("__bf_item", param);
|
|
188683
|
+
} else if (supportableDestructure) {
|
|
188684
|
+
loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
|
|
188685
|
+
if (loop.index)
|
|
188686
|
+
loopBound.push(loop.index);
|
|
188687
|
+
} else {
|
|
188688
|
+
loopBound.push(param);
|
|
188689
|
+
if (loop.index)
|
|
188690
|
+
loopBound.push(loop.index);
|
|
188691
|
+
}
|
|
188692
|
+
for (const d of loop.preamble?.declarations ?? [])
|
|
188693
|
+
loopBound.push(d.name);
|
|
188694
|
+
for (const n of loopBound) {
|
|
188695
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
|
|
188696
|
+
}
|
|
188674
188697
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188698
|
+
for (const n of loopBound) {
|
|
188699
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1;
|
|
188700
|
+
if (c <= 0)
|
|
188701
|
+
this.loopBoundNames.delete(n);
|
|
188702
|
+
else
|
|
188703
|
+
this.loopBoundNames.set(n, c);
|
|
188704
|
+
}
|
|
188675
188705
|
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188676
188706
|
this.inLoop = prevInLoop;
|
|
188677
188707
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
@@ -188850,7 +188880,7 @@ ${children}`;
|
|
|
188850
188880
|
}
|
|
188851
188881
|
const bareId = value.expr.trim();
|
|
188852
188882
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
188853
|
-
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
188883
|
+
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
|
|
188854
188884
|
const jinja2 = this.convertExpressionToJinja(value.expr);
|
|
188855
188885
|
const body = this.shouldBoolStr(value.expr, name) ? `${name}="{{ bf.bool_str(${jinja2}) }}"` : `${name}="{{ bf.string(${jinja2}) }}"`;
|
|
188856
188886
|
return `
|
|
@@ -189137,8 +189167,13 @@ Options:
|
|
|
189137
189167
|
}
|
|
189138
189168
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
189139
189169
|
return false;
|
|
189170
|
+
if (this.isLoopBoundName(bare))
|
|
189171
|
+
return false;
|
|
189140
189172
|
return this.booleanTypedProps.has(bare);
|
|
189141
189173
|
}
|
|
189174
|
+
isLoopBoundName(name) {
|
|
189175
|
+
return this.loopBoundNames.has(name);
|
|
189176
|
+
}
|
|
189142
189177
|
shouldBoolStr(expr, name) {
|
|
189143
189178
|
if (isExplicitStringCall(expr))
|
|
189144
189179
|
return false;
|
|
@@ -189228,7 +189263,6 @@ var conformancePins = {
|
|
|
189228
189263
|
var renderDivergences = {
|
|
189229
189264
|
"aliased-destructured-prop": "aliased destructured prop `{ n: count }` loses its rename — template vars, ssr-defaults, and the props bridge all key off the local name, so the prop is always undefined (https://github.com/piconic-ai/barefootjs/issues/2460)",
|
|
189230
189265
|
"composite-row-child-aliased-prop": "same #2460 defect as `aliased-destructured-prop`, inside a keyed `.map()` loop row: the nested child's renamed prop (`{ n: count }`) is always undefined, so both rows render an empty count (https://github.com/piconic-ai/barefootjs/issues/2460)",
|
|
189231
|
-
"loop-param-shadows-bool-prop": 'a .map() param sharing a boolean prop\'s name is routed through the bool lowering in attribute position (renders "true"/"false" instead of the row string) — `collectBooleanTypedProps` lacks the `collectLoopBoundNames` subtraction its sibling `collectStringValueNames` got in #2236 (https://github.com/piconic-ai/barefootjs/issues/2488)',
|
|
189232
189266
|
"loop-param-shadows-spread-const": "a .map() param shadowing an object const is resolved by `emitSpread` against `localConstants` with no loop-shadow check, so every row spreads the OUTER const instead of the row value (https://github.com/piconic-ai/barefootjs/issues/2489)"
|
|
189233
189267
|
};
|
|
189234
189268
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAwB/B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jinja",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.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.30.
|
|
56
|
+
"@barefootjs/shared": "0.30.3"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@barefootjs/jsx": ">=0.2.0"
|
|
@@ -285,6 +285,21 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
285
285
|
*/
|
|
286
286
|
private staticLoopSourceBoundNames: Set<string> = new Set()
|
|
287
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Names currently bound by an enclosing loop body — the block-param
|
|
290
|
+
* locals `renderLoop` introduces (item, index, per-binding destructure
|
|
291
|
+
* fields, `.map()` preamble declarations) — ref-counted so nested loops
|
|
292
|
+
* compose. This is the POSITION-ACCURATE twin of the coarse
|
|
293
|
+
* `staticLoopSourceBoundNames` above: that set is a whole-component
|
|
294
|
+
* union used only to guard static-const inlining (safe to over-suppress
|
|
295
|
+
* there — the fallback is just "don't inline"), whereas the boolean-prop
|
|
296
|
+
* and nullable-optional classification sites need to know whether a name
|
|
297
|
+
* is loop-bound AT THIS POSITION, because for those two the coarse
|
|
298
|
+
* fallback would silently mis-render a genuine prop occurrence outside
|
|
299
|
+
* the loop too (#2488).
|
|
300
|
+
*/
|
|
301
|
+
private loopBoundNames: Map<string, number> = new Map()
|
|
302
|
+
|
|
288
303
|
/**
|
|
289
304
|
* Optional, no-default props that are `None` when the caller omits them.
|
|
290
305
|
* Their bare-reference attribute emission is guarded with a Jinja
|
|
@@ -318,6 +333,7 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
318
333
|
this.booleanTypedProps = collectBooleanTypedProps(ir)
|
|
319
334
|
this.localConstants = ir.metadata.localConstants ?? []
|
|
320
335
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir)
|
|
336
|
+
this.loopBoundNames.clear()
|
|
321
337
|
this.nullableOptionalProps = collectNullableOptionalProps(ir)
|
|
322
338
|
this.stringValueNames = collectStringValueNames(ir)
|
|
323
339
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants)
|
|
@@ -911,7 +927,39 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
911
927
|
const preambleLines = (loop.preamble?.declarations ?? []).map(
|
|
912
928
|
d => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`,
|
|
913
929
|
)
|
|
930
|
+
// Names this loop binds in body scope, for the position-accurate
|
|
931
|
+
// `loopBoundNames` guard (#2488) — mirrors the ERB adapter's `loopBound`
|
|
932
|
+
// derivation, adapted to what THIS renderLoop actually binds: the
|
|
933
|
+
// for-header target(s) (`loopVar` / `objectIteration` key+value /
|
|
934
|
+
// `iterationShape === 'keys'`'s `param`), each `indexLocalLines` name
|
|
935
|
+
// (explicit index, or a destructure binding), and the `.map()`
|
|
936
|
+
// preamble's declared locals. Ref-counted so nested loops compose.
|
|
937
|
+
const loopBound: string[] = []
|
|
938
|
+
if (loop.objectIteration === 'entries') {
|
|
939
|
+
loopBound.push(loop.index ?? param, param)
|
|
940
|
+
} else if (loop.objectIteration === 'keys' || loop.objectIteration === 'values') {
|
|
941
|
+
loopBound.push(param)
|
|
942
|
+
} else if (loop.iterationShape === 'keys') {
|
|
943
|
+
// The header still binds the throwaway loop var; `param` is only the
|
|
944
|
+
// index alias set beneath it (#2488).
|
|
945
|
+
loopBound.push('__bf_item', param)
|
|
946
|
+
} else if (supportableDestructure) {
|
|
947
|
+
loopBound.push('__bf_item', ...(loop.paramBindings ?? []).map(b => b.name))
|
|
948
|
+
if (loop.index) loopBound.push(loop.index)
|
|
949
|
+
} else {
|
|
950
|
+
loopBound.push(param)
|
|
951
|
+
if (loop.index) loopBound.push(loop.index)
|
|
952
|
+
}
|
|
953
|
+
for (const d of loop.preamble?.declarations ?? []) loopBound.push(d.name)
|
|
954
|
+
for (const n of loopBound) {
|
|
955
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1)
|
|
956
|
+
}
|
|
914
957
|
const childrenUnderLoop = this.renderChildren(loop.children)
|
|
958
|
+
for (const n of loopBound) {
|
|
959
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1
|
|
960
|
+
if (c <= 0) this.loopBoundNames.delete(n)
|
|
961
|
+
else this.loopBoundNames.set(n, c)
|
|
962
|
+
}
|
|
915
963
|
this.currentLoopKeyDepth = prevLoopKeyDepth
|
|
916
964
|
this.inLoop = prevInLoop
|
|
917
965
|
void renderedChildren
|
|
@@ -1303,7 +1351,11 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1303
1351
|
!isBooleanAttr(name) &&
|
|
1304
1352
|
!value.presenceOrUndefined &&
|
|
1305
1353
|
/^[A-Za-z_$][\w$]*$/.test(normalizedBareId) &&
|
|
1306
|
-
this.nullableOptionalProps.has(normalizedBareId)
|
|
1354
|
+
this.nullableOptionalProps.has(normalizedBareId) &&
|
|
1355
|
+
// Inside a `.map()` callback, a param that shadows a nullable
|
|
1356
|
+
// optional prop's name is the row binding, not the prop — skip the
|
|
1357
|
+
// spurious "is defined and is not none" guard (#2488).
|
|
1358
|
+
!this.isLoopBoundName(normalizedBareId)
|
|
1307
1359
|
) {
|
|
1308
1360
|
const jinja = this.convertExpressionToJinja(value.expr)
|
|
1309
1361
|
const body = this.shouldBoolStr(value.expr, name)
|
|
@@ -1806,9 +1858,18 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1806
1858
|
bare = bare.slice(this.propsObjectName.length + 1)
|
|
1807
1859
|
}
|
|
1808
1860
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare)) return false
|
|
1861
|
+
// Inside a `.map()` callback, a param that shares a boolean prop's name
|
|
1862
|
+
// is the ROW binding, not the prop — route it through plain string
|
|
1863
|
+
// emission instead of `bf.bool_str` (#2488).
|
|
1864
|
+
if (this.isLoopBoundName(bare)) return false
|
|
1809
1865
|
return this.booleanTypedProps.has(bare)
|
|
1810
1866
|
}
|
|
1811
1867
|
|
|
1868
|
+
/** Position-accurate loop-bound-name check — see `loopBoundNames`'s docstring. */
|
|
1869
|
+
private isLoopBoundName(name: string): boolean {
|
|
1870
|
+
return this.loopBoundNames.has(name)
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1812
1873
|
/**
|
|
1813
1874
|
* Whether an attribute-value expression should route through
|
|
1814
1875
|
* `bf.bool_str` (vs. plain `bf.string`) at its interpolation site.
|
|
@@ -36,8 +36,6 @@ export const renderDivergences: RenderDivergences = {
|
|
|
36
36
|
// #2482 audit follow-ups: loop-scope holes in per-adapter name
|
|
37
37
|
// classification. Graduate by applying the loop-bound-name guards
|
|
38
38
|
// described in each issue and deleting the line.
|
|
39
|
-
'loop-param-shadows-bool-prop':
|
|
40
|
-
'a .map() param sharing a boolean prop\'s name is routed through the bool lowering in attribute position (renders "true"/"false" instead of the row string) — `collectBooleanTypedProps` lacks the `collectLoopBoundNames` subtraction its sibling `collectStringValueNames` got in #2236 (https://github.com/piconic-ai/barefootjs/issues/2488)',
|
|
41
39
|
'loop-param-shadows-spread-const':
|
|
42
40
|
'a .map() param shadowing an object const is resolved by `emitSpread` against `localConstants` with no loop-shadow check, so every row spreads the OUTER const instead of the row value (https://github.com/piconic-ai/barefootjs/issues/2489)',
|
|
43
41
|
}
|