@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.
@@ -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,CA6HR;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"}
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":"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"}
1
+ {"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"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"}
@@ -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
- lines.push(`{% for ${minijinjaIdent(loopVar)} in ${array} %}`);
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 `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
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 `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
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
- attrName = "data-key";
188849
- else
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,CAOnE,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAG7E,CAAA"}
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":"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"}
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
- lines.push(`{% for ${minijinjaIdent(loopVar)} in ${array} %}`);
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 `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
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 `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
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
- attrName = "data-key";
188849
- else
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,eAkG7B,CAAA"}
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
- lines.push(`{% for ${minijinjaIdent(loopVar)} in ${array} %}`);
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 `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
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 `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
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
- attrName = "data-key";
188849
- else
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": "`&copy;` 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,iBAiB/B,CAAA"}
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.4",
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.4"
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.4",
64
+ "@barefootjs/jsx": "0.18.5",
65
65
  "typescript": "^5.0.0"
66
66
  }
67
67
  }
@@ -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
@@ -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 mut s = if matches!(start, JsValue::Null) { 0 } else { num::to_f64(start) as i64 };
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
- return node.value
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.iterationShape === 'keys') {
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
- lines.push(`{% for ${minijinjaIdent(loopVar)} in ${array} %}`)
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 `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`
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 `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`
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') attrName = 'data-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)
@@ -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
- '`&copy;` 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 = {}