@barefootjs/xslate 0.30.0 → 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/xslate-adapter.d.ts +16 -0
- package/dist/adapter/xslate-adapter.d.ts.map +1 -1
- package/dist/build.js +36 -1
- package/dist/index.js +38 -2
- package/dist/render-divergences.d.ts.map +1 -1
- package/lib/BarefootJS/Backend/Xslate.pm +1 -1
- package/package.json +3 -3
- package/src/adapter/xslate-adapter.ts +63 -1
- package/src/render-divergences.ts +6 -0
package/dist/adapter/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;
|
|
@@ -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,
|
|
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;
|
|
@@ -189167,7 +189202,8 @@ var conformancePins = {
|
|
|
189167
189202
|
// src/render-divergences.ts
|
|
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
|
-
"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)"
|
|
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)",
|
|
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)"
|
|
189171
189207
|
};
|
|
189172
189208
|
export {
|
|
189173
189209
|
xslateAdapter,
|
|
@@ -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/xslate",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.3",
|
|
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.
|
|
58
|
+
"@barefootjs/shared": "0.30.3"
|
|
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.
|
|
65
|
+
"@barefootjs/jsx": "0.30.2",
|
|
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
|
|
@@ -32,4 +32,10 @@ export const renderDivergences: RenderDivergences = {
|
|
|
32
32
|
'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)',
|
|
33
33
|
'composite-row-child-aliased-prop':
|
|
34
34
|
'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)',
|
|
35
|
+
|
|
36
|
+
// #2482 audit follow-ups: loop-scope holes in per-adapter name
|
|
37
|
+
// classification. Graduate by applying the loop-bound-name guards
|
|
38
|
+
// described in each issue and deleting the line.
|
|
39
|
+
'loop-param-shadows-spread-const':
|
|
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)',
|
|
35
41
|
}
|