@barefootjs/rust 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 +38 -1
- package/dist/adapter/minijinja-adapter.d.ts +16 -0
- package/dist/adapter/minijinja-adapter.d.ts.map +1 -1
- package/dist/build.js +38 -1
- package/dist/index.js +38 -2
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/adapter/minijinja-adapter.ts +65 -1
- package/src/render-divergences.ts +0 -2
package/dist/adapter/index.js
CHANGED
|
@@ -188317,6 +188317,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188317
188317
|
_loweringMatchers = [];
|
|
188318
188318
|
localConstants = [];
|
|
188319
188319
|
staticLoopSourceBoundNames = new Set;
|
|
188320
|
+
loopBoundNames = new Map;
|
|
188320
188321
|
nullableOptionalProps = new Set;
|
|
188321
188322
|
constructor(options = {}) {
|
|
188322
188323
|
super();
|
|
@@ -188333,6 +188334,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188333
188334
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188334
188335
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188335
188336
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188337
|
+
this.loopBoundNames.clear();
|
|
188336
188338
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188337
188339
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188338
188340
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188665,7 +188667,37 @@ ${whenTrue}
|
|
|
188665
188667
|
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188666
188668
|
this.currentLoopKeyDepth = loop.depth;
|
|
188667
188669
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188670
|
+
const loopBound = [];
|
|
188671
|
+
if (loop.objectIteration === "entries") {
|
|
188672
|
+
loopBound.push(loop.index ?? param, param);
|
|
188673
|
+
} else if (loop.objectIteration === "keys") {
|
|
188674
|
+
loopBound.push(param, "__bf_v");
|
|
188675
|
+
} else if (loop.objectIteration === "values") {
|
|
188676
|
+
loopBound.push("__bf_k", param);
|
|
188677
|
+
} else if (loop.iterationShape === "keys") {
|
|
188678
|
+
loopBound.push("__bf_item", param);
|
|
188679
|
+
} else if (supportableDestructure) {
|
|
188680
|
+
loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
|
|
188681
|
+
if (loop.index)
|
|
188682
|
+
loopBound.push(loop.index);
|
|
188683
|
+
} else {
|
|
188684
|
+
loopBound.push(param);
|
|
188685
|
+
if (loop.index)
|
|
188686
|
+
loopBound.push(loop.index);
|
|
188687
|
+
}
|
|
188688
|
+
for (const d of loop.preamble?.declarations ?? [])
|
|
188689
|
+
loopBound.push(d.name);
|
|
188690
|
+
for (const n of loopBound) {
|
|
188691
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
|
|
188692
|
+
}
|
|
188668
188693
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188694
|
+
for (const n of loopBound) {
|
|
188695
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1;
|
|
188696
|
+
if (c <= 0)
|
|
188697
|
+
this.loopBoundNames.delete(n);
|
|
188698
|
+
else
|
|
188699
|
+
this.loopBoundNames.set(n, c);
|
|
188700
|
+
}
|
|
188669
188701
|
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188670
188702
|
this.inLoop = prevInLoop;
|
|
188671
188703
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
@@ -188844,7 +188876,7 @@ ${children}`;
|
|
|
188844
188876
|
}
|
|
188845
188877
|
const bareId = value.expr.trim();
|
|
188846
188878
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
188847
|
-
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
188879
|
+
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
|
|
188848
188880
|
const jinja2 = this.convertExpressionToJinja(value.expr);
|
|
188849
188881
|
const body = this.shouldBoolStr(value.expr, name) ? `${name}="{{ bf.bool_str(${jinja2}) }}"` : `${name}="{{ bf.string(${jinja2}) }}"`;
|
|
188850
188882
|
return `
|
|
@@ -189131,8 +189163,13 @@ Options:
|
|
|
189131
189163
|
}
|
|
189132
189164
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
189133
189165
|
return false;
|
|
189166
|
+
if (this.isLoopBoundName(bare))
|
|
189167
|
+
return false;
|
|
189134
189168
|
return this.booleanTypedProps.has(bare);
|
|
189135
189169
|
}
|
|
189170
|
+
isLoopBoundName(name) {
|
|
189171
|
+
return this.loopBoundNames.has(name);
|
|
189172
|
+
}
|
|
189136
189173
|
shouldBoolStr(expr, name) {
|
|
189137
189174
|
if (isExplicitStringCall(expr))
|
|
189138
189175
|
return false;
|
|
@@ -203,6 +203,20 @@ export declare class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitt
|
|
|
203
203
|
* `collectLoopBoundNames` use in `collectStringValueNames`.
|
|
204
204
|
*/
|
|
205
205
|
private staticLoopSourceBoundNames;
|
|
206
|
+
/**
|
|
207
|
+
* Names currently bound by an enclosing loop body — the block-param
|
|
208
|
+
* locals `renderLoop` introduces (item, index, per-binding destructure
|
|
209
|
+
* fields, `.map()` preamble declarations) — ref-counted so nested loops
|
|
210
|
+
* compose. This is the POSITION-ACCURATE twin of the coarse
|
|
211
|
+
* `staticLoopSourceBoundNames` above: that set is a whole-component
|
|
212
|
+
* union used only to guard static-const inlining (safe to over-suppress
|
|
213
|
+
* there — the fallback is just "don't inline"), whereas the boolean-prop
|
|
214
|
+
* and nullable-optional classification sites need to know whether a name
|
|
215
|
+
* is loop-bound AT THIS POSITION, because for those two the coarse
|
|
216
|
+
* fallback would silently mis-render a genuine prop occurrence outside
|
|
217
|
+
* the loop too (#2488).
|
|
218
|
+
*/
|
|
219
|
+
private loopBoundNames;
|
|
206
220
|
/**
|
|
207
221
|
* Optional, no-default props that are `None` when the caller omits them.
|
|
208
222
|
* Their bare-reference attribute emission is guarded with a Jinja
|
|
@@ -417,6 +431,8 @@ export declare class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitt
|
|
|
417
431
|
consequent: string;
|
|
418
432
|
} | null;
|
|
419
433
|
isBooleanTypedPropRef(expr: string): boolean;
|
|
434
|
+
/** Position-accurate loop-bound-name check — see `loopBoundNames`'s docstring. */
|
|
435
|
+
private isLoopBoundName;
|
|
420
436
|
/**
|
|
421
437
|
* Whether an attribute-value expression should route through
|
|
422
438
|
* `bf.bool_str` (vs. plain `bf.string`) at its interpolation site.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;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;AA6BpD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AA8B7D,qBAAa,gBAAiB,SAAQ,WAAY,YAAW,aAAa,CAAC,cAAc,CAAC;IACxF,IAAI,SAAc;IAClB,SAAS,SAAQ;IACjB,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,CAAmC;IAClD,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,uBAA4B,EAMhD;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiHG;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;AA6BpD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AA8B7D,qBAAa,gBAAiB,SAAQ,WAAY,YAAW,aAAa,CAAC,cAAc,CAAC;IACxF,IAAI,SAAc;IAClB,SAAS,SAAQ;IACjB,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,CAAmC;IAClD,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;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,cAAc,CAAiC;IAEvD;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB,CAAyB;IAEtD,YAAY,OAAO,GAAE,uBAA4B,EAMhD;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,CA8EzE;IAMD,OAAO,CAAC,2BAA2B;IAyBnC;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/B;IAMD,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAE5F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7B;IAED,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEpG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEtF;IAED,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEhG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAE9F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAEpG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAe9F;IAED,uEAAuE;IACvE,OAAO,CAAC,kBAAkB;IAmB1B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,0BAA0B;IAYlC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,MAAM,CAExF;IAMD,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAqCxC;IAED;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IA2BhC,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA6B3C;IAMD,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAuC7C;IAED,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAcnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmT/B;IAMD;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAoCpC;IAED;;;;;;;;;;OAUG;IACH,OAAO,CAAC,2BAA2B;IAUnC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,4BAA4B;IAiBpC,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CA8FzC;IAED,OAAO,CAAC,sBAAsB,CAAI;IAElC;+DAC2D;IAC3D,OAAO,CAAC,kBAAkB,CAAI;IAE9B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAYT,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAQ1C;IAMD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CA8JlC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,gBAAgB;IAoCxB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAIjD;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAMD;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAuB7B,OAAO,CAAC,kCAAkC;IAoC1C;;;;;OAKG;IACH,OAAO,CAAC,iCAAiC;IAmBzC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAuBvC;;;;;;;OAOG;IACH,OAAO,KAAK,OAAO,GASlB;IAED;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GASpB;IAED,sEAAsE;IACtE,OAAO,KAAK,OAAO,GAKlB;IAED,OAAO,CAAC,wBAAwB;IAyEhC;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAK/B;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAI/B;;gFAE4E;IAC5E,OAAO,CAAC,kBAAkB;IAI1B;;;;OAIG;IACH,8BAA8B,CAC5B,IAAI,EAAE,MAAM,GACX;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAgBlD;IAED,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAW3C;IAED,kFAAkF;IAClF,OAAO,CAAC,eAAe;IAIvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAKrB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,2BAA2B;IASnC,OAAO,CAAC,yBAAyB;IAUjC,OAAO,CAAC,gBAAgB;IAcxB,iFAAiF;IACjF,OAAO,CAAC,4BAA4B;CAGrC;AAED,eAAO,MAAM,gBAAgB,kBAAyB,CAAA"}
|
package/dist/build.js
CHANGED
|
@@ -188317,6 +188317,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188317
188317
|
_loweringMatchers = [];
|
|
188318
188318
|
localConstants = [];
|
|
188319
188319
|
staticLoopSourceBoundNames = new Set;
|
|
188320
|
+
loopBoundNames = new Map;
|
|
188320
188321
|
nullableOptionalProps = new Set;
|
|
188321
188322
|
constructor(options = {}) {
|
|
188322
188323
|
super();
|
|
@@ -188333,6 +188334,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188333
188334
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188334
188335
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188335
188336
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188337
|
+
this.loopBoundNames.clear();
|
|
188336
188338
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188337
188339
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188338
188340
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188665,7 +188667,37 @@ ${whenTrue}
|
|
|
188665
188667
|
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188666
188668
|
this.currentLoopKeyDepth = loop.depth;
|
|
188667
188669
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188670
|
+
const loopBound = [];
|
|
188671
|
+
if (loop.objectIteration === "entries") {
|
|
188672
|
+
loopBound.push(loop.index ?? param, param);
|
|
188673
|
+
} else if (loop.objectIteration === "keys") {
|
|
188674
|
+
loopBound.push(param, "__bf_v");
|
|
188675
|
+
} else if (loop.objectIteration === "values") {
|
|
188676
|
+
loopBound.push("__bf_k", param);
|
|
188677
|
+
} else if (loop.iterationShape === "keys") {
|
|
188678
|
+
loopBound.push("__bf_item", param);
|
|
188679
|
+
} else if (supportableDestructure) {
|
|
188680
|
+
loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
|
|
188681
|
+
if (loop.index)
|
|
188682
|
+
loopBound.push(loop.index);
|
|
188683
|
+
} else {
|
|
188684
|
+
loopBound.push(param);
|
|
188685
|
+
if (loop.index)
|
|
188686
|
+
loopBound.push(loop.index);
|
|
188687
|
+
}
|
|
188688
|
+
for (const d of loop.preamble?.declarations ?? [])
|
|
188689
|
+
loopBound.push(d.name);
|
|
188690
|
+
for (const n of loopBound) {
|
|
188691
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
|
|
188692
|
+
}
|
|
188668
188693
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188694
|
+
for (const n of loopBound) {
|
|
188695
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1;
|
|
188696
|
+
if (c <= 0)
|
|
188697
|
+
this.loopBoundNames.delete(n);
|
|
188698
|
+
else
|
|
188699
|
+
this.loopBoundNames.set(n, c);
|
|
188700
|
+
}
|
|
188669
188701
|
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188670
188702
|
this.inLoop = prevInLoop;
|
|
188671
188703
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
@@ -188844,7 +188876,7 @@ ${children}`;
|
|
|
188844
188876
|
}
|
|
188845
188877
|
const bareId = value.expr.trim();
|
|
188846
188878
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
188847
|
-
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
188879
|
+
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
|
|
188848
188880
|
const jinja2 = this.convertExpressionToJinja(value.expr);
|
|
188849
188881
|
const body = this.shouldBoolStr(value.expr, name) ? `${name}="{{ bf.bool_str(${jinja2}) }}"` : `${name}="{{ bf.string(${jinja2}) }}"`;
|
|
188850
188882
|
return `
|
|
@@ -189131,8 +189163,13 @@ Options:
|
|
|
189131
189163
|
}
|
|
189132
189164
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
189133
189165
|
return false;
|
|
189166
|
+
if (this.isLoopBoundName(bare))
|
|
189167
|
+
return false;
|
|
189134
189168
|
return this.booleanTypedProps.has(bare);
|
|
189135
189169
|
}
|
|
189170
|
+
isLoopBoundName(name) {
|
|
189171
|
+
return this.loopBoundNames.has(name);
|
|
189172
|
+
}
|
|
189136
189173
|
shouldBoolStr(expr, name) {
|
|
189137
189174
|
if (isExplicitStringCall(expr))
|
|
189138
189175
|
return false;
|
package/dist/index.js
CHANGED
|
@@ -188317,6 +188317,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188317
188317
|
_loweringMatchers = [];
|
|
188318
188318
|
localConstants = [];
|
|
188319
188319
|
staticLoopSourceBoundNames = new Set;
|
|
188320
|
+
loopBoundNames = new Map;
|
|
188320
188321
|
nullableOptionalProps = new Set;
|
|
188321
188322
|
constructor(options = {}) {
|
|
188322
188323
|
super();
|
|
@@ -188333,6 +188334,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188333
188334
|
this.booleanTypedProps = collectBooleanTypedProps(ir);
|
|
188334
188335
|
this.localConstants = ir.metadata.localConstants ?? [];
|
|
188335
188336
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir);
|
|
188337
|
+
this.loopBoundNames.clear();
|
|
188336
188338
|
this.nullableOptionalProps = collectNullableOptionalProps(ir);
|
|
188337
188339
|
this.stringValueNames = collectStringValueNames(ir);
|
|
188338
188340
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
|
|
@@ -188665,7 +188667,37 @@ ${whenTrue}
|
|
|
188665
188667
|
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188666
188668
|
this.currentLoopKeyDepth = loop.depth;
|
|
188667
188669
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188670
|
+
const loopBound = [];
|
|
188671
|
+
if (loop.objectIteration === "entries") {
|
|
188672
|
+
loopBound.push(loop.index ?? param, param);
|
|
188673
|
+
} else if (loop.objectIteration === "keys") {
|
|
188674
|
+
loopBound.push(param, "__bf_v");
|
|
188675
|
+
} else if (loop.objectIteration === "values") {
|
|
188676
|
+
loopBound.push("__bf_k", param);
|
|
188677
|
+
} else if (loop.iterationShape === "keys") {
|
|
188678
|
+
loopBound.push("__bf_item", param);
|
|
188679
|
+
} else if (supportableDestructure) {
|
|
188680
|
+
loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
|
|
188681
|
+
if (loop.index)
|
|
188682
|
+
loopBound.push(loop.index);
|
|
188683
|
+
} else {
|
|
188684
|
+
loopBound.push(param);
|
|
188685
|
+
if (loop.index)
|
|
188686
|
+
loopBound.push(loop.index);
|
|
188687
|
+
}
|
|
188688
|
+
for (const d of loop.preamble?.declarations ?? [])
|
|
188689
|
+
loopBound.push(d.name);
|
|
188690
|
+
for (const n of loopBound) {
|
|
188691
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
|
|
188692
|
+
}
|
|
188668
188693
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188694
|
+
for (const n of loopBound) {
|
|
188695
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1;
|
|
188696
|
+
if (c <= 0)
|
|
188697
|
+
this.loopBoundNames.delete(n);
|
|
188698
|
+
else
|
|
188699
|
+
this.loopBoundNames.set(n, c);
|
|
188700
|
+
}
|
|
188669
188701
|
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188670
188702
|
this.inLoop = prevInLoop;
|
|
188671
188703
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
@@ -188844,7 +188876,7 @@ ${children}`;
|
|
|
188844
188876
|
}
|
|
188845
188877
|
const bareId = value.expr.trim();
|
|
188846
188878
|
const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
|
|
188847
|
-
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
|
|
188879
|
+
if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
|
|
188848
188880
|
const jinja2 = this.convertExpressionToJinja(value.expr);
|
|
188849
188881
|
const body = this.shouldBoolStr(value.expr, name) ? `${name}="{{ bf.bool_str(${jinja2}) }}"` : `${name}="{{ bf.string(${jinja2}) }}"`;
|
|
188850
188882
|
return `
|
|
@@ -189131,8 +189163,13 @@ Options:
|
|
|
189131
189163
|
}
|
|
189132
189164
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare))
|
|
189133
189165
|
return false;
|
|
189166
|
+
if (this.isLoopBoundName(bare))
|
|
189167
|
+
return false;
|
|
189134
189168
|
return this.booleanTypedProps.has(bare);
|
|
189135
189169
|
}
|
|
189170
|
+
isLoopBoundName(name) {
|
|
189171
|
+
return this.loopBoundNames.has(name);
|
|
189172
|
+
}
|
|
189136
189173
|
shouldBoolStr(expr, name) {
|
|
189137
189174
|
if (isExplicitStringCall(expr))
|
|
189138
189175
|
return false;
|
|
@@ -189222,7 +189259,6 @@ var conformancePins = {
|
|
|
189222
189259
|
var renderDivergences = {
|
|
189223
189260
|
"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)",
|
|
189224
189261
|
"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)",
|
|
189225
|
-
"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)',
|
|
189226
189262
|
"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)"
|
|
189227
189263
|
};
|
|
189228
189264
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;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;;;;;;;;;;;;;;GAcG;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/rust",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.3",
|
|
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.30.
|
|
57
|
+
"@barefootjs/shared": "0.30.3"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@barefootjs/jsx": ">=0.2.0"
|
|
@@ -333,6 +333,21 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
333
333
|
*/
|
|
334
334
|
private staticLoopSourceBoundNames: Set<string> = new Set()
|
|
335
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Names currently bound by an enclosing loop body — the block-param
|
|
338
|
+
* locals `renderLoop` introduces (item, index, per-binding destructure
|
|
339
|
+
* fields, `.map()` preamble declarations) — ref-counted so nested loops
|
|
340
|
+
* compose. This is the POSITION-ACCURATE twin of the coarse
|
|
341
|
+
* `staticLoopSourceBoundNames` above: that set is a whole-component
|
|
342
|
+
* union used only to guard static-const inlining (safe to over-suppress
|
|
343
|
+
* there — the fallback is just "don't inline"), whereas the boolean-prop
|
|
344
|
+
* and nullable-optional classification sites need to know whether a name
|
|
345
|
+
* is loop-bound AT THIS POSITION, because for those two the coarse
|
|
346
|
+
* fallback would silently mis-render a genuine prop occurrence outside
|
|
347
|
+
* the loop too (#2488).
|
|
348
|
+
*/
|
|
349
|
+
private loopBoundNames: Map<string, number> = new Map()
|
|
350
|
+
|
|
336
351
|
/**
|
|
337
352
|
* Optional, no-default props that are `None` when the caller omits them.
|
|
338
353
|
* Their bare-reference attribute emission is guarded with a Jinja
|
|
@@ -366,6 +381,7 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
366
381
|
this.booleanTypedProps = collectBooleanTypedProps(ir)
|
|
367
382
|
this.localConstants = ir.metadata.localConstants ?? []
|
|
368
383
|
this.staticLoopSourceBoundNames = collectLoopBoundNames(ir)
|
|
384
|
+
this.loopBoundNames.clear()
|
|
369
385
|
this.nullableOptionalProps = collectNullableOptionalProps(ir)
|
|
370
386
|
this.stringValueNames = collectStringValueNames(ir)
|
|
371
387
|
this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants)
|
|
@@ -952,7 +968,42 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
952
968
|
const preambleLines = (loop.preamble?.declarations ?? []).map(
|
|
953
969
|
d => `{% set ${minijinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`,
|
|
954
970
|
)
|
|
971
|
+
// Names this loop binds in body scope, for the position-accurate
|
|
972
|
+
// `loopBoundNames` guard (#2488) — mirrors the ERB adapter's `loopBound`
|
|
973
|
+
// derivation, adapted to what THIS renderLoop actually binds: the
|
|
974
|
+
// for-header target(s) (`loopVar` / `objectIteration` key+value /
|
|
975
|
+
// `iterationShape === 'keys'`'s `param`), each `indexLocalLines` name
|
|
976
|
+
// (explicit index, or a destructure binding), and the `.map()`
|
|
977
|
+
// preamble's declared locals. Ref-counted so nested loops compose.
|
|
978
|
+
const loopBound: string[] = []
|
|
979
|
+
if (loop.objectIteration === 'entries') {
|
|
980
|
+
loopBound.push(loop.index ?? param, param)
|
|
981
|
+
} else if (loop.objectIteration === 'keys') {
|
|
982
|
+
// `|items` binds both slots; the unused one is a throwaway (#2488).
|
|
983
|
+
loopBound.push(param, '__bf_v')
|
|
984
|
+
} else if (loop.objectIteration === 'values') {
|
|
985
|
+
loopBound.push('__bf_k', param)
|
|
986
|
+
} else if (loop.iterationShape === 'keys') {
|
|
987
|
+
// The header still binds the throwaway loop var; `param` is only the
|
|
988
|
+
// index alias set beneath it (#2488).
|
|
989
|
+
loopBound.push('__bf_item', param)
|
|
990
|
+
} else if (supportableDestructure) {
|
|
991
|
+
loopBound.push('__bf_item', ...(loop.paramBindings ?? []).map(b => b.name))
|
|
992
|
+
if (loop.index) loopBound.push(loop.index)
|
|
993
|
+
} else {
|
|
994
|
+
loopBound.push(param)
|
|
995
|
+
if (loop.index) loopBound.push(loop.index)
|
|
996
|
+
}
|
|
997
|
+
for (const d of loop.preamble?.declarations ?? []) loopBound.push(d.name)
|
|
998
|
+
for (const n of loopBound) {
|
|
999
|
+
this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1)
|
|
1000
|
+
}
|
|
955
1001
|
const childrenUnderLoop = this.renderChildren(loop.children)
|
|
1002
|
+
for (const n of loopBound) {
|
|
1003
|
+
const c = (this.loopBoundNames.get(n) ?? 1) - 1
|
|
1004
|
+
if (c <= 0) this.loopBoundNames.delete(n)
|
|
1005
|
+
else this.loopBoundNames.set(n, c)
|
|
1006
|
+
}
|
|
956
1007
|
this.currentLoopKeyDepth = prevLoopKeyDepth
|
|
957
1008
|
this.inLoop = prevInLoop
|
|
958
1009
|
void renderedChildren
|
|
@@ -1352,7 +1403,11 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
1352
1403
|
!isBooleanAttr(name) &&
|
|
1353
1404
|
!value.presenceOrUndefined &&
|
|
1354
1405
|
/^[A-Za-z_$][\w$]*$/.test(normalizedBareId) &&
|
|
1355
|
-
this.nullableOptionalProps.has(normalizedBareId)
|
|
1406
|
+
this.nullableOptionalProps.has(normalizedBareId) &&
|
|
1407
|
+
// Inside a `.map()` callback, a param that shadows a nullable
|
|
1408
|
+
// optional prop's name is the row binding, not the prop — skip the
|
|
1409
|
+
// spurious "is defined and is not none" guard (#2488).
|
|
1410
|
+
!this.isLoopBoundName(normalizedBareId)
|
|
1356
1411
|
) {
|
|
1357
1412
|
const jinja = this.convertExpressionToJinja(value.expr)
|
|
1358
1413
|
const body = this.shouldBoolStr(value.expr, name)
|
|
@@ -1861,9 +1916,18 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
1861
1916
|
bare = bare.slice(this.propsObjectName.length + 1)
|
|
1862
1917
|
}
|
|
1863
1918
|
if (!/^[A-Za-z_$][\w$]*$/.test(bare)) return false
|
|
1919
|
+
// Inside a `.map()` callback, a param that shares a boolean prop's name
|
|
1920
|
+
// is the ROW binding, not the prop — route it through plain string
|
|
1921
|
+
// emission instead of `bf.bool_str` (#2488).
|
|
1922
|
+
if (this.isLoopBoundName(bare)) return false
|
|
1864
1923
|
return this.booleanTypedProps.has(bare)
|
|
1865
1924
|
}
|
|
1866
1925
|
|
|
1926
|
+
/** Position-accurate loop-bound-name check — see `loopBoundNames`'s docstring. */
|
|
1927
|
+
private isLoopBoundName(name: string): boolean {
|
|
1928
|
+
return this.loopBoundNames.has(name)
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1867
1931
|
/**
|
|
1868
1932
|
* Whether an attribute-value expression should route through
|
|
1869
1933
|
* `bf.bool_str` (vs. plain `bf.string`) at its interpolation site.
|
|
@@ -38,8 +38,6 @@ export const renderDivergences: RenderDivergences = {
|
|
|
38
38
|
// #2482 audit follow-ups: loop-scope holes in per-adapter name
|
|
39
39
|
// classification. Graduate by applying the loop-bound-name guards
|
|
40
40
|
// described in each issue and deleting the line.
|
|
41
|
-
'loop-param-shadows-bool-prop':
|
|
42
|
-
'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)',
|
|
43
41
|
'loop-param-shadows-spread-const':
|
|
44
42
|
'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)',
|
|
45
43
|
}
|