@barefootjs/xslate 0.30.2 → 0.30.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -188282,6 +188282,7 @@ class XslateAdapter extends BaseAdapter {
188282
188282
  _loweringMatchers = [];
188283
188283
  localConstants = [];
188284
188284
  staticLoopSourceBoundNames = new Set;
188285
+ loopBoundNames = new Map;
188285
188286
  nullableOptionalProps = new Set;
188286
188287
  constructor(options = {}) {
188287
188288
  super();
@@ -188298,6 +188299,7 @@ class XslateAdapter extends BaseAdapter {
188298
188299
  this.booleanTypedProps = collectBooleanTypedProps(ir);
188299
188300
  this.localConstants = ir.metadata.localConstants ?? [];
188300
188301
  this.staticLoopSourceBoundNames = collectLoopBoundNames2(ir);
188302
+ this.loopBoundNames.clear();
188301
188303
  this.nullableOptionalProps = collectNullableOptionalProps(ir);
188302
188304
  this.stringValueNames = collectStringValueNames(ir);
188303
188305
  this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
@@ -188629,7 +188631,35 @@ ${whenTrue}
188629
188631
  const prevLoopKeyDepth = this.currentLoopKeyDepth;
188630
188632
  this.currentLoopKeyDepth = loop.depth;
188631
188633
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`);
188634
+ const loopBound = [];
188635
+ if (loop.objectIteration === "entries") {
188636
+ loopBound.push("__bf_pair", loop.index ?? param, param);
188637
+ } else if (loop.objectIteration === "keys" || loop.objectIteration === "values") {
188638
+ loopBound.push(param);
188639
+ } else if (loop.iterationShape === "keys") {
188640
+ loopBound.push("__bf_item", param);
188641
+ } else if (supportableDestructure) {
188642
+ loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
188643
+ if (loop.index)
188644
+ loopBound.push(loop.index);
188645
+ } else {
188646
+ loopBound.push(param);
188647
+ if (loop.index)
188648
+ loopBound.push(loop.index);
188649
+ }
188650
+ for (const d of loop.preamble?.declarations ?? [])
188651
+ loopBound.push(d.name);
188652
+ for (const n of loopBound) {
188653
+ this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
188654
+ }
188632
188655
  const childrenUnderLoop = this.renderChildren(loop.children);
188656
+ for (const n of loopBound) {
188657
+ const c = (this.loopBoundNames.get(n) ?? 1) - 1;
188658
+ if (c <= 0)
188659
+ this.loopBoundNames.delete(n);
188660
+ else
188661
+ this.loopBoundNames.set(n, c);
188662
+ }
188633
188663
  this.currentLoopKeyDepth = prevLoopKeyDepth;
188634
188664
  this.inLoop = prevInLoop;
188635
188665
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
@@ -188807,7 +188837,7 @@ ${children}`;
188807
188837
  }
188808
188838
  const bareId = value.expr.trim();
188809
188839
  const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
188810
- if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
188840
+ if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
188811
188841
  const perl2 = this.convertExpressionToKolon(value.expr);
188812
188842
  const body = isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(value.expr) ? `${name}="<: $bf.bool_str(${perl2}) :>"` : `${name}="<: ${perl2} :>"`;
188813
188843
  return `
@@ -189082,8 +189112,13 @@ Options:
189082
189112
  }
189083
189113
  if (!/^[A-Za-z_$][\w$]*$/.test(bare))
189084
189114
  return false;
189115
+ if (this.isLoopBoundName(bare))
189116
+ return false;
189085
189117
  return this.booleanTypedProps.has(bare);
189086
189118
  }
189119
+ isLoopBoundName(name) {
189120
+ return this.loopBoundNames.has(name);
189121
+ }
189087
189122
  _resolveLiteralConst(name) {
189088
189123
  if (this.staticLoopSourceBoundNames.has(name))
189089
189124
  return null;
@@ -114,6 +114,20 @@ export declare class XslateAdapter extends BaseAdapter implements IRNodeEmitter<
114
114
  * `collectLoopBoundNames` use in `collectStringValueNames`.
115
115
  */
116
116
  private staticLoopSourceBoundNames;
117
+ /**
118
+ * Names currently bound by an enclosing loop body — the block-param
119
+ * locals `renderLoop` introduces (item, index, per-binding destructure
120
+ * fields, `.map()` preamble declarations) — ref-counted so nested loops
121
+ * compose. This is the POSITION-ACCURATE twin of the coarse
122
+ * `staticLoopSourceBoundNames` above: that set is a whole-component
123
+ * union used only to guard static-const inlining (safe to over-suppress
124
+ * there — the fallback is just "don't inline"), whereas the boolean-prop
125
+ * and nullable-optional classification sites need to know whether a name
126
+ * is loop-bound AT THIS POSITION, because for those two the coarse
127
+ * fallback would silently mis-render a genuine prop occurrence outside
128
+ * the loop too (#2488).
129
+ */
130
+ private loopBoundNames;
117
131
  /**
118
132
  * Optional, no-default props that are `undef` when the caller omits them.
119
133
  * Their bare-reference attribute emission is guarded with Kolon `defined` so
@@ -326,6 +340,8 @@ export declare class XslateAdapter extends BaseAdapter implements IRNodeEmitter<
326
340
  consequent: string;
327
341
  } | null;
328
342
  isBooleanTypedPropRef(expr: string): boolean;
343
+ /** Position-accurate loop-bound-name check — see `loopBoundNames`'s docstring. */
344
+ private isLoopBoundName;
329
345
  /**
330
346
  * Inline a const (any scope) whose initializer is a pure numeric or
331
347
  * single-quoted string literal (`const totalPages = 5`, #1897
@@ -1 +1 @@
1
- {"version":3,"file":"xslate-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/xslate-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;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,EAG1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,EAgChB,MAAM,iBAAiB,CAAA;AAMxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AA6BrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AA2C1D,qBAAa,aAAc,SAAQ,WAAY,YAAW,aAAa,CAAC,eAAe,CAAC;IACtF,IAAI,SAAW;IACf,SAAS,SAAQ;IACjB,qBAAqB,UAAO;IAG5B,kBAAkB,EAAG,cAAc,CAAS;IAE5C;;;;;OAKG;IACH,kBAAkB,EAAE,yBAAyB,CAA4B;IAEzE,OAAO,CAAC,aAAa,CAAa;IAClC;;;uCAGmC;IACnC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,OAAO,CAAgC;IAC/C,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;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB,CAAyB;IAEjD;;;;;;;OAOG;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;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAyB;IAEtD,YAAY,OAAO,GAAE,oBAAyB,EAM7C;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,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAE9F;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,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAEtG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAExF;IAED,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAElG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAEhG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAEtG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAehG;IAED,uEAAuE;IACvE,OAAO,CAAC,kBAAkB;IAiB1B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,0BAA0B;IAclC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,CAAC,eAAe,CAAC,GAAG,MAAM,CAE1F;IAMD,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAqCxC;IAED;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IA4BhC,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA4B3C;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,CA+Q/B;IAMD;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAmCpC;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,2BAA2B;IAUnC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,4BAA4B;IAiBpC,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CA0FzC;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;IAWT,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAQ1C;IAMD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAsJlC;IAED;;;;;;;;;;OAUG;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;IAwB1C;;;;OAIG;IACH,OAAO,CAAC,iCAAiC;IAmBzC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAuBvC;;;;;;;OAOG;IACH,OAAO,KAAK,OAAO,GAUlB;IAED;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GAQpB;IAED,sEAAsE;IACtE,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,wBAAwB;IAyEhC;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAI/B;oEACgE;IAChE,OAAO,CAAC,kBAAkB;IAI1B;;;;;OAKG;IACH;;;;;OAKG;IACH;;;;;OAKG;IACH;;;;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,CAO3C;IAED;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,2BAA2B;IASnC,OAAO,CAAC,yBAAyB;IASjC,OAAO,CAAC,gBAAgB;IAcxB,iFAAiF;IACjF,OAAO,CAAC,4BAA4B;CAGrC;AAED,eAAO,MAAM,aAAa,eAAsB,CAAA"}
1
+ {"version":3,"file":"xslate-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/xslate-adapter.ts"],"names":[],"mappings":"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"}
package/dist/build.js CHANGED
@@ -188282,6 +188282,7 @@ class XslateAdapter extends BaseAdapter {
188282
188282
  _loweringMatchers = [];
188283
188283
  localConstants = [];
188284
188284
  staticLoopSourceBoundNames = new Set;
188285
+ loopBoundNames = new Map;
188285
188286
  nullableOptionalProps = new Set;
188286
188287
  constructor(options = {}) {
188287
188288
  super();
@@ -188298,6 +188299,7 @@ class XslateAdapter extends BaseAdapter {
188298
188299
  this.booleanTypedProps = collectBooleanTypedProps(ir);
188299
188300
  this.localConstants = ir.metadata.localConstants ?? [];
188300
188301
  this.staticLoopSourceBoundNames = collectLoopBoundNames2(ir);
188302
+ this.loopBoundNames.clear();
188301
188303
  this.nullableOptionalProps = collectNullableOptionalProps(ir);
188302
188304
  this.stringValueNames = collectStringValueNames(ir);
188303
188305
  this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
@@ -188629,7 +188631,35 @@ ${whenTrue}
188629
188631
  const prevLoopKeyDepth = this.currentLoopKeyDepth;
188630
188632
  this.currentLoopKeyDepth = loop.depth;
188631
188633
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`);
188634
+ const loopBound = [];
188635
+ if (loop.objectIteration === "entries") {
188636
+ loopBound.push("__bf_pair", loop.index ?? param, param);
188637
+ } else if (loop.objectIteration === "keys" || loop.objectIteration === "values") {
188638
+ loopBound.push(param);
188639
+ } else if (loop.iterationShape === "keys") {
188640
+ loopBound.push("__bf_item", param);
188641
+ } else if (supportableDestructure) {
188642
+ loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
188643
+ if (loop.index)
188644
+ loopBound.push(loop.index);
188645
+ } else {
188646
+ loopBound.push(param);
188647
+ if (loop.index)
188648
+ loopBound.push(loop.index);
188649
+ }
188650
+ for (const d of loop.preamble?.declarations ?? [])
188651
+ loopBound.push(d.name);
188652
+ for (const n of loopBound) {
188653
+ this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
188654
+ }
188632
188655
  const childrenUnderLoop = this.renderChildren(loop.children);
188656
+ for (const n of loopBound) {
188657
+ const c = (this.loopBoundNames.get(n) ?? 1) - 1;
188658
+ if (c <= 0)
188659
+ this.loopBoundNames.delete(n);
188660
+ else
188661
+ this.loopBoundNames.set(n, c);
188662
+ }
188633
188663
  this.currentLoopKeyDepth = prevLoopKeyDepth;
188634
188664
  this.inLoop = prevInLoop;
188635
188665
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
@@ -188807,7 +188837,7 @@ ${children}`;
188807
188837
  }
188808
188838
  const bareId = value.expr.trim();
188809
188839
  const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
188810
- if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
188840
+ if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
188811
188841
  const perl2 = this.convertExpressionToKolon(value.expr);
188812
188842
  const body = isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(value.expr) ? `${name}="<: $bf.bool_str(${perl2}) :>"` : `${name}="<: ${perl2} :>"`;
188813
188843
  return `
@@ -189082,8 +189112,13 @@ Options:
189082
189112
  }
189083
189113
  if (!/^[A-Za-z_$][\w$]*$/.test(bare))
189084
189114
  return false;
189115
+ if (this.isLoopBoundName(bare))
189116
+ return false;
189085
189117
  return this.booleanTypedProps.has(bare);
189086
189118
  }
189119
+ isLoopBoundName(name) {
189120
+ return this.loopBoundNames.has(name);
189121
+ }
189087
189122
  _resolveLiteralConst(name) {
189088
189123
  if (this.staticLoopSourceBoundNames.has(name))
189089
189124
  return null;
package/dist/index.js CHANGED
@@ -188282,6 +188282,7 @@ class XslateAdapter extends BaseAdapter {
188282
188282
  _loweringMatchers = [];
188283
188283
  localConstants = [];
188284
188284
  staticLoopSourceBoundNames = new Set;
188285
+ loopBoundNames = new Map;
188285
188286
  nullableOptionalProps = new Set;
188286
188287
  constructor(options = {}) {
188287
188288
  super();
@@ -188298,6 +188299,7 @@ class XslateAdapter extends BaseAdapter {
188298
188299
  this.booleanTypedProps = collectBooleanTypedProps(ir);
188299
188300
  this.localConstants = ir.metadata.localConstants ?? [];
188300
188301
  this.staticLoopSourceBoundNames = collectLoopBoundNames2(ir);
188302
+ this.loopBoundNames.clear();
188301
188303
  this.nullableOptionalProps = collectNullableOptionalProps(ir);
188302
188304
  this.stringValueNames = collectStringValueNames(ir);
188303
188305
  this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants);
@@ -188629,7 +188631,35 @@ ${whenTrue}
188629
188631
  const prevLoopKeyDepth = this.currentLoopKeyDepth;
188630
188632
  this.currentLoopKeyDepth = loop.depth;
188631
188633
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`);
188634
+ const loopBound = [];
188635
+ if (loop.objectIteration === "entries") {
188636
+ loopBound.push("__bf_pair", loop.index ?? param, param);
188637
+ } else if (loop.objectIteration === "keys" || loop.objectIteration === "values") {
188638
+ loopBound.push(param);
188639
+ } else if (loop.iterationShape === "keys") {
188640
+ loopBound.push("__bf_item", param);
188641
+ } else if (supportableDestructure) {
188642
+ loopBound.push("__bf_item", ...(loop.paramBindings ?? []).map((b) => b.name));
188643
+ if (loop.index)
188644
+ loopBound.push(loop.index);
188645
+ } else {
188646
+ loopBound.push(param);
188647
+ if (loop.index)
188648
+ loopBound.push(loop.index);
188649
+ }
188650
+ for (const d of loop.preamble?.declarations ?? [])
188651
+ loopBound.push(d.name);
188652
+ for (const n of loopBound) {
188653
+ this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1);
188654
+ }
188632
188655
  const childrenUnderLoop = this.renderChildren(loop.children);
188656
+ for (const n of loopBound) {
188657
+ const c = (this.loopBoundNames.get(n) ?? 1) - 1;
188658
+ if (c <= 0)
188659
+ this.loopBoundNames.delete(n);
188660
+ else
188661
+ this.loopBoundNames.set(n, c);
188662
+ }
188633
188663
  this.currentLoopKeyDepth = prevLoopKeyDepth;
188634
188664
  this.inLoop = prevInLoop;
188635
188665
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
@@ -188807,7 +188837,7 @@ ${children}`;
188807
188837
  }
188808
188838
  const bareId = value.expr.trim();
188809
188839
  const normalizedBareId = this.propsObjectName && bareId.startsWith(`${this.propsObjectName}.`) ? bareId.slice(this.propsObjectName.length + 1) : bareId;
188810
- if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId)) {
188840
+ if (!isBooleanAttr(name) && !value.presenceOrUndefined && /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) && this.nullableOptionalProps.has(normalizedBareId) && !this.isLoopBoundName(normalizedBareId)) {
188811
188841
  const perl2 = this.convertExpressionToKolon(value.expr);
188812
188842
  const body = isBooleanResultExpr(value.expr) || isAriaBooleanAttr(name) || this.isBooleanTypedPropRef(value.expr) ? `${name}="<: $bf.bool_str(${perl2}) :>"` : `${name}="<: ${perl2} :>"`;
188813
188843
  return `
@@ -189082,8 +189112,13 @@ Options:
189082
189112
  }
189083
189113
  if (!/^[A-Za-z_$][\w$]*$/.test(bare))
189084
189114
  return false;
189115
+ if (this.isLoopBoundName(bare))
189116
+ return false;
189085
189117
  return this.booleanTypedProps.has(bare);
189086
189118
  }
189119
+ isLoopBoundName(name) {
189120
+ return this.loopBoundNames.has(name);
189121
+ }
189087
189122
  _resolveLiteralConst(name) {
189088
189123
  if (this.staticLoopSourceBoundNames.has(name))
189089
189124
  return null;
@@ -189168,7 +189203,6 @@ var conformancePins = {
189168
189203
  var renderDivergences = {
189169
189204
  "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)",
189170
189205
  "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)",
189171
- "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)',
189172
189206
  "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)"
189173
189207
  };
189174
189208
  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,iBA0B/B,CAAA"}
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"}
@@ -1,5 +1,5 @@
1
1
  package BarefootJS::Backend::Xslate;
2
- our $VERSION = "0.30.0";
2
+ our $VERSION = "0.30.2";
3
3
  use strict;
4
4
  use warnings;
5
5
  use utf8;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/xslate",
3
- "version": "0.30.2",
3
+ "version": "0.30.4",
4
4
  "description": "Text::Xslate (Kolon) adapter for BarefootJS — compiles IR to .tx templates and ships the Xslate rendering backend; runs under any PSGI/Plack app",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,14 +55,14 @@
55
55
  "directory": "packages/adapter-xslate"
56
56
  },
57
57
  "dependencies": {
58
- "@barefootjs/shared": "0.30.2"
58
+ "@barefootjs/shared": "0.30.4"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@barefootjs/jsx": ">=0.2.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@barefootjs/adapter-tests": "0.1.0",
65
- "@barefootjs/jsx": "0.30.2",
65
+ "@barefootjs/jsx": "0.30.4",
66
66
  "typescript": "^5.0.0"
67
67
  }
68
68
  }
@@ -259,6 +259,21 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
259
259
  */
260
260
  private staticLoopSourceBoundNames: Set<string> = new Set()
261
261
 
262
+ /**
263
+ * Names currently bound by an enclosing loop body — the block-param
264
+ * locals `renderLoop` introduces (item, index, per-binding destructure
265
+ * fields, `.map()` preamble declarations) — ref-counted so nested loops
266
+ * compose. This is the POSITION-ACCURATE twin of the coarse
267
+ * `staticLoopSourceBoundNames` above: that set is a whole-component
268
+ * union used only to guard static-const inlining (safe to over-suppress
269
+ * there — the fallback is just "don't inline"), whereas the boolean-prop
270
+ * and nullable-optional classification sites need to know whether a name
271
+ * is loop-bound AT THIS POSITION, because for those two the coarse
272
+ * fallback would silently mis-render a genuine prop occurrence outside
273
+ * the loop too (#2488).
274
+ */
275
+ private loopBoundNames: Map<string, number> = new Map()
276
+
262
277
  /**
263
278
  * Optional, no-default props that are `undef` when the caller omits them.
264
279
  * Their bare-reference attribute emission is guarded with Kolon `defined` so
@@ -292,6 +307,7 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
292
307
  this.booleanTypedProps = collectBooleanTypedProps(ir)
293
308
  this.localConstants = ir.metadata.localConstants ?? []
294
309
  this.staticLoopSourceBoundNames = collectLoopBoundNames(ir)
310
+ this.loopBoundNames.clear()
295
311
  this.nullableOptionalProps = collectNullableOptionalProps(ir)
296
312
  this.stringValueNames = collectStringValueNames(ir)
297
313
  this.moduleStringConsts = collectModuleStringConsts(ir.metadata.localConstants)
@@ -889,7 +905,40 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
889
905
  const preambleLines = (loop.preamble?.declarations ?? []).map(
890
906
  d => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`,
891
907
  )
908
+ // Names this loop binds in body scope, for the position-accurate
909
+ // `loopBoundNames` guard (#2488) — mirrors the ERB adapter's `loopBound`
910
+ // derivation, adapted to what THIS renderLoop actually binds: the
911
+ // for-header target(s) (`loopVar` / `objectIteration` key+value /
912
+ // `iterationShape === 'keys'`'s `param`), each `indexLocalLines` name
913
+ // (explicit index, or a destructure binding), and the `.map()`
914
+ // preamble's declared locals. Ref-counted so nested loops compose.
915
+ const loopBound: string[] = []
916
+ if (loop.objectIteration === 'entries') {
917
+ // `.kv()` binds the pair var the key/value locals are derived from (#2488).
918
+ loopBound.push('__bf_pair', loop.index ?? param, param)
919
+ } else if (loop.objectIteration === 'keys' || loop.objectIteration === 'values') {
920
+ loopBound.push(param)
921
+ } else if (loop.iterationShape === 'keys') {
922
+ // The header still binds the throwaway loop var; `param` is only the
923
+ // index alias derived from it beneath (#2488).
924
+ loopBound.push('__bf_item', param)
925
+ } else if (supportableDestructure) {
926
+ loopBound.push('__bf_item', ...(loop.paramBindings ?? []).map(b => b.name))
927
+ if (loop.index) loopBound.push(loop.index)
928
+ } else {
929
+ loopBound.push(param)
930
+ if (loop.index) loopBound.push(loop.index)
931
+ }
932
+ for (const d of loop.preamble?.declarations ?? []) loopBound.push(d.name)
933
+ for (const n of loopBound) {
934
+ this.loopBoundNames.set(n, (this.loopBoundNames.get(n) ?? 0) + 1)
935
+ }
892
936
  const childrenUnderLoop = this.renderChildren(loop.children)
937
+ for (const n of loopBound) {
938
+ const c = (this.loopBoundNames.get(n) ?? 1) - 1
939
+ if (c <= 0) this.loopBoundNames.delete(n)
940
+ else this.loopBoundNames.set(n, c)
941
+ }
893
942
  this.currentLoopKeyDepth = prevLoopKeyDepth
894
943
  this.inLoop = prevInLoop
895
944
  void renderedChildren
@@ -1269,7 +1318,11 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1269
1318
  !isBooleanAttr(name) &&
1270
1319
  !value.presenceOrUndefined &&
1271
1320
  /^[A-Za-z_$][\w$]*$/.test(normalizedBareId) &&
1272
- this.nullableOptionalProps.has(normalizedBareId)
1321
+ this.nullableOptionalProps.has(normalizedBareId) &&
1322
+ // Inside a `.map()` callback, a param that shadows a nullable
1323
+ // optional prop's name is the row binding, not the prop — skip the
1324
+ // spurious `defined` guard (#2488).
1325
+ !this.isLoopBoundName(normalizedBareId)
1273
1326
  ) {
1274
1327
  const perl = this.convertExpressionToKolon(value.expr)
1275
1328
  const body =
@@ -1750,9 +1803,18 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1750
1803
  bare = bare.slice(this.propsObjectName.length + 1)
1751
1804
  }
1752
1805
  if (!/^[A-Za-z_$][\w$]*$/.test(bare)) return false
1806
+ // Inside a `.map()` callback, a param that shares a boolean prop's name
1807
+ // is the ROW binding, not the prop — route it through plain string
1808
+ // emission instead of `$bf.bool_str` (#2488).
1809
+ if (this.isLoopBoundName(bare)) return false
1753
1810
  return this.booleanTypedProps.has(bare)
1754
1811
  }
1755
1812
 
1813
+ /** Position-accurate loop-bound-name check — see `loopBoundNames`'s docstring. */
1814
+ private isLoopBoundName(name: string): boolean {
1815
+ return this.loopBoundNames.has(name)
1816
+ }
1817
+
1756
1818
  /**
1757
1819
  * Inline a const (any scope) whose initializer is a pure numeric or
1758
1820
  * single-quoted string literal (`const totalPages = 5`, #1897
@@ -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
  }