@barefootjs/rust 0.18.4 → 0.18.5
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/expr/array-method.d.ts.map +1 -1
- package/dist/adapter/expr/emitters.d.ts +2 -2
- package/dist/adapter/expr/emitters.d.ts.map +1 -1
- package/dist/adapter/index.js +45 -13
- package/dist/adapter/lib/constants.d.ts.map +1 -1
- package/dist/adapter/minijinja-adapter.d.ts +8 -0
- package/dist/adapter/minijinja-adapter.d.ts.map +1 -1
- package/dist/build.js +45 -13
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +47 -25
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +3 -3
- package/runtime/src/num.rs +30 -0
- package/runtime/src/runtime.rs +78 -10
- package/runtime/tests/helper_vectors.rs +6 -0
- package/runtime/tests/template_primitives.rs +42 -0
- package/src/__tests__/minijinja-adapter-unit.test.ts +21 -0
- package/src/adapter/expr/array-method.ts +19 -0
- package/src/adapter/expr/emitters.ts +2 -2
- package/src/adapter/lib/constants.ts +3 -0
- package/src/adapter/minijinja-adapter.ts +68 -8
- package/src/conformance-pins.ts +0 -5
- package/src/render-divergences.ts +1 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array-method.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/array-method.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACV,MAAM,iBAAiB,CAAA;AAGxB,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAAE,EAClB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,
|
|
1
|
+
{"version":3,"file":"array-method.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/array-method.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACV,MAAM,iBAAiB,CAAA;AAGxB,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAAE,EAClB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAgJR;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAUf;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM,GAAG,OAAO,EAC3B,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAkBf;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,EAC/B,OAAO,CAAC,EAAE,OAAO,GAChB,MAAM,GAAG,IAAI,CAMf;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,GAAG,IAAI,CAKf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CASxE;AAGD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,EACvC,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAmBR"}
|
|
@@ -77,7 +77,7 @@ export declare class JinjaFilterEmitter implements ParsedExprEmitter {
|
|
|
77
77
|
constructor(param: string, localVarMap: Map<string, string>, isStringName?: (n: string) => boolean, onUnsupported?: ((message: string, reason?: string) => void) | undefined);
|
|
78
78
|
identifier(name: string): string;
|
|
79
79
|
literal(value: string | number | boolean | null, literalType: LiteralType): string;
|
|
80
|
-
member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string;
|
|
80
|
+
member(object: ParsedExpr, property: string, _computed: boolean, _optional: boolean, emit: (e: ParsedExpr) => string): string;
|
|
81
81
|
indexAccess(object: ParsedExpr, index: ParsedExpr, emit: (e: ParsedExpr) => string): string;
|
|
82
82
|
call(callee: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
|
|
83
83
|
unary(op: string, argument: ParsedExpr, emit: (e: ParsedExpr) => string): string;
|
|
@@ -112,7 +112,7 @@ export declare class JinjaTopLevelEmitter implements ParsedExprEmitter {
|
|
|
112
112
|
constructor(ctx: JinjaEmitContext);
|
|
113
113
|
identifier(name: string): string;
|
|
114
114
|
literal(value: string | number | boolean | null, literalType: LiteralType): string;
|
|
115
|
-
member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string;
|
|
115
|
+
member(object: ParsedExpr, property: string, _computed: boolean, _optional: boolean, emit: (e: ParsedExpr) => string): string;
|
|
116
116
|
indexAccess(object: ParsedExpr, index: ParsedExpr, emit: (e: ParsedExpr) => string): string;
|
|
117
117
|
call(callee: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
|
|
118
118
|
unary(op: string, argument: ParsedExpr, emit: (e: ParsedExpr) => string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,KAAK,YAAY,EAIlB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AA+B1D;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAmB,YAAW,iBAAiB;IAExD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAI7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAPjC,YACmB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,YAAY,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAqB,EAIlD,aAAa,CAAC,GAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,aAAA,EACzE;IAEJ,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/B;IAED,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,EAAE,WAAW,EAAE,WAAW,GAAG,MAAM,CAKjF;IAED,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter/index.js
CHANGED
|
@@ -187369,7 +187369,7 @@ function isAriaBooleanAttr(name) {
|
|
|
187369
187369
|
}
|
|
187370
187370
|
|
|
187371
187371
|
// src/adapter/minijinja-adapter.ts
|
|
187372
|
-
import { BF_SLOT, BF_COND, BF_REGION } from "@barefootjs/shared";
|
|
187372
|
+
import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from "@barefootjs/shared";
|
|
187373
187373
|
|
|
187374
187374
|
// src/adapter/lib/constants.ts
|
|
187375
187375
|
var JINJA_TEMPLATE_PRIMITIVES = {
|
|
@@ -187378,7 +187378,10 @@ var JINJA_TEMPLATE_PRIMITIVES = {
|
|
|
187378
187378
|
Number: { arity: 1, emit: (args) => `bf.number(${args[0]})` },
|
|
187379
187379
|
"Math.floor": { arity: 1, emit: (args) => `bf.floor(${args[0]})` },
|
|
187380
187380
|
"Math.ceil": { arity: 1, emit: (args) => `bf.ceil(${args[0]})` },
|
|
187381
|
-
"Math.round": { arity: 1, emit: (args) => `bf.round(${args[0]})` }
|
|
187381
|
+
"Math.round": { arity: 1, emit: (args) => `bf.round(${args[0]})` },
|
|
187382
|
+
"Math.min": { arity: 2, emit: (args) => `bf.min(${args[0]}, ${args[1]})` },
|
|
187383
|
+
"Math.max": { arity: 2, emit: (args) => `bf.max(${args[0]}, ${args[1]})` },
|
|
187384
|
+
"Math.abs": { arity: 1, emit: (args) => `bf.abs(${args[0]})` }
|
|
187382
187385
|
};
|
|
187383
187386
|
var JINJA_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(JINJA_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
|
|
187384
187387
|
|
|
@@ -187544,6 +187547,12 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
187544
187547
|
const recv = emit(object);
|
|
187545
187548
|
return `bf.trim(${recv})`;
|
|
187546
187549
|
}
|
|
187550
|
+
case "trimStart":
|
|
187551
|
+
case "trimEnd": {
|
|
187552
|
+
const fn = method === "trimStart" ? "trim_start" : "trim_end";
|
|
187553
|
+
const recv = emit(object);
|
|
187554
|
+
return `bf.${fn}(${recv})`;
|
|
187555
|
+
}
|
|
187547
187556
|
case "toFixed": {
|
|
187548
187557
|
const recv = emit(object);
|
|
187549
187558
|
const digits = args.length >= 1 ? emit(args[0]) : "0";
|
|
@@ -187577,6 +187586,12 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
187577
187586
|
const newS = emit(args[1]);
|
|
187578
187587
|
return `bf.replace(${recv}, ${oldS}, ${newS})`;
|
|
187579
187588
|
}
|
|
187589
|
+
case "replaceAll": {
|
|
187590
|
+
const recv = emit(object);
|
|
187591
|
+
const oldS = emit(args[0]);
|
|
187592
|
+
const newS = emit(args[1]);
|
|
187593
|
+
return `bf.replace_all(${recv}, ${oldS}, ${newS})`;
|
|
187594
|
+
}
|
|
187580
187595
|
case "repeat": {
|
|
187581
187596
|
const recv = emit(object);
|
|
187582
187597
|
const count = args.length === 0 ? "0" : emit(args[0]);
|
|
@@ -187719,7 +187734,7 @@ class JinjaFilterEmitter {
|
|
|
187719
187734
|
return "none";
|
|
187720
187735
|
return String(value);
|
|
187721
187736
|
}
|
|
187722
|
-
member(object, property, _computed, emit) {
|
|
187737
|
+
member(object, property, _computed, _optional, emit) {
|
|
187723
187738
|
if (property === "length") {
|
|
187724
187739
|
return `bf.length(${emit(object)})`;
|
|
187725
187740
|
}
|
|
@@ -187825,7 +187840,7 @@ class JinjaTopLevelEmitter {
|
|
|
187825
187840
|
return "none";
|
|
187826
187841
|
return String(value);
|
|
187827
187842
|
}
|
|
187828
|
-
member(object, property, _computed, emit) {
|
|
187843
|
+
member(object, property, _computed, _optional, emit) {
|
|
187829
187844
|
if (object.kind === "identifier" && object.name === "props") {
|
|
187830
187845
|
return minijinjaIdent(property);
|
|
187831
187846
|
}
|
|
@@ -188252,6 +188267,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188252
188267
|
options;
|
|
188253
188268
|
errors = [];
|
|
188254
188269
|
inLoop = false;
|
|
188270
|
+
currentLoopKeyDepth = 0;
|
|
188255
188271
|
propsObjectName = null;
|
|
188256
188272
|
propsParams = [];
|
|
188257
188273
|
booleanTypedProps = new Set;
|
|
@@ -188328,7 +188344,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188328
188344
|
return this.renderElement(node);
|
|
188329
188345
|
}
|
|
188330
188346
|
emitText(node) {
|
|
188331
|
-
return node.value;
|
|
188347
|
+
return escapeHtml(node.value);
|
|
188332
188348
|
}
|
|
188333
188349
|
emitExpression(node) {
|
|
188334
188350
|
return this.renderExpression(node);
|
|
@@ -188558,7 +188574,7 @@ ${whenTrue}
|
|
|
188558
188574
|
const renderedChildren = this.renderChildren(loop.children);
|
|
188559
188575
|
const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
|
|
188560
188576
|
const indexLocalLines = [];
|
|
188561
|
-
if (loop.iterationShape === "keys") {
|
|
188577
|
+
if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
|
|
188562
188578
|
indexLocalLines.push(`{% set ${minijinjaIdent(param)} = loop.index0 %}`);
|
|
188563
188579
|
} else if (loop.index) {
|
|
188564
188580
|
indexLocalLines.push(`{% set ${minijinjaIdent(loop.index)} = loop.index0 %}`);
|
|
@@ -188578,13 +188594,17 @@ ${whenTrue}
|
|
|
188578
188594
|
}
|
|
188579
188595
|
const prevInLoop = this.inLoop;
|
|
188580
188596
|
this.inLoop = true;
|
|
188597
|
+
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188598
|
+
this.currentLoopKeyDepth = loop.depth;
|
|
188581
188599
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188600
|
+
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188582
188601
|
this.inLoop = prevInLoop;
|
|
188583
188602
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
188584
188603
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
188585
188604
|
const lines = [];
|
|
188586
188605
|
lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`);
|
|
188587
|
-
|
|
188606
|
+
const forHeader = loop.objectIteration === "entries" ? `{% for ${minijinjaIdent(loop.index ?? param)}, ${minijinjaIdent(param)} in ${array}|items %}` : loop.objectIteration === "keys" ? `{% for ${minijinjaIdent(param)}, __bf_v in ${array}|items %}` : loop.objectIteration === "values" ? `{% for __bf_k, ${minijinjaIdent(param)} in ${array}|items %}` : `{% for ${minijinjaIdent(loopVar)} in ${array} %}`;
|
|
188607
|
+
lines.push(forHeader);
|
|
188588
188608
|
for (const il of indexLocalLines)
|
|
188589
188609
|
lines.push(il);
|
|
188590
188610
|
if (loop.filterPredicate) {
|
|
@@ -188656,9 +188676,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
|
|
|
188656
188676
|
renderComponent(comp) {
|
|
188657
188677
|
const segments = [{ kind: "entries", parts: [] }];
|
|
188658
188678
|
const currentEntries = () => this.componentPropSegmentEntries(segments);
|
|
188679
|
+
const namedSlotSetBlocks = [];
|
|
188659
188680
|
for (const p of comp.props) {
|
|
188660
188681
|
if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
|
|
188661
188682
|
continue;
|
|
188683
|
+
if (p.value.kind === "jsx-children" && p.name !== "children") {
|
|
188684
|
+
const prevInLoop = this.inLoop;
|
|
188685
|
+
this.inLoop = false;
|
|
188686
|
+
const slotBody = this.renderChildren(p.value.children);
|
|
188687
|
+
this.inLoop = prevInLoop;
|
|
188688
|
+
const captureName = `bf_prop_${this.childrenCaptureCounter++}`;
|
|
188689
|
+
namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`);
|
|
188690
|
+
currentEntries().push(`${minijinjaHashKey(p.name)}: ${captureName}`);
|
|
188691
|
+
continue;
|
|
188692
|
+
}
|
|
188662
188693
|
if (p.value.kind === "spread") {
|
|
188663
188694
|
const trimmed = p.value.expr.trim();
|
|
188664
188695
|
if (this.propsObjectName && this.propsObjectName === trimmed) {
|
|
@@ -188687,11 +188718,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
|
|
|
188687
188718
|
const captureName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
|
|
188688
188719
|
currentEntries().push(`${minijinjaHashKey("children")}: ${captureName}`);
|
|
188689
188720
|
const dict = this.combineComponentPropSegments(segments);
|
|
188690
|
-
return
|
|
188721
|
+
return `${namedSlotSetBlocks.join("")}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
|
|
188691
188722
|
}
|
|
188692
188723
|
const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
|
|
188693
188724
|
const dictEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
|
|
188694
|
-
return
|
|
188725
|
+
return `${namedSlotSetBlocks.join("")}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
|
|
188695
188726
|
}
|
|
188696
188727
|
childrenCaptureCounter = 0;
|
|
188697
188728
|
presenceVarCounter = 0;
|
|
@@ -188736,7 +188767,7 @@ ${alternate}
|
|
|
188736
188767
|
${children}`;
|
|
188737
188768
|
}
|
|
188738
188769
|
elementAttrEmitter = {
|
|
188739
|
-
emitLiteral: (value, name) => `${name}="${value.value}"`,
|
|
188770
|
+
emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
|
|
188740
188771
|
emitExpression: (value, name) => {
|
|
188741
188772
|
if (name === "style") {
|
|
188742
188773
|
const css = this.tryLowerStyleObject(value.expr);
|
|
@@ -188844,9 +188875,10 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
188844
188875
|
let attrName;
|
|
188845
188876
|
if (attr.name === "className")
|
|
188846
188877
|
attrName = "class";
|
|
188847
|
-
else if (attr.name === "key")
|
|
188848
|
-
|
|
188849
|
-
|
|
188878
|
+
else if (attr.name === "key") {
|
|
188879
|
+
const depth = this.currentLoopKeyDepth;
|
|
188880
|
+
attrName = depth > 0 ? `data-key-${depth}` : "data-key";
|
|
188881
|
+
} else
|
|
188850
188882
|
attrName = attr.name;
|
|
188851
188883
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
|
|
188852
188884
|
if (lowered)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAUnE,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAG7E,CAAA"}
|
|
@@ -138,6 +138,14 @@ export declare class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitt
|
|
|
138
138
|
private options;
|
|
139
139
|
private errors;
|
|
140
140
|
private inLoop;
|
|
141
|
+
/**
|
|
142
|
+
* `IRLoop.depth` of the loop currently being rendered (save/restore
|
|
143
|
+
* around `renderChildren(loop.children)`, mirroring `inLoop` above).
|
|
144
|
+
* `renderAttributes` reads this to derive the `key` → `data-key`/
|
|
145
|
+
* `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
|
|
146
|
+
* re-derived here (#2168 nested-loop-outer-binding).
|
|
147
|
+
*/
|
|
148
|
+
private currentLoopKeyDepth;
|
|
141
149
|
/**
|
|
142
150
|
* SolidJS-style props identifier (`function(props: P)`) and the
|
|
143
151
|
* analyzer-extracted prop names. Stashed at `generate()` entry so the
|
|
@@ -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,EAyBhB,MAAM,iBAAiB,CAAA;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AA4BpD,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;;;;;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;;;;;;;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,CA4EzE;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,
|
|
1
|
+
{"version":3,"file":"minijinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/minijinja-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/build.js
CHANGED
|
@@ -187369,7 +187369,7 @@ function isAriaBooleanAttr(name) {
|
|
|
187369
187369
|
}
|
|
187370
187370
|
|
|
187371
187371
|
// src/adapter/minijinja-adapter.ts
|
|
187372
|
-
import { BF_SLOT, BF_COND, BF_REGION } from "@barefootjs/shared";
|
|
187372
|
+
import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from "@barefootjs/shared";
|
|
187373
187373
|
|
|
187374
187374
|
// src/adapter/lib/constants.ts
|
|
187375
187375
|
var JINJA_TEMPLATE_PRIMITIVES = {
|
|
@@ -187378,7 +187378,10 @@ var JINJA_TEMPLATE_PRIMITIVES = {
|
|
|
187378
187378
|
Number: { arity: 1, emit: (args) => `bf.number(${args[0]})` },
|
|
187379
187379
|
"Math.floor": { arity: 1, emit: (args) => `bf.floor(${args[0]})` },
|
|
187380
187380
|
"Math.ceil": { arity: 1, emit: (args) => `bf.ceil(${args[0]})` },
|
|
187381
|
-
"Math.round": { arity: 1, emit: (args) => `bf.round(${args[0]})` }
|
|
187381
|
+
"Math.round": { arity: 1, emit: (args) => `bf.round(${args[0]})` },
|
|
187382
|
+
"Math.min": { arity: 2, emit: (args) => `bf.min(${args[0]}, ${args[1]})` },
|
|
187383
|
+
"Math.max": { arity: 2, emit: (args) => `bf.max(${args[0]}, ${args[1]})` },
|
|
187384
|
+
"Math.abs": { arity: 1, emit: (args) => `bf.abs(${args[0]})` }
|
|
187382
187385
|
};
|
|
187383
187386
|
var JINJA_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(JINJA_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
|
|
187384
187387
|
|
|
@@ -187544,6 +187547,12 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
187544
187547
|
const recv = emit(object);
|
|
187545
187548
|
return `bf.trim(${recv})`;
|
|
187546
187549
|
}
|
|
187550
|
+
case "trimStart":
|
|
187551
|
+
case "trimEnd": {
|
|
187552
|
+
const fn = method === "trimStart" ? "trim_start" : "trim_end";
|
|
187553
|
+
const recv = emit(object);
|
|
187554
|
+
return `bf.${fn}(${recv})`;
|
|
187555
|
+
}
|
|
187547
187556
|
case "toFixed": {
|
|
187548
187557
|
const recv = emit(object);
|
|
187549
187558
|
const digits = args.length >= 1 ? emit(args[0]) : "0";
|
|
@@ -187577,6 +187586,12 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
187577
187586
|
const newS = emit(args[1]);
|
|
187578
187587
|
return `bf.replace(${recv}, ${oldS}, ${newS})`;
|
|
187579
187588
|
}
|
|
187589
|
+
case "replaceAll": {
|
|
187590
|
+
const recv = emit(object);
|
|
187591
|
+
const oldS = emit(args[0]);
|
|
187592
|
+
const newS = emit(args[1]);
|
|
187593
|
+
return `bf.replace_all(${recv}, ${oldS}, ${newS})`;
|
|
187594
|
+
}
|
|
187580
187595
|
case "repeat": {
|
|
187581
187596
|
const recv = emit(object);
|
|
187582
187597
|
const count = args.length === 0 ? "0" : emit(args[0]);
|
|
@@ -187719,7 +187734,7 @@ class JinjaFilterEmitter {
|
|
|
187719
187734
|
return "none";
|
|
187720
187735
|
return String(value);
|
|
187721
187736
|
}
|
|
187722
|
-
member(object, property, _computed, emit) {
|
|
187737
|
+
member(object, property, _computed, _optional, emit) {
|
|
187723
187738
|
if (property === "length") {
|
|
187724
187739
|
return `bf.length(${emit(object)})`;
|
|
187725
187740
|
}
|
|
@@ -187825,7 +187840,7 @@ class JinjaTopLevelEmitter {
|
|
|
187825
187840
|
return "none";
|
|
187826
187841
|
return String(value);
|
|
187827
187842
|
}
|
|
187828
|
-
member(object, property, _computed, emit) {
|
|
187843
|
+
member(object, property, _computed, _optional, emit) {
|
|
187829
187844
|
if (object.kind === "identifier" && object.name === "props") {
|
|
187830
187845
|
return minijinjaIdent(property);
|
|
187831
187846
|
}
|
|
@@ -188252,6 +188267,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188252
188267
|
options;
|
|
188253
188268
|
errors = [];
|
|
188254
188269
|
inLoop = false;
|
|
188270
|
+
currentLoopKeyDepth = 0;
|
|
188255
188271
|
propsObjectName = null;
|
|
188256
188272
|
propsParams = [];
|
|
188257
188273
|
booleanTypedProps = new Set;
|
|
@@ -188328,7 +188344,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188328
188344
|
return this.renderElement(node);
|
|
188329
188345
|
}
|
|
188330
188346
|
emitText(node) {
|
|
188331
|
-
return node.value;
|
|
188347
|
+
return escapeHtml(node.value);
|
|
188332
188348
|
}
|
|
188333
188349
|
emitExpression(node) {
|
|
188334
188350
|
return this.renderExpression(node);
|
|
@@ -188558,7 +188574,7 @@ ${whenTrue}
|
|
|
188558
188574
|
const renderedChildren = this.renderChildren(loop.children);
|
|
188559
188575
|
const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
|
|
188560
188576
|
const indexLocalLines = [];
|
|
188561
|
-
if (loop.iterationShape === "keys") {
|
|
188577
|
+
if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
|
|
188562
188578
|
indexLocalLines.push(`{% set ${minijinjaIdent(param)} = loop.index0 %}`);
|
|
188563
188579
|
} else if (loop.index) {
|
|
188564
188580
|
indexLocalLines.push(`{% set ${minijinjaIdent(loop.index)} = loop.index0 %}`);
|
|
@@ -188578,13 +188594,17 @@ ${whenTrue}
|
|
|
188578
188594
|
}
|
|
188579
188595
|
const prevInLoop = this.inLoop;
|
|
188580
188596
|
this.inLoop = true;
|
|
188597
|
+
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188598
|
+
this.currentLoopKeyDepth = loop.depth;
|
|
188581
188599
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188600
|
+
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188582
188601
|
this.inLoop = prevInLoop;
|
|
188583
188602
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
188584
188603
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
188585
188604
|
const lines = [];
|
|
188586
188605
|
lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`);
|
|
188587
|
-
|
|
188606
|
+
const forHeader = loop.objectIteration === "entries" ? `{% for ${minijinjaIdent(loop.index ?? param)}, ${minijinjaIdent(param)} in ${array}|items %}` : loop.objectIteration === "keys" ? `{% for ${minijinjaIdent(param)}, __bf_v in ${array}|items %}` : loop.objectIteration === "values" ? `{% for __bf_k, ${minijinjaIdent(param)} in ${array}|items %}` : `{% for ${minijinjaIdent(loopVar)} in ${array} %}`;
|
|
188607
|
+
lines.push(forHeader);
|
|
188588
188608
|
for (const il of indexLocalLines)
|
|
188589
188609
|
lines.push(il);
|
|
188590
188610
|
if (loop.filterPredicate) {
|
|
@@ -188656,9 +188676,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
|
|
|
188656
188676
|
renderComponent(comp) {
|
|
188657
188677
|
const segments = [{ kind: "entries", parts: [] }];
|
|
188658
188678
|
const currentEntries = () => this.componentPropSegmentEntries(segments);
|
|
188679
|
+
const namedSlotSetBlocks = [];
|
|
188659
188680
|
for (const p of comp.props) {
|
|
188660
188681
|
if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
|
|
188661
188682
|
continue;
|
|
188683
|
+
if (p.value.kind === "jsx-children" && p.name !== "children") {
|
|
188684
|
+
const prevInLoop = this.inLoop;
|
|
188685
|
+
this.inLoop = false;
|
|
188686
|
+
const slotBody = this.renderChildren(p.value.children);
|
|
188687
|
+
this.inLoop = prevInLoop;
|
|
188688
|
+
const captureName = `bf_prop_${this.childrenCaptureCounter++}`;
|
|
188689
|
+
namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`);
|
|
188690
|
+
currentEntries().push(`${minijinjaHashKey(p.name)}: ${captureName}`);
|
|
188691
|
+
continue;
|
|
188692
|
+
}
|
|
188662
188693
|
if (p.value.kind === "spread") {
|
|
188663
188694
|
const trimmed = p.value.expr.trim();
|
|
188664
188695
|
if (this.propsObjectName && this.propsObjectName === trimmed) {
|
|
@@ -188687,11 +188718,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
|
|
|
188687
188718
|
const captureName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
|
|
188688
188719
|
currentEntries().push(`${minijinjaHashKey("children")}: ${captureName}`);
|
|
188689
188720
|
const dict = this.combineComponentPropSegments(segments);
|
|
188690
|
-
return
|
|
188721
|
+
return `${namedSlotSetBlocks.join("")}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
|
|
188691
188722
|
}
|
|
188692
188723
|
const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
|
|
188693
188724
|
const dictEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
|
|
188694
|
-
return
|
|
188725
|
+
return `${namedSlotSetBlocks.join("")}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
|
|
188695
188726
|
}
|
|
188696
188727
|
childrenCaptureCounter = 0;
|
|
188697
188728
|
presenceVarCounter = 0;
|
|
@@ -188736,7 +188767,7 @@ ${alternate}
|
|
|
188736
188767
|
${children}`;
|
|
188737
188768
|
}
|
|
188738
188769
|
elementAttrEmitter = {
|
|
188739
|
-
emitLiteral: (value, name) => `${name}="${value.value}"`,
|
|
188770
|
+
emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
|
|
188740
188771
|
emitExpression: (value, name) => {
|
|
188741
188772
|
if (name === "style") {
|
|
188742
188773
|
const css = this.tryLowerStyleObject(value.expr);
|
|
@@ -188844,9 +188875,10 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
188844
188875
|
let attrName;
|
|
188845
188876
|
if (attr.name === "className")
|
|
188846
188877
|
attrName = "class";
|
|
188847
|
-
else if (attr.name === "key")
|
|
188848
|
-
|
|
188849
|
-
|
|
188878
|
+
else if (attr.name === "key") {
|
|
188879
|
+
const depth = this.currentLoopKeyDepth;
|
|
188880
|
+
attrName = depth > 0 ? `data-key-${depth}` : "data-key";
|
|
188881
|
+
} else
|
|
188850
188882
|
attrName = attr.name;
|
|
188851
188883
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
|
|
188852
188884
|
if (lowered)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eA6F7B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -187369,7 +187369,7 @@ function isAriaBooleanAttr(name) {
|
|
|
187369
187369
|
}
|
|
187370
187370
|
|
|
187371
187371
|
// src/adapter/minijinja-adapter.ts
|
|
187372
|
-
import { BF_SLOT, BF_COND, BF_REGION } from "@barefootjs/shared";
|
|
187372
|
+
import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from "@barefootjs/shared";
|
|
187373
187373
|
|
|
187374
187374
|
// src/adapter/lib/constants.ts
|
|
187375
187375
|
var JINJA_TEMPLATE_PRIMITIVES = {
|
|
@@ -187378,7 +187378,10 @@ var JINJA_TEMPLATE_PRIMITIVES = {
|
|
|
187378
187378
|
Number: { arity: 1, emit: (args) => `bf.number(${args[0]})` },
|
|
187379
187379
|
"Math.floor": { arity: 1, emit: (args) => `bf.floor(${args[0]})` },
|
|
187380
187380
|
"Math.ceil": { arity: 1, emit: (args) => `bf.ceil(${args[0]})` },
|
|
187381
|
-
"Math.round": { arity: 1, emit: (args) => `bf.round(${args[0]})` }
|
|
187381
|
+
"Math.round": { arity: 1, emit: (args) => `bf.round(${args[0]})` },
|
|
187382
|
+
"Math.min": { arity: 2, emit: (args) => `bf.min(${args[0]}, ${args[1]})` },
|
|
187383
|
+
"Math.max": { arity: 2, emit: (args) => `bf.max(${args[0]}, ${args[1]})` },
|
|
187384
|
+
"Math.abs": { arity: 1, emit: (args) => `bf.abs(${args[0]})` }
|
|
187382
187385
|
};
|
|
187383
187386
|
var JINJA_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(JINJA_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
|
|
187384
187387
|
|
|
@@ -187544,6 +187547,12 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
187544
187547
|
const recv = emit(object);
|
|
187545
187548
|
return `bf.trim(${recv})`;
|
|
187546
187549
|
}
|
|
187550
|
+
case "trimStart":
|
|
187551
|
+
case "trimEnd": {
|
|
187552
|
+
const fn = method === "trimStart" ? "trim_start" : "trim_end";
|
|
187553
|
+
const recv = emit(object);
|
|
187554
|
+
return `bf.${fn}(${recv})`;
|
|
187555
|
+
}
|
|
187547
187556
|
case "toFixed": {
|
|
187548
187557
|
const recv = emit(object);
|
|
187549
187558
|
const digits = args.length >= 1 ? emit(args[0]) : "0";
|
|
@@ -187577,6 +187586,12 @@ function renderArrayMethod(method, object, args, emit) {
|
|
|
187577
187586
|
const newS = emit(args[1]);
|
|
187578
187587
|
return `bf.replace(${recv}, ${oldS}, ${newS})`;
|
|
187579
187588
|
}
|
|
187589
|
+
case "replaceAll": {
|
|
187590
|
+
const recv = emit(object);
|
|
187591
|
+
const oldS = emit(args[0]);
|
|
187592
|
+
const newS = emit(args[1]);
|
|
187593
|
+
return `bf.replace_all(${recv}, ${oldS}, ${newS})`;
|
|
187594
|
+
}
|
|
187580
187595
|
case "repeat": {
|
|
187581
187596
|
const recv = emit(object);
|
|
187582
187597
|
const count = args.length === 0 ? "0" : emit(args[0]);
|
|
@@ -187719,7 +187734,7 @@ class JinjaFilterEmitter {
|
|
|
187719
187734
|
return "none";
|
|
187720
187735
|
return String(value);
|
|
187721
187736
|
}
|
|
187722
|
-
member(object, property, _computed, emit) {
|
|
187737
|
+
member(object, property, _computed, _optional, emit) {
|
|
187723
187738
|
if (property === "length") {
|
|
187724
187739
|
return `bf.length(${emit(object)})`;
|
|
187725
187740
|
}
|
|
@@ -187825,7 +187840,7 @@ class JinjaTopLevelEmitter {
|
|
|
187825
187840
|
return "none";
|
|
187826
187841
|
return String(value);
|
|
187827
187842
|
}
|
|
187828
|
-
member(object, property, _computed, emit) {
|
|
187843
|
+
member(object, property, _computed, _optional, emit) {
|
|
187829
187844
|
if (object.kind === "identifier" && object.name === "props") {
|
|
187830
187845
|
return minijinjaIdent(property);
|
|
187831
187846
|
}
|
|
@@ -188252,6 +188267,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188252
188267
|
options;
|
|
188253
188268
|
errors = [];
|
|
188254
188269
|
inLoop = false;
|
|
188270
|
+
currentLoopKeyDepth = 0;
|
|
188255
188271
|
propsObjectName = null;
|
|
188256
188272
|
propsParams = [];
|
|
188257
188273
|
booleanTypedProps = new Set;
|
|
@@ -188328,7 +188344,7 @@ class MinijinjaAdapter extends BaseAdapter {
|
|
|
188328
188344
|
return this.renderElement(node);
|
|
188329
188345
|
}
|
|
188330
188346
|
emitText(node) {
|
|
188331
|
-
return node.value;
|
|
188347
|
+
return escapeHtml(node.value);
|
|
188332
188348
|
}
|
|
188333
188349
|
emitExpression(node) {
|
|
188334
188350
|
return this.renderExpression(node);
|
|
@@ -188558,7 +188574,7 @@ ${whenTrue}
|
|
|
188558
188574
|
const renderedChildren = this.renderChildren(loop.children);
|
|
188559
188575
|
const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
|
|
188560
188576
|
const indexLocalLines = [];
|
|
188561
|
-
if (loop.iterationShape === "keys") {
|
|
188577
|
+
if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
|
|
188562
188578
|
indexLocalLines.push(`{% set ${minijinjaIdent(param)} = loop.index0 %}`);
|
|
188563
188579
|
} else if (loop.index) {
|
|
188564
188580
|
indexLocalLines.push(`{% set ${minijinjaIdent(loop.index)} = loop.index0 %}`);
|
|
@@ -188578,13 +188594,17 @@ ${whenTrue}
|
|
|
188578
188594
|
}
|
|
188579
188595
|
const prevInLoop = this.inLoop;
|
|
188580
188596
|
this.inLoop = true;
|
|
188597
|
+
const prevLoopKeyDepth = this.currentLoopKeyDepth;
|
|
188598
|
+
this.currentLoopKeyDepth = loop.depth;
|
|
188581
188599
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188600
|
+
this.currentLoopKeyDepth = prevLoopKeyDepth;
|
|
188582
188601
|
this.inLoop = prevInLoop;
|
|
188583
188602
|
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
188584
188603
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
188585
188604
|
const lines = [];
|
|
188586
188605
|
lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`);
|
|
188587
|
-
|
|
188606
|
+
const forHeader = loop.objectIteration === "entries" ? `{% for ${minijinjaIdent(loop.index ?? param)}, ${minijinjaIdent(param)} in ${array}|items %}` : loop.objectIteration === "keys" ? `{% for ${minijinjaIdent(param)}, __bf_v in ${array}|items %}` : loop.objectIteration === "values" ? `{% for __bf_k, ${minijinjaIdent(param)} in ${array}|items %}` : `{% for ${minijinjaIdent(loopVar)} in ${array} %}`;
|
|
188607
|
+
lines.push(forHeader);
|
|
188588
188608
|
for (const il of indexLocalLines)
|
|
188589
188609
|
lines.push(il);
|
|
188590
188610
|
if (loop.filterPredicate) {
|
|
@@ -188656,9 +188676,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
|
|
|
188656
188676
|
renderComponent(comp) {
|
|
188657
188677
|
const segments = [{ kind: "entries", parts: [] }];
|
|
188658
188678
|
const currentEntries = () => this.componentPropSegmentEntries(segments);
|
|
188679
|
+
const namedSlotSetBlocks = [];
|
|
188659
188680
|
for (const p of comp.props) {
|
|
188660
188681
|
if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
|
|
188661
188682
|
continue;
|
|
188683
|
+
if (p.value.kind === "jsx-children" && p.name !== "children") {
|
|
188684
|
+
const prevInLoop = this.inLoop;
|
|
188685
|
+
this.inLoop = false;
|
|
188686
|
+
const slotBody = this.renderChildren(p.value.children);
|
|
188687
|
+
this.inLoop = prevInLoop;
|
|
188688
|
+
const captureName = `bf_prop_${this.childrenCaptureCounter++}`;
|
|
188689
|
+
namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`);
|
|
188690
|
+
currentEntries().push(`${minijinjaHashKey(p.name)}: ${captureName}`);
|
|
188691
|
+
continue;
|
|
188692
|
+
}
|
|
188662
188693
|
if (p.value.kind === "spread") {
|
|
188663
188694
|
const trimmed = p.value.expr.trim();
|
|
188664
188695
|
if (this.propsObjectName && this.propsObjectName === trimmed) {
|
|
@@ -188687,11 +188718,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
|
|
|
188687
188718
|
const captureName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
|
|
188688
188719
|
currentEntries().push(`${minijinjaHashKey("children")}: ${captureName}`);
|
|
188689
188720
|
const dict = this.combineComponentPropSegments(segments);
|
|
188690
|
-
return
|
|
188721
|
+
return `${namedSlotSetBlocks.join("")}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
|
|
188691
188722
|
}
|
|
188692
188723
|
const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
|
|
188693
188724
|
const dictEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
|
|
188694
|
-
return
|
|
188725
|
+
return `${namedSlotSetBlocks.join("")}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
|
|
188695
188726
|
}
|
|
188696
188727
|
childrenCaptureCounter = 0;
|
|
188697
188728
|
presenceVarCounter = 0;
|
|
@@ -188736,7 +188767,7 @@ ${alternate}
|
|
|
188736
188767
|
${children}`;
|
|
188737
188768
|
}
|
|
188738
188769
|
elementAttrEmitter = {
|
|
188739
|
-
emitLiteral: (value, name) => `${name}="${value.value}"`,
|
|
188770
|
+
emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
|
|
188740
188771
|
emitExpression: (value, name) => {
|
|
188741
188772
|
if (name === "style") {
|
|
188742
188773
|
const css = this.tryLowerStyleObject(value.expr);
|
|
@@ -188844,9 +188875,10 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
188844
188875
|
let attrName;
|
|
188845
188876
|
if (attr.name === "className")
|
|
188846
188877
|
attrName = "class";
|
|
188847
|
-
else if (attr.name === "key")
|
|
188848
|
-
|
|
188849
|
-
|
|
188878
|
+
else if (attr.name === "key") {
|
|
188879
|
+
const depth = this.currentLoopKeyDepth;
|
|
188880
|
+
attrName = depth > 0 ? `data-key-${depth}` : "data-key";
|
|
188881
|
+
} else
|
|
188850
188882
|
attrName = attr.name;
|
|
188851
188883
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
|
|
188852
188884
|
if (lowered)
|
|
@@ -189105,20 +189137,10 @@ var conformancePins = {
|
|
|
189105
189137
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
189106
189138
|
],
|
|
189107
189139
|
"array-map-function-reference": [{ code: "BF101", severity: "error" }],
|
|
189108
|
-
"dangerous-inner-html": [{ code: "BF101", severity: "error" }]
|
|
189109
|
-
"string-replaceall": [{ code: "BF101", severity: "error" }]
|
|
189140
|
+
"dangerous-inner-html": [{ code: "BF101", severity: "error" }]
|
|
189110
189141
|
};
|
|
189111
189142
|
// src/render-divergences.ts
|
|
189112
|
-
var renderDivergences = {
|
|
189113
|
-
"html-entity-text": "`©` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes",
|
|
189114
|
-
"math-methods": "Math.min/max/abs over a signal render empty (only Math.floor is in the template-primitive registry)",
|
|
189115
|
-
"static-attr-escape": 'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
|
|
189116
|
-
"object-entries-map": "`Object.entries(prop).map(([k, v]) => …)` renders an EMPTY list — the object-shaped prop silently produces zero iterations",
|
|
189117
|
-
"nested-loop-outer-binding": "nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`",
|
|
189118
|
-
"jsx-element-prop": "a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped",
|
|
189119
|
-
"string-slice": "`.slice()` on a STRING renders empty (array-slice helper misfires on strings)",
|
|
189120
|
-
"string-trim-sided": "`.trimStart()` / `.trimEnd()` render empty (no lowering)"
|
|
189121
|
-
};
|
|
189143
|
+
var renderDivergences = {};
|
|
189122
189144
|
export {
|
|
189123
189145
|
renderDivergences,
|
|
189124
189146
|
minijinjaAdapter,
|
|
@@ -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,iBAAsB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/rust",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
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,14 +54,14 @@
|
|
|
54
54
|
"directory": "packages/adapter-rust"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@barefootjs/shared": "0.18.
|
|
57
|
+
"@barefootjs/shared": "0.18.5"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@barefootjs/jsx": ">=0.2.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
64
|
-
"@barefootjs/jsx": "0.18.
|
|
64
|
+
"@barefootjs/jsx": "0.18.5",
|
|
65
65
|
"typescript": "^5.0.0"
|
|
66
66
|
}
|
|
67
67
|
}
|
package/runtime/src/num.rs
CHANGED
|
@@ -373,6 +373,36 @@ pub fn js_round(n: f64) -> f64 {
|
|
|
373
373
|
(n + 0.5).floor()
|
|
374
374
|
}
|
|
375
375
|
|
|
376
|
+
/// `Math.min(a, b)` / `Math.max(a, b)` -- two-arg forms only (#2168
|
|
377
|
+
/// math-methods). NOT `f64::min`/`f64::max`: those follow IEEE-754
|
|
378
|
+
/// `minNum`/`maxNum` semantics and return the non-NaN operand when only
|
|
379
|
+
/// one side is NaN, whereas JS returns NaN if EITHER operand is NaN.
|
|
380
|
+
pub fn js_min(a: f64, b: f64) -> f64 {
|
|
381
|
+
if a.is_nan() {
|
|
382
|
+
return a;
|
|
383
|
+
}
|
|
384
|
+
if b.is_nan() {
|
|
385
|
+
return b;
|
|
386
|
+
}
|
|
387
|
+
if a < b { a } else { b }
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
pub fn js_max(a: f64, b: f64) -> f64 {
|
|
391
|
+
if a.is_nan() {
|
|
392
|
+
return a;
|
|
393
|
+
}
|
|
394
|
+
if b.is_nan() {
|
|
395
|
+
return b;
|
|
396
|
+
}
|
|
397
|
+
if a > b { a } else { b }
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/// `Math.abs()` (#2168 math-methods). `f64::abs` already matches JS for
|
|
401
|
+
/// NaN (NaN.abs() is NaN) and both infinities, no guard needed.
|
|
402
|
+
pub fn js_abs(n: f64) -> f64 {
|
|
403
|
+
n.abs()
|
|
404
|
+
}
|
|
405
|
+
|
|
376
406
|
/// JS `%`: remainder with the dividend's sign. Rust's `%` on `f64` already
|
|
377
407
|
/// implements C `fmod` semantics (IEEE-754 remainder), so this is a
|
|
378
408
|
/// documentation-only wrapper -- see the module docstring for why no
|
package/runtime/src/runtime.rs
CHANGED
|
@@ -166,6 +166,34 @@ fn char_slice_to(s: &str, n: usize) -> String {
|
|
|
166
166
|
s.chars().take(n).collect()
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/// `[start, end)` range slice by Unicode scalar value (`char`), not
|
|
170
|
+
/// byte offset -- shared by `slice`'s string branch. Matches JS except
|
|
171
|
+
/// for astral-plane input, the same divergence boundary `char_len` /
|
|
172
|
+
/// `char_slice_from` / `char_slice_to` already accept.
|
|
173
|
+
fn char_slice_range(s: &str, start: usize, end: usize) -> String {
|
|
174
|
+
if start >= end {
|
|
175
|
+
return String::new();
|
|
176
|
+
}
|
|
177
|
+
s.chars().skip(start).take(end - start).collect()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/// Clamp JS `.slice(start, end?)` bounds against a receiver of
|
|
181
|
+
/// `length` elements -- shared by `slice`'s array and string branches
|
|
182
|
+
/// below.
|
|
183
|
+
fn clamp_slice_range(length: i64, start: &JsValue, end: &JsValue) -> (i64, i64) {
|
|
184
|
+
let mut s = if matches!(start, JsValue::Null) { 0 } else { num::to_f64(start) as i64 };
|
|
185
|
+
if s < 0 {
|
|
186
|
+
s += length;
|
|
187
|
+
}
|
|
188
|
+
s = s.clamp(0, length);
|
|
189
|
+
let mut e = if matches!(end, JsValue::Null) { length } else { num::to_f64(end) as i64 };
|
|
190
|
+
if e < 0 {
|
|
191
|
+
e += length;
|
|
192
|
+
}
|
|
193
|
+
e = e.clamp(0, length);
|
|
194
|
+
(s, e)
|
|
195
|
+
}
|
|
196
|
+
|
|
169
197
|
// ---------------------------------------------------------------------------
|
|
170
198
|
// spread_attrs support (JSX intrinsic-element spread, #1407).
|
|
171
199
|
// ---------------------------------------------------------------------------
|
|
@@ -1155,6 +1183,9 @@ impl Object for BfInstance {
|
|
|
1155
1183
|
"floor" => Ok(MjValue::from(num::js_floor(js_number(a(0))))),
|
|
1156
1184
|
"ceil" => Ok(MjValue::from(num::js_ceil(js_number(a(0))))),
|
|
1157
1185
|
"round" => Ok(MjValue::from(num::js_round(js_number(a(0))))),
|
|
1186
|
+
"min" => Ok(MjValue::from(num::js_min(js_number(a(0)), js_number(a(1))))),
|
|
1187
|
+
"max" => Ok(MjValue::from(num::js_max(js_number(a(0)), js_number(a(1))))),
|
|
1188
|
+
"abs" => Ok(MjValue::from(num::js_abs(js_number(a(0))))),
|
|
1158
1189
|
"to_fixed" => Ok(MjValue::from(num::to_fixed(js_number(a(0)), num::to_f64(a(1)) as i32))),
|
|
1159
1190
|
|
|
1160
1191
|
// -- Array / string method helpers (#1448 Tier A) ------------------
|
|
@@ -1191,6 +1222,8 @@ impl Object for BfInstance {
|
|
|
1191
1222
|
Ok(js_to_mj(&flat_map_tuple(a(0), &specs)))
|
|
1192
1223
|
}
|
|
1193
1224
|
"trim" => Ok(MjValue::from(trim(a(0)))),
|
|
1225
|
+
"trim_start" => Ok(MjValue::from(trim_start(a(0)))),
|
|
1226
|
+
"trim_end" => Ok(MjValue::from(trim_end(a(0)))),
|
|
1194
1227
|
"split" => {
|
|
1195
1228
|
let sep = if args.len() > 1 { Some(a(1)) } else { None };
|
|
1196
1229
|
let limit = if args.len() > 2 && !matches!(a(2), JsValue::Null) { Some(num::to_f64(a(2)) as i64) } else { None };
|
|
@@ -1199,6 +1232,7 @@ impl Object for BfInstance {
|
|
|
1199
1232
|
"starts_with" => Ok(MjValue::from(starts_with(a(0), a(1), a(2)))),
|
|
1200
1233
|
"ends_with" => Ok(MjValue::from(ends_with(a(0), a(1), a(2)))),
|
|
1201
1234
|
"replace" => Ok(MjValue::from(replace(a(0), a(1), a(2)))),
|
|
1235
|
+
"replace_all" => Ok(MjValue::from(replace_all(a(0), a(1), a(2)))),
|
|
1202
1236
|
"query" => Ok(MjValue::from(query(a(0), &js_args[1..]))),
|
|
1203
1237
|
"repeat" => Ok(MjValue::from(repeat(a(0), a(1)))),
|
|
1204
1238
|
"pad_start" => Ok(MjValue::from(pad(&scalar_or_empty(a(0)), a(1), a(2), true))),
|
|
@@ -1351,7 +1385,18 @@ pub fn concat(a: &JsValue, b: &JsValue) -> JsValue {
|
|
|
1351
1385
|
JsValue::Array(out)
|
|
1352
1386
|
}
|
|
1353
1387
|
|
|
1388
|
+
/// `Array.prototype.slice(start, end?)` AND `String.prototype.slice`
|
|
1389
|
+
/// (the `string-slice` divergence) -- the adapter emits the same
|
|
1390
|
+
/// `bf.slice(recv, start, end)` call for both receiver shapes (it
|
|
1391
|
+
/// can't disambiguate string vs. array at compile time), so this
|
|
1392
|
+
/// dispatches on `recv`'s `JsValue` variant, mirroring `includes` /
|
|
1393
|
+
/// `length` above.
|
|
1354
1394
|
pub fn slice(recv: &JsValue, start: &JsValue, end: &JsValue) -> JsValue {
|
|
1395
|
+
if let JsValue::String(s) = recv {
|
|
1396
|
+
let length = char_len(s) as i64;
|
|
1397
|
+
let (s_idx, e_idx) = clamp_slice_range(length, start, end);
|
|
1398
|
+
return JsValue::String(char_slice_range(s, s_idx as usize, e_idx as usize));
|
|
1399
|
+
}
|
|
1355
1400
|
let items = match recv.as_array() {
|
|
1356
1401
|
Some(a) => a,
|
|
1357
1402
|
None => return JsValue::Array(Vec::new()),
|
|
@@ -1360,16 +1405,7 @@ pub fn slice(recv: &JsValue, start: &JsValue, end: &JsValue) -> JsValue {
|
|
|
1360
1405
|
if length == 0 {
|
|
1361
1406
|
return JsValue::Array(Vec::new());
|
|
1362
1407
|
}
|
|
1363
|
-
let
|
|
1364
|
-
if s < 0 {
|
|
1365
|
-
s += length;
|
|
1366
|
-
}
|
|
1367
|
-
s = s.clamp(0, length);
|
|
1368
|
-
let mut e = if matches!(end, JsValue::Null) { length } else { num::to_f64(end) as i64 };
|
|
1369
|
-
if e < 0 {
|
|
1370
|
-
e += length;
|
|
1371
|
-
}
|
|
1372
|
-
e = e.clamp(0, length);
|
|
1408
|
+
let (s, e) = clamp_slice_range(length, start, end);
|
|
1373
1409
|
if s >= e {
|
|
1374
1410
|
return JsValue::Array(Vec::new());
|
|
1375
1411
|
}
|
|
@@ -1420,6 +1456,24 @@ pub fn trim(recv: &JsValue) -> String {
|
|
|
1420
1456
|
}
|
|
1421
1457
|
}
|
|
1422
1458
|
|
|
1459
|
+
/// `String.prototype.trimStart()` -- the one-sided sibling of `trim`
|
|
1460
|
+
/// above (#2183 follow-up), via Rust's native `str::trim_start`.
|
|
1461
|
+
pub fn trim_start(recv: &JsValue) -> String {
|
|
1462
|
+
match recv {
|
|
1463
|
+
JsValue::Null | JsValue::Array(_) | JsValue::Object(_) => String::new(),
|
|
1464
|
+
other => js_string(other).trim_start().to_string(),
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/// `String.prototype.trimEnd()` -- the one-sided sibling of `trim`
|
|
1469
|
+
/// above (#2183 follow-up), via Rust's native `str::trim_end`.
|
|
1470
|
+
pub fn trim_end(recv: &JsValue) -> String {
|
|
1471
|
+
match recv {
|
|
1472
|
+
JsValue::Null | JsValue::Array(_) | JsValue::Object(_) => String::new(),
|
|
1473
|
+
other => js_string(other).trim_end().to_string(),
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1423
1477
|
pub fn split(recv: &JsValue, sep: Option<&JsValue>, limit: Option<i64>) -> JsValue {
|
|
1424
1478
|
let s = scalar_or_empty(recv);
|
|
1425
1479
|
let mut parts: Vec<String> = match sep {
|
|
@@ -1488,6 +1542,20 @@ pub fn replace(recv: &JsValue, pattern: &JsValue, replacement: &JsValue) -> Stri
|
|
|
1488
1542
|
}
|
|
1489
1543
|
}
|
|
1490
1544
|
|
|
1545
|
+
/// `String.prototype.replaceAll(pattern, replacement)`, string-pattern
|
|
1546
|
+
/// form only (#2182) -- every occurrence, the all-occurrences sibling
|
|
1547
|
+
/// of `replace` above. Rust's own `str::replace` (no count arg) is
|
|
1548
|
+
/// already global by default, including the empty-pattern-inserts-at-
|
|
1549
|
+
/// every-boundary edge case (`"abc".replace("", "X")` -> "XaXbXcX"),
|
|
1550
|
+
/// so it needs no hand-rolled loop the way `replace_all` on the
|
|
1551
|
+
/// backends whose native replace is first-occurrence-only does.
|
|
1552
|
+
pub fn replace_all(recv: &JsValue, pattern: &JsValue, replacement: &JsValue) -> String {
|
|
1553
|
+
let s = scalar_or_empty(recv);
|
|
1554
|
+
let o = js_string(pattern);
|
|
1555
|
+
let n = js_string(replacement);
|
|
1556
|
+
s.replace(&o, &n)
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1491
1559
|
/// `queryHref(base, {...})` (#2042) -- build `"$base?k=v&..."` from a flat
|
|
1492
1560
|
/// list of (guard, key, value) triples. A pair is included iff its guard is
|
|
1493
1561
|
/// JS-truthy AND its value is a non-empty string. A value may also be a
|
|
@@ -116,6 +116,9 @@ fn call_binding(fn_name: &str, args: &[JsValue]) -> Option<JsValue> {
|
|
|
116
116
|
"floor" => JsValue::Number(num::js_floor(runtime::js_number(&a(0)))),
|
|
117
117
|
"ceil" => JsValue::Number(num::js_ceil(runtime::js_number(&a(0)))),
|
|
118
118
|
"round" => JsValue::Number(num::js_round(runtime::js_number(&a(0)))),
|
|
119
|
+
"min" => JsValue::Number(num::js_min(runtime::js_number(&a(0)), runtime::js_number(&a(1)))),
|
|
120
|
+
"max" => JsValue::Number(num::js_max(runtime::js_number(&a(0)), runtime::js_number(&a(1)))),
|
|
121
|
+
"abs" => JsValue::Number(num::js_abs(runtime::js_number(&a(0)))),
|
|
119
122
|
"to_fixed" => {
|
|
120
123
|
let digits = if args.len() > 1 { num::to_f64(&a(1)) as i32 } else { 0 };
|
|
121
124
|
JsValue::String(num::to_fixed(runtime::js_number(&a(0)), digits))
|
|
@@ -123,9 +126,12 @@ fn call_binding(fn_name: &str, args: &[JsValue]) -> Option<JsValue> {
|
|
|
123
126
|
"lower" => JsValue::String(runtime::js_string(&a(0)).to_lowercase()),
|
|
124
127
|
"upper" => JsValue::String(runtime::js_string(&a(0)).to_uppercase()),
|
|
125
128
|
"trim" => JsValue::String(runtime::trim(&a(0))),
|
|
129
|
+
"trim_start" => JsValue::String(runtime::trim_start(&a(0))),
|
|
130
|
+
"trim_end" => JsValue::String(runtime::trim_end(&a(0))),
|
|
126
131
|
"starts_with" => JsValue::Bool(runtime::starts_with(&a(0), &a(1), &a(2))),
|
|
127
132
|
"ends_with" => JsValue::Bool(runtime::ends_with(&a(0), &a(1), &a(2))),
|
|
128
133
|
"replace" => JsValue::String(runtime::replace(&a(0), &a(1), &a(2))),
|
|
134
|
+
"replace_all" => JsValue::String(runtime::replace_all(&a(0), &a(1), &a(2))),
|
|
129
135
|
"repeat" => JsValue::String(runtime::repeat(&a(0), &a(1))),
|
|
130
136
|
"pad_start" => JsValue::String(runtime::pad(&runtime::js_string(&a(0)), &a(1), &a(2), true)),
|
|
131
137
|
"pad_end" => JsValue::String(runtime::pad(&runtime::js_string(&a(0)), &a(1), &a(2), false)),
|
|
@@ -169,6 +169,20 @@ fn slice_mutation_isolation_and_clamping() {
|
|
|
169
169
|
assert_eq!(src, arr(vec![s("a"), s("b"), s("c")]));
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/// The `string-slice` divergence (#2182): a string receiver used to
|
|
173
|
+
/// fall through the array-only branch and return an empty array
|
|
174
|
+
/// instead of a substring.
|
|
175
|
+
#[test]
|
|
176
|
+
fn slice_string_receiver() {
|
|
177
|
+
let word = s("barefootjs");
|
|
178
|
+
assert_eq!(runtime::slice(&word, &n(0.0), &n(4.0)), s("bare"));
|
|
179
|
+
assert_eq!(runtime::slice(&word, &n(-4.0), &JsValue::Null), s("otjs"));
|
|
180
|
+
assert_eq!(runtime::slice(&word, &n(4.0), &JsValue::Null), s("footjs"));
|
|
181
|
+
assert_eq!(runtime::slice(&word, &n(5.0), &n(2.0)), s(""));
|
|
182
|
+
// Multi-byte: index by character, not byte.
|
|
183
|
+
assert_eq!(runtime::slice(&s("héllo"), &n(0.0), &n(2.0)), s("hé"));
|
|
184
|
+
}
|
|
185
|
+
|
|
172
186
|
#[test]
|
|
173
187
|
fn reverse_mutation_isolation() {
|
|
174
188
|
assert_eq!(runtime::reverse(&arr(vec![s("a"), s("b"), s("c")])), arr(vec![s("c"), s("b"), s("a")]));
|
|
@@ -192,6 +206,34 @@ fn trim_helper() {
|
|
|
192
206
|
assert_eq!(runtime::trim(&n(42.0)), "42");
|
|
193
207
|
}
|
|
194
208
|
|
|
209
|
+
#[test]
|
|
210
|
+
fn trim_start_and_trim_end_helpers() {
|
|
211
|
+
// The one-sided siblings of `trim` above (#2183 follow-up). Padding
|
|
212
|
+
// BOTH sides of the flagship input so a swapped side (or a
|
|
213
|
+
// routed-through-both-sides regression) fails visibly.
|
|
214
|
+
assert_eq!(runtime::trim_start(&s(" padded ")), "padded ");
|
|
215
|
+
assert_eq!(runtime::trim_end(&s(" padded ")), " padded");
|
|
216
|
+
|
|
217
|
+
assert_eq!(runtime::trim_start(&s("\t\nleading")), "leading");
|
|
218
|
+
assert_eq!(runtime::trim_end(&s("trailing ")), "trailing");
|
|
219
|
+
|
|
220
|
+
assert_eq!(runtime::trim_start(&s("no-pad")), "no-pad");
|
|
221
|
+
assert_eq!(runtime::trim_end(&s("no-pad")), "no-pad");
|
|
222
|
+
|
|
223
|
+
assert_eq!(runtime::trim_start(&s(" ")), "");
|
|
224
|
+
assert_eq!(runtime::trim_end(&s(" ")), "");
|
|
225
|
+
|
|
226
|
+
assert_eq!(runtime::trim_start(&s("")), "");
|
|
227
|
+
assert_eq!(runtime::trim_end(&s("")), "");
|
|
228
|
+
|
|
229
|
+
assert_eq!(runtime::trim_start(&JsValue::Null), "");
|
|
230
|
+
assert_eq!(runtime::trim_end(&JsValue::Null), "");
|
|
231
|
+
assert_eq!(runtime::trim_start(&obj(&[("a", n(1.0))])), "");
|
|
232
|
+
assert_eq!(runtime::trim_end(&obj(&[("a", n(1.0))])), "");
|
|
233
|
+
assert_eq!(runtime::trim_start(&n(42.0)), "42");
|
|
234
|
+
assert_eq!(runtime::trim_end(&n(42.0)), "42");
|
|
235
|
+
}
|
|
236
|
+
|
|
195
237
|
#[test]
|
|
196
238
|
fn split_helper() {
|
|
197
239
|
assert_eq!(runtime::split(&s("a,b,c"), Some(&s(",")), None), arr(vec![s("a"), s("b"), s("c")]));
|
|
@@ -385,6 +385,27 @@ export function C(props: { count: number }) {
|
|
|
385
385
|
})
|
|
386
386
|
})
|
|
387
387
|
|
|
388
|
+
describe('MinijinjaAdapter - named-slot capture identifier safety (#2168 jsx-element-prop)', () => {
|
|
389
|
+
// A JSX-valued prop under a hyphenated name (`data-slot`, a valid JSX
|
|
390
|
+
// attribute name) must not leak into the `{% set %}` capture variable's
|
|
391
|
+
// identifier — minijinja variable names can't contain `-`. The capture
|
|
392
|
+
// identifier is purely counter-based (never derived from the prop name);
|
|
393
|
+
// the hash KEY passed to `render_child` still carries the real name,
|
|
394
|
+
// quoted via `minijinjaHashKey`.
|
|
395
|
+
test('a hyphenated prop name does not appear in the capture variable', () => {
|
|
396
|
+
const { template } = compileAndGenerate(`
|
|
397
|
+
function Card(props) { return null }
|
|
398
|
+
export function Parent() {
|
|
399
|
+
return <Card data-slot={<strong>Title</strong>}>text</Card>
|
|
400
|
+
}
|
|
401
|
+
`)
|
|
402
|
+
expect(template).toContain('{% set bf_prop_0 %}')
|
|
403
|
+
expect(template).toContain("'data-slot': bf_prop_0")
|
|
404
|
+
expect(template).not.toContain('data-slot %}')
|
|
405
|
+
expect(template).not.toContain('data-slot_')
|
|
406
|
+
})
|
|
407
|
+
})
|
|
408
|
+
|
|
388
409
|
// #2038 nested-callback-predicate loudness is pinned at the shared
|
|
389
410
|
// conformance layer (workstream C): `filter-nested-callback-predicate` /
|
|
390
411
|
// `filter-nested-find-predicate` (BF101 via `expectedDiagnostics`) and
|
|
@@ -91,6 +91,15 @@ export function renderArrayMethod(
|
|
|
91
91
|
const recv = emit(object)
|
|
92
92
|
return `bf.trim(${recv})`
|
|
93
93
|
}
|
|
94
|
+
case 'trimStart':
|
|
95
|
+
case 'trimEnd': {
|
|
96
|
+
// `.trimStart()` / `.trimEnd()` — the one-sided siblings of
|
|
97
|
+
// `.trim()` (#2183 follow-up). Dedicated `bf.trim_start` /
|
|
98
|
+
// `bf.trim_end` helpers, not `bf.trim` with a flag.
|
|
99
|
+
const fn = method === 'trimStart' ? 'trim_start' : 'trim_end'
|
|
100
|
+
const recv = emit(object)
|
|
101
|
+
return `bf.${fn}(${recv})`
|
|
102
|
+
}
|
|
94
103
|
case 'toFixed': {
|
|
95
104
|
// `.toFixed(digits?)` — `bf.to_fixed` mirrors JS rounding +
|
|
96
105
|
// zero-padding (default 0 digits). #1897.
|
|
@@ -126,6 +135,16 @@ export function renderArrayMethod(
|
|
|
126
135
|
const newS = emit(args[1])
|
|
127
136
|
return `bf.replace(${recv}, ${oldS}, ${newS})`
|
|
128
137
|
}
|
|
138
|
+
case 'replaceAll': {
|
|
139
|
+
// `.replaceAll(old, new)` — string-pattern form, EVERY occurrence,
|
|
140
|
+
// via the dedicated `bf.replace_all` helper (not `bf.replace`
|
|
141
|
+
// with a flag) — the regex-pattern form is refused upstream at
|
|
142
|
+
// the parser, same as `.replace`. See #2182.
|
|
143
|
+
const recv = emit(object)
|
|
144
|
+
const oldS = emit(args[0])
|
|
145
|
+
const newS = emit(args[1])
|
|
146
|
+
return `bf.replace_all(${recv}, ${oldS}, ${newS})`
|
|
147
|
+
}
|
|
129
148
|
case 'repeat': {
|
|
130
149
|
const recv = emit(object)
|
|
131
150
|
const count = args.length === 0 ? '0' : emit(args[0])
|
|
@@ -141,7 +141,7 @@ export class JinjaFilterEmitter implements ParsedExprEmitter {
|
|
|
141
141
|
return String(value)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string {
|
|
144
|
+
member(object: ParsedExpr, property: string, _computed: boolean, _optional: boolean, emit: (e: ParsedExpr) => string): string {
|
|
145
145
|
// `.length` — route through `bf.length` (handles both array element
|
|
146
146
|
// count and string char count, JS-compatibly). Jinja's builtin
|
|
147
147
|
// `|length` filter also faults trying to match JS semantics for every
|
|
@@ -313,7 +313,7 @@ export class JinjaTopLevelEmitter implements ParsedExprEmitter {
|
|
|
313
313
|
return String(value)
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string {
|
|
316
|
+
member(object: ParsedExpr, property: string, _computed: boolean, _optional: boolean, emit: (e: ParsedExpr) => string): string {
|
|
317
317
|
// `props.x` flattens to the bare context var the SSR caller binds each
|
|
318
318
|
// prop to (props arrive as individual top-level context entries, not a
|
|
319
319
|
// nested `props` dict).
|
|
@@ -26,6 +26,9 @@ export const JINJA_TEMPLATE_PRIMITIVES: Record<string, PrimitiveSpec> = {
|
|
|
26
26
|
'Math.floor': { arity: 1, emit: (args) => `bf.floor(${args[0]})` },
|
|
27
27
|
'Math.ceil': { arity: 1, emit: (args) => `bf.ceil(${args[0]})` },
|
|
28
28
|
'Math.round': { arity: 1, emit: (args) => `bf.round(${args[0]})` },
|
|
29
|
+
'Math.min': { arity: 2, emit: (args) => `bf.min(${args[0]}, ${args[1]})` },
|
|
30
|
+
'Math.max': { arity: 2, emit: (args) => `bf.max(${args[0]}, ${args[1]})` },
|
|
31
|
+
'Math.abs': { arity: 1, emit: (args) => `bf.abs(${args[0]})` },
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
/**
|
|
@@ -168,7 +168,7 @@ import {
|
|
|
168
168
|
} from '@barefootjs/jsx'
|
|
169
169
|
import { isAriaBooleanAttr, isBooleanResultExpr, isExplicitStringCall } from './boolean-result.ts'
|
|
170
170
|
import type { ParsedExpr, LoweringMatcher, LoopBindingPathSegment } from '@barefootjs/jsx'
|
|
171
|
-
import { BF_SLOT, BF_COND, BF_REGION } from '@barefootjs/shared'
|
|
171
|
+
import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from '@barefootjs/shared'
|
|
172
172
|
|
|
173
173
|
import type { JinjaRenderCtx } from './lib/types.ts'
|
|
174
174
|
import { JINJA_PRIMITIVE_EMIT_MAP } from './lib/constants.ts'
|
|
@@ -254,6 +254,14 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
254
254
|
private options: Required<MinijinjaAdapterOptions>
|
|
255
255
|
private errors: CompilerError[] = []
|
|
256
256
|
private inLoop: boolean = false
|
|
257
|
+
/**
|
|
258
|
+
* `IRLoop.depth` of the loop currently being rendered (save/restore
|
|
259
|
+
* around `renderChildren(loop.children)`, mirroring `inLoop` above).
|
|
260
|
+
* `renderAttributes` reads this to derive the `key` → `data-key`/
|
|
261
|
+
* `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
|
|
262
|
+
* re-derived here (#2168 nested-loop-outer-binding).
|
|
263
|
+
*/
|
|
264
|
+
private currentLoopKeyDepth = 0
|
|
257
265
|
/**
|
|
258
266
|
* SolidJS-style props identifier (`function(props: P)`) and the
|
|
259
267
|
* analyzer-extracted prop names. Stashed at `generate()` entry so the
|
|
@@ -449,7 +457,9 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
449
457
|
}
|
|
450
458
|
|
|
451
459
|
emitText(node: IRText): string {
|
|
452
|
-
|
|
460
|
+
// IRText carries the entity-DECODED value (Phase 1 decodes JSX
|
|
461
|
+
// character references); re-escape for direct HTML emission.
|
|
462
|
+
return escapeHtml(node.value)
|
|
453
463
|
}
|
|
454
464
|
|
|
455
465
|
emitExpression(node: IRExpression): string {
|
|
@@ -810,7 +820,11 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
810
820
|
// adds one `{% set %}` local per binding (`rest` aliases the item so
|
|
811
821
|
// `rest.flag` resolves).
|
|
812
822
|
const indexLocalLines: string[] = []
|
|
813
|
-
if (loop.
|
|
823
|
+
if (loop.objectIteration) {
|
|
824
|
+
// `key`/`value` bind directly in the for-header (see below) via the
|
|
825
|
+
// `|items` filter — no derived `loop.index0` local needed, unlike
|
|
826
|
+
// the array `iterationShape` cases.
|
|
827
|
+
} else if (loop.iterationShape === 'keys') {
|
|
814
828
|
indexLocalLines.push(`{% set ${minijinjaIdent(param)} = loop.index0 %}`)
|
|
815
829
|
} else if (loop.index) {
|
|
816
830
|
indexLocalLines.push(`{% set ${minijinjaIdent(loop.index)} = loop.index0 %}`)
|
|
@@ -843,10 +857,13 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
843
857
|
|
|
844
858
|
const prevInLoop = this.inLoop
|
|
845
859
|
this.inLoop = true
|
|
860
|
+
const prevLoopKeyDepth = this.currentLoopKeyDepth
|
|
861
|
+
this.currentLoopKeyDepth = loop.depth
|
|
846
862
|
// Re-render children now that inLoop is set (so nested components use the
|
|
847
863
|
// loop-child naming convention). renderedChildren above was computed with
|
|
848
864
|
// the previous flag; recompute under the loop flag.
|
|
849
865
|
const childrenUnderLoop = this.renderChildren(loop.children)
|
|
866
|
+
this.currentLoopKeyDepth = prevLoopKeyDepth
|
|
850
867
|
this.inLoop = prevInLoop
|
|
851
868
|
void renderedChildren
|
|
852
869
|
|
|
@@ -863,7 +880,25 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
863
880
|
// Scoped per-call-site marker so sibling `.map()`s under the same parent
|
|
864
881
|
// each get their own reconciliation range.
|
|
865
882
|
lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`)
|
|
866
|
-
|
|
883
|
+
// `objectIteration` (#2168 object-entries-map): minijinja has no
|
|
884
|
+
// built-in `.items()` OBJECT METHOD (unlike Python's dict) — `|items`
|
|
885
|
+
// is a FILTER, yielding `[key, value]` pairs, which the `for` tag's
|
|
886
|
+
// own tuple-unpack target (`for a, b in ...`, mirroring Jinja2) binds
|
|
887
|
+
// directly. There's no `|keys`/`|values` filter, so `'keys'`/`'values'`
|
|
888
|
+
// reuse the SAME `|items` pairs and bind the unused half to a
|
|
889
|
+
// throwaway name. Order is whatever the underlying `BTreeMap` gives —
|
|
890
|
+
// sorted-by-key, not JS insertion order (a deliberate design choice
|
|
891
|
+
// for a DIFFERENT feature, canonical JSON encoding — see `num.rs`);
|
|
892
|
+
// this happens to satisfy the current fixture, but is a documented
|
|
893
|
+
// known limitation for out-of-alphabetical-order data, same as Go.
|
|
894
|
+
const forHeader = loop.objectIteration === 'entries'
|
|
895
|
+
? `{% for ${minijinjaIdent(loop.index ?? param)}, ${minijinjaIdent(param)} in ${array}|items %}`
|
|
896
|
+
: loop.objectIteration === 'keys'
|
|
897
|
+
? `{% for ${minijinjaIdent(param)}, __bf_v in ${array}|items %}`
|
|
898
|
+
: loop.objectIteration === 'values'
|
|
899
|
+
? `{% for __bf_k, ${minijinjaIdent(param)} in ${array}|items %}`
|
|
900
|
+
: `{% for ${minijinjaIdent(loopVar)} in ${array} %}`
|
|
901
|
+
lines.push(forHeader)
|
|
867
902
|
for (const il of indexLocalLines) lines.push(il)
|
|
868
903
|
|
|
869
904
|
// Handle filter().map() pattern by wrapping children in if-condition
|
|
@@ -1017,11 +1052,33 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
1017
1052
|
type Segment = { kind: 'entries'; parts: string[] } | { kind: 'spread'; expr: string }
|
|
1018
1053
|
const segments: Segment[] = [{ kind: 'entries', parts: [] }]
|
|
1019
1054
|
const currentEntries = () => this.componentPropSegmentEntries(segments)
|
|
1055
|
+
// Named JSX-valued props OTHER than the reserved `children`
|
|
1056
|
+
// (`header={<strong>Title</strong>}`, #2168 jsx-element-prop) each get
|
|
1057
|
+
// their own `{% set %}` capture, prepended to the final returned
|
|
1058
|
+
// string below — same mechanism as the reserved children capture,
|
|
1059
|
+
// just keyed by the prop's own name instead of `children`.
|
|
1060
|
+
const namedSlotSetBlocks: string[] = []
|
|
1020
1061
|
|
|
1021
1062
|
for (const p of comp.props) {
|
|
1022
1063
|
// Skip callback props (onXxx) and `ref` — both are client-only for
|
|
1023
1064
|
// SSR (Hono renders neither; the client JS wires them at hydration).
|
|
1024
1065
|
if ((p.name.match(/^on[A-Z]/) || p.name === 'ref') && p.value.kind === 'expression') continue
|
|
1066
|
+
if (p.value.kind === 'jsx-children' && p.name !== 'children') {
|
|
1067
|
+
const prevInLoop = this.inLoop
|
|
1068
|
+
this.inLoop = false
|
|
1069
|
+
const slotBody = this.renderChildren(p.value.children)
|
|
1070
|
+
this.inLoop = prevInLoop
|
|
1071
|
+
// Purely counter-based — NOT derived from `p.name` or `comp.slotId`.
|
|
1072
|
+
// A JSX prop name can contain characters (`data-slot`) that aren't a
|
|
1073
|
+
// valid minijinja `{% set %}` target, and `comp.slotId` alone would
|
|
1074
|
+
// collide across two named-slot props on the same component
|
|
1075
|
+
// invocation (unlike the reserved children slot, there's only ever
|
|
1076
|
+
// one of those per invocation).
|
|
1077
|
+
const captureName = `bf_prop_${this.childrenCaptureCounter++}`
|
|
1078
|
+
namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`)
|
|
1079
|
+
currentEntries().push(`${minijinjaHashKey(p.name)}: ${captureName}`)
|
|
1080
|
+
continue
|
|
1081
|
+
}
|
|
1025
1082
|
if (p.value.kind === 'spread') {
|
|
1026
1083
|
const trimmed = p.value.expr.trim()
|
|
1027
1084
|
// SolidJS-style props identifier (`function(props: P)`) has no
|
|
@@ -1085,12 +1142,12 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
1085
1142
|
const captureName = `bf_children_${comp.slotId ?? 'c' + this.childrenCaptureCounter++}`
|
|
1086
1143
|
currentEntries().push(`${minijinjaHashKey('children')}: ${captureName}`)
|
|
1087
1144
|
const dict = this.combineComponentPropSegments(segments)
|
|
1088
|
-
return
|
|
1145
|
+
return `${namedSlotSetBlocks.join('')}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`
|
|
1089
1146
|
}
|
|
1090
1147
|
|
|
1091
1148
|
const isEmpty = segments.every(s => s.kind === 'entries' && s.parts.length === 0)
|
|
1092
1149
|
const dictEntries = isEmpty ? '' : `, ${this.combineComponentPropSegments(segments)}`
|
|
1093
|
-
return
|
|
1150
|
+
return `${namedSlotSetBlocks.join('')}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`
|
|
1094
1151
|
}
|
|
1095
1152
|
|
|
1096
1153
|
private childrenCaptureCounter = 0
|
|
@@ -1175,7 +1232,7 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
1175
1232
|
* AttrValue lowering for intrinsic-element attributes (Jinja).
|
|
1176
1233
|
*/
|
|
1177
1234
|
private readonly elementAttrEmitter: AttrValueEmitter = {
|
|
1178
|
-
emitLiteral: (value, name) => `${name}="${value.value}"`,
|
|
1235
|
+
emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
|
|
1179
1236
|
emitExpression: (value, name) => {
|
|
1180
1237
|
// `style={{ … }}` object literal → a CSS string with dynamic values
|
|
1181
1238
|
// interpolated, instead of refusing the bare object with BF101 (#1322).
|
|
@@ -1380,7 +1437,10 @@ export class MinijinjaAdapter extends BaseAdapter implements IRNodeEmitter<Jinja
|
|
|
1380
1437
|
// Rewrite JSX special-prop names to their HTML-attribute counterparts.
|
|
1381
1438
|
let attrName: string
|
|
1382
1439
|
if (attr.name === 'className') attrName = 'class'
|
|
1383
|
-
else if (attr.name === 'key')
|
|
1440
|
+
else if (attr.name === 'key') {
|
|
1441
|
+
const depth = this.currentLoopKeyDepth
|
|
1442
|
+
attrName = depth > 0 ? `data-key-${depth}` : 'data-key'
|
|
1443
|
+
}
|
|
1384
1444
|
else attrName = attr.name
|
|
1385
1445
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName)
|
|
1386
1446
|
if (lowered) parts.push(lowered)
|
package/src/conformance-pins.ts
CHANGED
|
@@ -104,9 +104,4 @@ export const conformancePins: ConformancePins = {
|
|
|
104
104
|
// the shape loudly instead of emitting entity-escaped markup that
|
|
105
105
|
// silently renders tags as text.
|
|
106
106
|
'dangerous-inner-html': [{ code: 'BF101', severity: 'error' }],
|
|
107
|
-
// Edge-case sweep (Priority 12): `.replaceAll` has no lowering yet —
|
|
108
|
-
// only first-occurrence `.replace` is wired to the runtime helpers.
|
|
109
|
-
// Refused with BF101 rather than reusing the first-only lowering,
|
|
110
|
-
// which would silently change semantics.
|
|
111
|
-
'string-replaceall': [{ code: 'BF101', severity: 'error' }],
|
|
112
107
|
}
|
|
@@ -16,21 +16,4 @@
|
|
|
16
16
|
|
|
17
17
|
import type { RenderDivergences } from '@barefootjs/jsx'
|
|
18
18
|
|
|
19
|
-
export const renderDivergences: RenderDivergences = {
|
|
20
|
-
'html-entity-text':
|
|
21
|
-
'`©` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes',
|
|
22
|
-
'math-methods':
|
|
23
|
-
'Math.min/max/abs over a signal render empty (only Math.floor is in the template-primitive registry)',
|
|
24
|
-
'static-attr-escape':
|
|
25
|
-
'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
|
|
26
|
-
'object-entries-map':
|
|
27
|
-
'`Object.entries(prop).map(([k, v]) => …)` renders an EMPTY list — the object-shaped prop silently produces zero iterations',
|
|
28
|
-
'nested-loop-outer-binding':
|
|
29
|
-
'nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`',
|
|
30
|
-
'jsx-element-prop':
|
|
31
|
-
'a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped',
|
|
32
|
-
'string-slice':
|
|
33
|
-
'`.slice()` on a STRING renders empty (array-slice helper misfires on strings)',
|
|
34
|
-
'string-trim-sided':
|
|
35
|
-
'`.trimStart()` / `.trimEnd()` render empty (no lowering)',
|
|
36
|
-
}
|
|
19
|
+
export const renderDivergences: RenderDivergences = {}
|