@barefootjs/jinja 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":"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,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAkB5H;IAED,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAK1F;IAED,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAMpF;IAED,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAI/E;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAc/F;IAED,OAAO,CAAC,EAAE,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAoB5G;IAED,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,EAC9C,SAAS,EAAE,UAAU,EAAE,EACvB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CASR;IAED,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAE5E;IAED,WAAW,CACT,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAAE,EAClB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAER;IAED,UAAU,CACR,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,SAAS,GAAG;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,EACvC,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAER;IAED,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAEtF;IAED,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAE9C;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAElD;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;IAED,aAAa,CAAC,WAAW,EAAE,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAK1G;CACF;AAED;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,YAAW,iBAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG;IAAhC,YAA6B,GAAG,EAAE,gBAAgB,EAAI;IAEtD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc/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,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAyB5H;IAED,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAI1F;IAED,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CA+BpF;IAED,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAI/E;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAa/F;IAED,OAAO,CAAC,EAAE,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAW5G;IAED,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,EAC7C,QAAQ,EAAE,UAAU,EAAE,EACtB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CA2ER;IAED;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IA6B9B,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAE5E;IAED,WAAW,CACT,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAAE,EAClB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAER;IAED,UAAU,CACR,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,SAAS,GAAG;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,EACvC,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAER;IAED,WAAW,CACT,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAC9B,MAAM,CAER;IAED,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAwB9E;IAED,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAMlD;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG1B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;IAED,aAAa,CAAC,UAAU,EAAE,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG,MAAM,CAWzG;CACF"}
@@ -187369,7 +187369,7 @@ function isAriaBooleanAttr(name) {
187369
187369
  }
187370
187370
 
187371
187371
  // src/adapter/jinja-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
 
@@ -187557,6 +187560,12 @@ function renderArrayMethod(method, object, args, emit) {
187557
187560
  const recv = emit(object);
187558
187561
  return `bf.trim(${recv})`;
187559
187562
  }
187563
+ case "trimStart":
187564
+ case "trimEnd": {
187565
+ const fn = method === "trimStart" ? "trim_start" : "trim_end";
187566
+ const recv = emit(object);
187567
+ return `bf.${fn}(${recv})`;
187568
+ }
187560
187569
  case "toFixed": {
187561
187570
  const recv = emit(object);
187562
187571
  const digits = args.length >= 1 ? emit(args[0]) : "0";
@@ -187590,6 +187599,12 @@ function renderArrayMethod(method, object, args, emit) {
187590
187599
  const newS = emit(args[1]);
187591
187600
  return `bf.replace(${recv}, ${oldS}, ${newS})`;
187592
187601
  }
187602
+ case "replaceAll": {
187603
+ const recv = emit(object);
187604
+ const oldS = emit(args[0]);
187605
+ const newS = emit(args[1]);
187606
+ return `bf.replace_all(${recv}, ${oldS}, ${newS})`;
187607
+ }
187593
187608
  case "repeat": {
187594
187609
  const recv = emit(object);
187595
187610
  const count = args.length === 0 ? "0" : emit(args[0]);
@@ -187732,11 +187747,11 @@ class JinjaFilterEmitter {
187732
187747
  return "none";
187733
187748
  return String(value);
187734
187749
  }
187735
- member(object, property, _computed, emit) {
187750
+ member(object, property, _computed, _optional, emit) {
187736
187751
  if (property === "length") {
187737
187752
  return `bf.length(${emit(object)})`;
187738
187753
  }
187739
- return `${emit(object)}.${property}`;
187754
+ return `${emit(object)}['${escapeJinjaSingleQuoted(property)}']`;
187740
187755
  }
187741
187756
  indexAccess(object, index, emit) {
187742
187757
  return `${emit(object)}[${emit(index)}]`;
@@ -187838,7 +187853,7 @@ class JinjaTopLevelEmitter {
187838
187853
  return "none";
187839
187854
  return String(value);
187840
187855
  }
187841
- member(object, property, _computed, emit) {
187856
+ member(object, property, _computed, _optional, emit) {
187842
187857
  if (object.kind === "identifier" && object.name === "props") {
187843
187858
  return jinjaIdent(property);
187844
187859
  }
@@ -187850,7 +187865,7 @@ class JinjaTopLevelEmitter {
187850
187865
  const obj = emit(object);
187851
187866
  if (property === "length")
187852
187867
  return `bf.length(${obj})`;
187853
- return `${obj}.${property}`;
187868
+ return `${obj}['${escapeJinjaSingleQuoted(property)}']`;
187854
187869
  }
187855
187870
  indexAccess(object, index, emit) {
187856
187871
  return `${emit(object)}[${emit(index)}]`;
@@ -188257,6 +188272,7 @@ class JinjaAdapter extends BaseAdapter {
188257
188272
  options;
188258
188273
  errors = [];
188259
188274
  inLoop = false;
188275
+ currentLoopKeyDepth = 0;
188260
188276
  propsObjectName = null;
188261
188277
  propsParams = [];
188262
188278
  booleanTypedProps = new Set;
@@ -188333,7 +188349,7 @@ class JinjaAdapter extends BaseAdapter {
188333
188349
  return this.renderElement(node);
188334
188350
  }
188335
188351
  emitText(node) {
188336
- return node.value;
188352
+ return escapeHtml(node.value);
188337
188353
  }
188338
188354
  emitExpression(node) {
188339
188355
  return this.renderExpression(node);
@@ -188564,7 +188580,7 @@ ${whenTrue}
188564
188580
  const renderedChildren = this.renderChildren(loop.children);
188565
188581
  const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
188566
188582
  const indexLocalLines = [];
188567
- if (loop.iterationShape === "keys") {
188583
+ if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
188568
188584
  indexLocalLines.push(`{% set ${jinjaIdent(param)} = loop.index0 %}`);
188569
188585
  } else if (loop.index) {
188570
188586
  indexLocalLines.push(`{% set ${jinjaIdent(loop.index)} = loop.index0 %}`);
@@ -188584,13 +188600,17 @@ ${whenTrue}
188584
188600
  }
188585
188601
  const prevInLoop = this.inLoop;
188586
188602
  this.inLoop = true;
188603
+ const prevLoopKeyDepth = this.currentLoopKeyDepth;
188604
+ this.currentLoopKeyDepth = loop.depth;
188587
188605
  const childrenUnderLoop = this.renderChildren(loop.children);
188606
+ this.currentLoopKeyDepth = prevLoopKeyDepth;
188588
188607
  this.inLoop = prevInLoop;
188589
188608
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
188590
188609
  ${childrenUnderLoop}` : childrenUnderLoop;
188591
188610
  const lines = [];
188592
188611
  lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`);
188593
- lines.push(`{% for ${jinjaIdent(loopVar)} in ${array} %}`);
188612
+ const forHeader = loop.objectIteration === "entries" ? `{% for ${jinjaIdent(loop.index ?? param)}, ${jinjaIdent(param)} in ${array}.items() %}` : loop.objectIteration === "keys" ? `{% for ${jinjaIdent(param)} in ${array}.keys() %}` : loop.objectIteration === "values" ? `{% for ${jinjaIdent(param)} in ${array}.values() %}` : `{% for ${jinjaIdent(loopVar)} in ${array} %}`;
188613
+ lines.push(forHeader);
188594
188614
  for (const il of indexLocalLines)
188595
188615
  lines.push(il);
188596
188616
  if (loop.filterPredicate) {
@@ -188662,9 +188682,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188662
188682
  renderComponent(comp) {
188663
188683
  const segments = [{ kind: "entries", parts: [] }];
188664
188684
  const currentEntries = () => this.componentPropSegmentEntries(segments);
188685
+ const namedSlotSetBlocks = [];
188665
188686
  for (const p of comp.props) {
188666
188687
  if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
188667
188688
  continue;
188689
+ if (p.value.kind === "jsx-children" && p.name !== "children") {
188690
+ const prevInLoop = this.inLoop;
188691
+ this.inLoop = false;
188692
+ const slotBody = this.renderChildren(p.value.children);
188693
+ this.inLoop = prevInLoop;
188694
+ const captureName = `bf_prop_${this.childrenCaptureCounter++}`;
188695
+ namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`);
188696
+ currentEntries().push(`${jinjaHashKey(p.name)}: ${captureName}`);
188697
+ continue;
188698
+ }
188668
188699
  if (p.value.kind === "spread") {
188669
188700
  const trimmed = p.value.expr.trim();
188670
188701
  if (this.propsObjectName && this.propsObjectName === trimmed) {
@@ -188693,11 +188724,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188693
188724
  const captureName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
188694
188725
  currentEntries().push(`${jinjaHashKey("children")}: ${captureName}`);
188695
188726
  const dict = this.combineComponentPropSegments(segments);
188696
- return `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
188727
+ return `${namedSlotSetBlocks.join("")}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
188697
188728
  }
188698
188729
  const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
188699
188730
  const dictEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
188700
- return `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
188731
+ return `${namedSlotSetBlocks.join("")}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
188701
188732
  }
188702
188733
  childrenCaptureCounter = 0;
188703
188734
  presenceVarCounter = 0;
@@ -188742,7 +188773,7 @@ ${alternate}
188742
188773
  ${children}`;
188743
188774
  }
188744
188775
  elementAttrEmitter = {
188745
- emitLiteral: (value, name) => `${name}="${value.value}"`,
188776
+ emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
188746
188777
  emitExpression: (value, name) => {
188747
188778
  if (name === "style") {
188748
188779
  const css = this.tryLowerStyleObject(value.expr);
@@ -188850,9 +188881,10 @@ ${name}="{{ bf.string(${val}) }}"
188850
188881
  let attrName;
188851
188882
  if (attr.name === "className")
188852
188883
  attrName = "class";
188853
- else if (attr.name === "key")
188854
- attrName = "data-key";
188855
- else
188884
+ else if (attr.name === "key") {
188885
+ const depth = this.currentLoopKeyDepth;
188886
+ attrName = depth > 0 ? `data-key-${depth}` : "data-key";
188887
+ } else
188856
188888
  attrName = attr.name;
188857
188889
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
188858
188890
  if (lowered)
@@ -113,6 +113,14 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
113
113
  private options;
114
114
  private errors;
115
115
  private inLoop;
116
+ /**
117
+ * `IRLoop.depth` of the loop currently being rendered (save/restore
118
+ * around `renderChildren(loop.children)`, mirroring `inLoop` above).
119
+ * `renderAttributes` reads this to derive the `key` → `data-key`/
120
+ * `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
121
+ * re-derived here (#2168 nested-loop-outer-binding).
122
+ */
123
+ private currentLoopKeyDepth;
116
124
  /**
117
125
  * SolidJS-style props identifier (`function(props: P)`) and the
118
126
  * analyzer-extracted prop names. Stashed at `generate()` entry so the
@@ -1 +1 @@
1
- {"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;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;;;;GAIG;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"}
package/dist/build.js CHANGED
@@ -187369,7 +187369,7 @@ function isAriaBooleanAttr(name) {
187369
187369
  }
187370
187370
 
187371
187371
  // src/adapter/jinja-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
 
@@ -187557,6 +187560,12 @@ function renderArrayMethod(method, object, args, emit) {
187557
187560
  const recv = emit(object);
187558
187561
  return `bf.trim(${recv})`;
187559
187562
  }
187563
+ case "trimStart":
187564
+ case "trimEnd": {
187565
+ const fn = method === "trimStart" ? "trim_start" : "trim_end";
187566
+ const recv = emit(object);
187567
+ return `bf.${fn}(${recv})`;
187568
+ }
187560
187569
  case "toFixed": {
187561
187570
  const recv = emit(object);
187562
187571
  const digits = args.length >= 1 ? emit(args[0]) : "0";
@@ -187590,6 +187599,12 @@ function renderArrayMethod(method, object, args, emit) {
187590
187599
  const newS = emit(args[1]);
187591
187600
  return `bf.replace(${recv}, ${oldS}, ${newS})`;
187592
187601
  }
187602
+ case "replaceAll": {
187603
+ const recv = emit(object);
187604
+ const oldS = emit(args[0]);
187605
+ const newS = emit(args[1]);
187606
+ return `bf.replace_all(${recv}, ${oldS}, ${newS})`;
187607
+ }
187593
187608
  case "repeat": {
187594
187609
  const recv = emit(object);
187595
187610
  const count = args.length === 0 ? "0" : emit(args[0]);
@@ -187732,11 +187747,11 @@ class JinjaFilterEmitter {
187732
187747
  return "none";
187733
187748
  return String(value);
187734
187749
  }
187735
- member(object, property, _computed, emit) {
187750
+ member(object, property, _computed, _optional, emit) {
187736
187751
  if (property === "length") {
187737
187752
  return `bf.length(${emit(object)})`;
187738
187753
  }
187739
- return `${emit(object)}.${property}`;
187754
+ return `${emit(object)}['${escapeJinjaSingleQuoted(property)}']`;
187740
187755
  }
187741
187756
  indexAccess(object, index, emit) {
187742
187757
  return `${emit(object)}[${emit(index)}]`;
@@ -187838,7 +187853,7 @@ class JinjaTopLevelEmitter {
187838
187853
  return "none";
187839
187854
  return String(value);
187840
187855
  }
187841
- member(object, property, _computed, emit) {
187856
+ member(object, property, _computed, _optional, emit) {
187842
187857
  if (object.kind === "identifier" && object.name === "props") {
187843
187858
  return jinjaIdent(property);
187844
187859
  }
@@ -187850,7 +187865,7 @@ class JinjaTopLevelEmitter {
187850
187865
  const obj = emit(object);
187851
187866
  if (property === "length")
187852
187867
  return `bf.length(${obj})`;
187853
- return `${obj}.${property}`;
187868
+ return `${obj}['${escapeJinjaSingleQuoted(property)}']`;
187854
187869
  }
187855
187870
  indexAccess(object, index, emit) {
187856
187871
  return `${emit(object)}[${emit(index)}]`;
@@ -188257,6 +188272,7 @@ class JinjaAdapter extends BaseAdapter {
188257
188272
  options;
188258
188273
  errors = [];
188259
188274
  inLoop = false;
188275
+ currentLoopKeyDepth = 0;
188260
188276
  propsObjectName = null;
188261
188277
  propsParams = [];
188262
188278
  booleanTypedProps = new Set;
@@ -188333,7 +188349,7 @@ class JinjaAdapter extends BaseAdapter {
188333
188349
  return this.renderElement(node);
188334
188350
  }
188335
188351
  emitText(node) {
188336
- return node.value;
188352
+ return escapeHtml(node.value);
188337
188353
  }
188338
188354
  emitExpression(node) {
188339
188355
  return this.renderExpression(node);
@@ -188564,7 +188580,7 @@ ${whenTrue}
188564
188580
  const renderedChildren = this.renderChildren(loop.children);
188565
188581
  const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
188566
188582
  const indexLocalLines = [];
188567
- if (loop.iterationShape === "keys") {
188583
+ if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
188568
188584
  indexLocalLines.push(`{% set ${jinjaIdent(param)} = loop.index0 %}`);
188569
188585
  } else if (loop.index) {
188570
188586
  indexLocalLines.push(`{% set ${jinjaIdent(loop.index)} = loop.index0 %}`);
@@ -188584,13 +188600,17 @@ ${whenTrue}
188584
188600
  }
188585
188601
  const prevInLoop = this.inLoop;
188586
188602
  this.inLoop = true;
188603
+ const prevLoopKeyDepth = this.currentLoopKeyDepth;
188604
+ this.currentLoopKeyDepth = loop.depth;
188587
188605
  const childrenUnderLoop = this.renderChildren(loop.children);
188606
+ this.currentLoopKeyDepth = prevLoopKeyDepth;
188588
188607
  this.inLoop = prevInLoop;
188589
188608
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
188590
188609
  ${childrenUnderLoop}` : childrenUnderLoop;
188591
188610
  const lines = [];
188592
188611
  lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`);
188593
- lines.push(`{% for ${jinjaIdent(loopVar)} in ${array} %}`);
188612
+ const forHeader = loop.objectIteration === "entries" ? `{% for ${jinjaIdent(loop.index ?? param)}, ${jinjaIdent(param)} in ${array}.items() %}` : loop.objectIteration === "keys" ? `{% for ${jinjaIdent(param)} in ${array}.keys() %}` : loop.objectIteration === "values" ? `{% for ${jinjaIdent(param)} in ${array}.values() %}` : `{% for ${jinjaIdent(loopVar)} in ${array} %}`;
188613
+ lines.push(forHeader);
188594
188614
  for (const il of indexLocalLines)
188595
188615
  lines.push(il);
188596
188616
  if (loop.filterPredicate) {
@@ -188662,9 +188682,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188662
188682
  renderComponent(comp) {
188663
188683
  const segments = [{ kind: "entries", parts: [] }];
188664
188684
  const currentEntries = () => this.componentPropSegmentEntries(segments);
188685
+ const namedSlotSetBlocks = [];
188665
188686
  for (const p of comp.props) {
188666
188687
  if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
188667
188688
  continue;
188689
+ if (p.value.kind === "jsx-children" && p.name !== "children") {
188690
+ const prevInLoop = this.inLoop;
188691
+ this.inLoop = false;
188692
+ const slotBody = this.renderChildren(p.value.children);
188693
+ this.inLoop = prevInLoop;
188694
+ const captureName = `bf_prop_${this.childrenCaptureCounter++}`;
188695
+ namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`);
188696
+ currentEntries().push(`${jinjaHashKey(p.name)}: ${captureName}`);
188697
+ continue;
188698
+ }
188668
188699
  if (p.value.kind === "spread") {
188669
188700
  const trimmed = p.value.expr.trim();
188670
188701
  if (this.propsObjectName && this.propsObjectName === trimmed) {
@@ -188693,11 +188724,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188693
188724
  const captureName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
188694
188725
  currentEntries().push(`${jinjaHashKey("children")}: ${captureName}`);
188695
188726
  const dict = this.combineComponentPropSegments(segments);
188696
- return `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
188727
+ return `${namedSlotSetBlocks.join("")}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
188697
188728
  }
188698
188729
  const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
188699
188730
  const dictEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
188700
- return `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
188731
+ return `${namedSlotSetBlocks.join("")}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
188701
188732
  }
188702
188733
  childrenCaptureCounter = 0;
188703
188734
  presenceVarCounter = 0;
@@ -188742,7 +188773,7 @@ ${alternate}
188742
188773
  ${children}`;
188743
188774
  }
188744
188775
  elementAttrEmitter = {
188745
- emitLiteral: (value, name) => `${name}="${value.value}"`,
188776
+ emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
188746
188777
  emitExpression: (value, name) => {
188747
188778
  if (name === "style") {
188748
188779
  const css = this.tryLowerStyleObject(value.expr);
@@ -188850,9 +188881,10 @@ ${name}="{{ bf.string(${val}) }}"
188850
188881
  let attrName;
188851
188882
  if (attr.name === "className")
188852
188883
  attrName = "class";
188853
- else if (attr.name === "key")
188854
- attrName = "data-key";
188855
- else
188884
+ else if (attr.name === "key") {
188885
+ const depth = this.currentLoopKeyDepth;
188886
+ attrName = depth > 0 ? `data-key-${depth}` : "data-key";
188887
+ } else
188856
188888
  attrName = attr.name;
188857
188889
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
188858
188890
  if (lowered)
@@ -1 +1 @@
1
- {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAmG7B,CAAA"}
1
+ {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eA8F7B,CAAA"}
package/dist/index.js CHANGED
@@ -187369,7 +187369,7 @@ function isAriaBooleanAttr(name) {
187369
187369
  }
187370
187370
 
187371
187371
  // src/adapter/jinja-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
 
@@ -187557,6 +187560,12 @@ function renderArrayMethod(method, object, args, emit) {
187557
187560
  const recv = emit(object);
187558
187561
  return `bf.trim(${recv})`;
187559
187562
  }
187563
+ case "trimStart":
187564
+ case "trimEnd": {
187565
+ const fn = method === "trimStart" ? "trim_start" : "trim_end";
187566
+ const recv = emit(object);
187567
+ return `bf.${fn}(${recv})`;
187568
+ }
187560
187569
  case "toFixed": {
187561
187570
  const recv = emit(object);
187562
187571
  const digits = args.length >= 1 ? emit(args[0]) : "0";
@@ -187590,6 +187599,12 @@ function renderArrayMethod(method, object, args, emit) {
187590
187599
  const newS = emit(args[1]);
187591
187600
  return `bf.replace(${recv}, ${oldS}, ${newS})`;
187592
187601
  }
187602
+ case "replaceAll": {
187603
+ const recv = emit(object);
187604
+ const oldS = emit(args[0]);
187605
+ const newS = emit(args[1]);
187606
+ return `bf.replace_all(${recv}, ${oldS}, ${newS})`;
187607
+ }
187593
187608
  case "repeat": {
187594
187609
  const recv = emit(object);
187595
187610
  const count = args.length === 0 ? "0" : emit(args[0]);
@@ -187732,11 +187747,11 @@ class JinjaFilterEmitter {
187732
187747
  return "none";
187733
187748
  return String(value);
187734
187749
  }
187735
- member(object, property, _computed, emit) {
187750
+ member(object, property, _computed, _optional, emit) {
187736
187751
  if (property === "length") {
187737
187752
  return `bf.length(${emit(object)})`;
187738
187753
  }
187739
- return `${emit(object)}.${property}`;
187754
+ return `${emit(object)}['${escapeJinjaSingleQuoted(property)}']`;
187740
187755
  }
187741
187756
  indexAccess(object, index, emit) {
187742
187757
  return `${emit(object)}[${emit(index)}]`;
@@ -187838,7 +187853,7 @@ class JinjaTopLevelEmitter {
187838
187853
  return "none";
187839
187854
  return String(value);
187840
187855
  }
187841
- member(object, property, _computed, emit) {
187856
+ member(object, property, _computed, _optional, emit) {
187842
187857
  if (object.kind === "identifier" && object.name === "props") {
187843
187858
  return jinjaIdent(property);
187844
187859
  }
@@ -187850,7 +187865,7 @@ class JinjaTopLevelEmitter {
187850
187865
  const obj = emit(object);
187851
187866
  if (property === "length")
187852
187867
  return `bf.length(${obj})`;
187853
- return `${obj}.${property}`;
187868
+ return `${obj}['${escapeJinjaSingleQuoted(property)}']`;
187854
187869
  }
187855
187870
  indexAccess(object, index, emit) {
187856
187871
  return `${emit(object)}[${emit(index)}]`;
@@ -188257,6 +188272,7 @@ class JinjaAdapter extends BaseAdapter {
188257
188272
  options;
188258
188273
  errors = [];
188259
188274
  inLoop = false;
188275
+ currentLoopKeyDepth = 0;
188260
188276
  propsObjectName = null;
188261
188277
  propsParams = [];
188262
188278
  booleanTypedProps = new Set;
@@ -188333,7 +188349,7 @@ class JinjaAdapter extends BaseAdapter {
188333
188349
  return this.renderElement(node);
188334
188350
  }
188335
188351
  emitText(node) {
188336
- return node.value;
188352
+ return escapeHtml(node.value);
188337
188353
  }
188338
188354
  emitExpression(node) {
188339
188355
  return this.renderExpression(node);
@@ -188564,7 +188580,7 @@ ${whenTrue}
188564
188580
  const renderedChildren = this.renderChildren(loop.children);
188565
188581
  const loopVar = loop.iterationShape === "keys" ? "__bf_item" : supportableDestructure ? "__bf_item" : param;
188566
188582
  const indexLocalLines = [];
188567
- if (loop.iterationShape === "keys") {
188583
+ if (loop.objectIteration) {} else if (loop.iterationShape === "keys") {
188568
188584
  indexLocalLines.push(`{% set ${jinjaIdent(param)} = loop.index0 %}`);
188569
188585
  } else if (loop.index) {
188570
188586
  indexLocalLines.push(`{% set ${jinjaIdent(loop.index)} = loop.index0 %}`);
@@ -188584,13 +188600,17 @@ ${whenTrue}
188584
188600
  }
188585
188601
  const prevInLoop = this.inLoop;
188586
188602
  this.inLoop = true;
188603
+ const prevLoopKeyDepth = this.currentLoopKeyDepth;
188604
+ this.currentLoopKeyDepth = loop.depth;
188587
188605
  const childrenUnderLoop = this.renderChildren(loop.children);
188606
+ this.currentLoopKeyDepth = prevLoopKeyDepth;
188588
188607
  this.inLoop = prevInLoop;
188589
188608
  const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.string(${this.convertExpressionToJinja(loop.key)})) | safe }}
188590
188609
  ${childrenUnderLoop}` : childrenUnderLoop;
188591
188610
  const lines = [];
188592
188611
  lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`);
188593
- lines.push(`{% for ${jinjaIdent(loopVar)} in ${array} %}`);
188612
+ const forHeader = loop.objectIteration === "entries" ? `{% for ${jinjaIdent(loop.index ?? param)}, ${jinjaIdent(param)} in ${array}.items() %}` : loop.objectIteration === "keys" ? `{% for ${jinjaIdent(param)} in ${array}.keys() %}` : loop.objectIteration === "values" ? `{% for ${jinjaIdent(param)} in ${array}.values() %}` : `{% for ${jinjaIdent(loopVar)} in ${array} %}`;
188613
+ lines.push(forHeader);
188594
188614
  for (const il of indexLocalLines)
188595
188615
  lines.push(il);
188596
188616
  if (loop.filterPredicate) {
@@ -188662,9 +188682,20 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188662
188682
  renderComponent(comp) {
188663
188683
  const segments = [{ kind: "entries", parts: [] }];
188664
188684
  const currentEntries = () => this.componentPropSegmentEntries(segments);
188685
+ const namedSlotSetBlocks = [];
188665
188686
  for (const p of comp.props) {
188666
188687
  if ((p.name.match(/^on[A-Z]/) || p.name === "ref") && p.value.kind === "expression")
188667
188688
  continue;
188689
+ if (p.value.kind === "jsx-children" && p.name !== "children") {
188690
+ const prevInLoop = this.inLoop;
188691
+ this.inLoop = false;
188692
+ const slotBody = this.renderChildren(p.value.children);
188693
+ this.inLoop = prevInLoop;
188694
+ const captureName = `bf_prop_${this.childrenCaptureCounter++}`;
188695
+ namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`);
188696
+ currentEntries().push(`${jinjaHashKey(p.name)}: ${captureName}`);
188697
+ continue;
188698
+ }
188668
188699
  if (p.value.kind === "spread") {
188669
188700
  const trimmed = p.value.expr.trim();
188670
188701
  if (this.propsObjectName && this.propsObjectName === trimmed) {
@@ -188693,11 +188724,11 @@ ${childrenUnderLoop}` : childrenUnderLoop;
188693
188724
  const captureName = `bf_children_${comp.slotId ?? "c" + this.childrenCaptureCounter++}`;
188694
188725
  currentEntries().push(`${jinjaHashKey("children")}: ${captureName}`);
188695
188726
  const dict = this.combineComponentPropSegments(segments);
188696
- return `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
188727
+ return `${namedSlotSetBlocks.join("")}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`;
188697
188728
  }
188698
188729
  const isEmpty = segments.every((s) => s.kind === "entries" && s.parts.length === 0);
188699
188730
  const dictEntries = isEmpty ? "" : `, ${this.combineComponentPropSegments(segments)}`;
188700
- return `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
188731
+ return `${namedSlotSetBlocks.join("")}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`;
188701
188732
  }
188702
188733
  childrenCaptureCounter = 0;
188703
188734
  presenceVarCounter = 0;
@@ -188742,7 +188773,7 @@ ${alternate}
188742
188773
  ${children}`;
188743
188774
  }
188744
188775
  elementAttrEmitter = {
188745
- emitLiteral: (value, name) => `${name}="${value.value}"`,
188776
+ emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
188746
188777
  emitExpression: (value, name) => {
188747
188778
  if (name === "style") {
188748
188779
  const css = this.tryLowerStyleObject(value.expr);
@@ -188850,9 +188881,10 @@ ${name}="{{ bf.string(${val}) }}"
188850
188881
  let attrName;
188851
188882
  if (attr.name === "className")
188852
188883
  attrName = "class";
188853
- else if (attr.name === "key")
188854
- attrName = "data-key";
188855
- else
188884
+ else if (attr.name === "key") {
188885
+ const depth = this.currentLoopKeyDepth;
188886
+ attrName = depth > 0 ? `data-key-${depth}` : "data-key";
188887
+ } else
188856
188888
  attrName = attr.name;
188857
188889
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
188858
188890
  if (lowered)
@@ -189111,20 +189143,10 @@ var conformancePins = {
189111
189143
  { code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
189112
189144
  ],
189113
189145
  "array-map-function-reference": [{ code: "BF101", severity: "error" }],
189114
- "dangerous-inner-html": [{ code: "BF101", severity: "error" }],
189115
- "string-replaceall": [{ code: "BF101", severity: "error" }]
189146
+ "dangerous-inner-html": [{ code: "BF101", severity: "error" }]
189116
189147
  };
189117
189148
  // src/render-divergences.ts
189118
- var renderDivergences = {
189119
- "html-entity-text": "`&copy;` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes",
189120
- "math-methods": "Math.min/max/abs over a signal render empty (only Math.floor is in the template-primitive registry)",
189121
- "static-attr-escape": 'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
189122
- "object-entries-map": "`Object.entries(prop).map(([k, v]) => …)` renders an EMPTY list — the object-shaped prop silently produces zero iterations",
189123
- "nested-loop-outer-binding": "nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`",
189124
- "jsx-element-prop": "a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped",
189125
- "string-slice": "`.slice()` on a STRING renders empty (array-slice helper misfires on strings)",
189126
- "string-trim-sided": "`.trimStart()` / `.trimEnd()` render empty (no lowering)"
189127
- };
189149
+ var renderDivergences = {};
189128
189150
  export {
189129
189151
  renderDivergences,
189130
189152
  jinjaAdapter,
@@ -1 +1 @@
1
- {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAiB/B,CAAA"}
1
+ {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAAsB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/jinja",
3
- "version": "0.18.4",
3
+ "version": "0.18.5",
4
4
  "description": "Jinja2 adapter for BarefootJS — compiles IR to .jinja templates and ships the Python BarefootJS rendering runtime; runs under any Python web framework (Flask, etc.)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,14 +53,14 @@
53
53
  "directory": "packages/adapter-jinja"
54
54
  },
55
55
  "dependencies": {
56
- "@barefootjs/shared": "0.18.4"
56
+ "@barefootjs/shared": "0.18.5"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@barefootjs/jsx": ">=0.2.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@barefootjs/adapter-tests": "0.1.0",
63
- "@barefootjs/jsx": "0.18.4",
63
+ "@barefootjs/jsx": "0.18.5",
64
64
  "typescript": "^5.0.0"
65
65
  }
66
66
  }
@@ -819,6 +819,29 @@ class BarefootJS:
819
819
  # is -1, not -2). `floor(n + 0.5)` reproduces that for both signs.
820
820
  return float(math.floor(n + 0.5))
821
821
 
822
+ def min(self, a: Any, b: Any) -> float:
823
+ """`Math.min(a, b)` -- two-arg form only (#2168 math-methods).
824
+ JS returns NaN if either operand is NaN."""
825
+ x, y = js_number(a), js_number(b)
826
+ if _is_nan(x):
827
+ return x
828
+ if _is_nan(y):
829
+ return y
830
+ return x if x < y else y
831
+
832
+ def max(self, a: Any, b: Any) -> float:
833
+ x, y = js_number(a), js_number(b)
834
+ if _is_nan(x):
835
+ return x
836
+ if _is_nan(y):
837
+ return y
838
+ return x if x > y else y
839
+
840
+ def abs(self, value: Any) -> float:
841
+ """`Math.abs()` (#2168 math-methods)."""
842
+ n = js_number(value)
843
+ return n if _is_nan(n) else abs(n)
844
+
822
845
  # -----------------------------------------------------------------
823
846
  # Array / String method helpers (#1448 Tier A)
824
847
  # -----------------------------------------------------------------
@@ -933,12 +956,20 @@ class BarefootJS:
933
956
  out.extend(b)
934
957
  return out
935
958
 
936
- def slice(self, recv: Any, start: Any, end: Any) -> list:
937
- if not isinstance(recv, list):
959
+ def slice(self, recv: Any, start: Any, end: Any) -> Any:
960
+ # `Array.prototype.slice(start, end?)` AND `String.prototype.slice`
961
+ # (the `string-slice` divergence, #2182) -- the adapter emits the
962
+ # same `bf.slice(recv, start, end)` call for both receiver shapes
963
+ # (it can't disambiguate string vs. array at compile time), so
964
+ # this dispatches on the Python type, mirroring `includes` above.
965
+ # `str` and `list` share slicing semantics (`recv[s:e]`) and
966
+ # `len()`, so one clamp computation serves both; `str` indexing
967
+ # is by Unicode code point already, matching JS except for
968
+ # astral-plane input (the same divergence boundary every other
969
+ # adapter's pad/trim helpers already accept).
970
+ if not isinstance(recv, (list, str)):
938
971
  return []
939
972
  length = len(recv)
940
- if length == 0:
941
- return []
942
973
  s = start if start is not None else 0
943
974
  if s < 0:
944
975
  s = length + s
@@ -950,8 +981,8 @@ class BarefootJS:
950
981
  e = max(e, 0)
951
982
  e = min(e, length)
952
983
  if s >= e:
953
- return []
954
- return list(recv[s:e])
984
+ return recv[0:0]
985
+ return recv[s:e] if isinstance(recv, str) else list(recv[s:e])
955
986
 
956
987
  def reverse(self, recv: Any) -> list:
957
988
  if not isinstance(recv, list):
@@ -1014,6 +1045,20 @@ class BarefootJS:
1014
1045
  return ""
1015
1046
  return js_string(recv).strip()
1016
1047
 
1048
+ def trim_start(self, recv: Any) -> str:
1049
+ """`String.prototype.trimStart()` -- the one-sided sibling of `trim`
1050
+ above (#2183 follow-up)."""
1051
+ if recv is None or isinstance(recv, (list, dict)):
1052
+ return ""
1053
+ return js_string(recv).lstrip()
1054
+
1055
+ def trim_end(self, recv: Any) -> str:
1056
+ """`String.prototype.trimEnd()` -- the one-sided sibling of `trim`
1057
+ above (#2183 follow-up)."""
1058
+ if recv is None or isinstance(recv, (list, dict)):
1059
+ return ""
1060
+ return js_string(recv).rstrip()
1061
+
1017
1062
  def to_fixed(self, value: Any, digits: int = 0) -> str:
1018
1063
  n = self.number(value)
1019
1064
  if _is_nan(n):
@@ -1076,6 +1121,19 @@ class BarefootJS:
1076
1121
  return s
1077
1122
  return s[:i] + n + s[i + len(o) :]
1078
1123
 
1124
+ def replace_all(self, recv: Any, pattern: Any, replacement: Any) -> str:
1125
+ """`String.prototype.replaceAll(pattern, replacement)`, string-pattern
1126
+ form only (#2182) -- every occurrence, the all-occurrences sibling of
1127
+ `replace` above. Python's own `str.replace(old, new)` (no count arg)
1128
+ is already global by default, including the empty-pattern-inserts-
1129
+ at-every-boundary edge case (`"abc".replace("", "X")` -> "XaXbXcX"),
1130
+ so it needs no hand-rolled loop the way the other runtimes' first-
1131
+ occurrence-only native replace does."""
1132
+ s = _scalar_or_empty(recv)
1133
+ o = js_string(pattern)
1134
+ n = js_string(replacement)
1135
+ return s.replace(o, n)
1136
+
1079
1137
  def query(self, base: Any, *triples: Any) -> str:
1080
1138
  """`queryHref(base, {...})` (#2042) -- build `"$base?k=v&..."` from a
1081
1139
  flat list of (guard, key, value) triples. A pair is included iff its
@@ -117,13 +117,19 @@ BINDINGS = {
117
117
  "floor": bf.floor,
118
118
  "ceil": bf.ceil,
119
119
  "round": bf.round,
120
+ "min": bf.min,
121
+ "max": bf.max,
122
+ "abs": bf.abs,
120
123
  "to_fixed": lambda *a: bf.to_fixed(*a),
121
124
  "lower": bf.lc,
122
125
  "upper": bf.uc,
123
126
  "trim": bf.trim,
127
+ "trim_start": bf.trim_start,
128
+ "trim_end": bf.trim_end,
124
129
  "starts_with": lambda *a: bf.starts_with(*a),
125
130
  "ends_with": lambda *a: bf.ends_with(*a),
126
131
  "replace": lambda *a: bf.replace(*a),
132
+ "replace_all": lambda *a: bf.replace_all(*a),
127
133
  "repeat": lambda *a: bf.repeat(*a),
128
134
  "pad_start": lambda *a: bf.pad_start(*a),
129
135
  "pad_end": lambda *a: bf.pad_end(*a),
@@ -74,6 +74,27 @@ class TemplatePrimitivesTest(unittest.TestCase):
74
74
  self.assertEqual(self.bf.round(-1.6), -2)
75
75
  self.assertTrue(_is_nan(self.bf.round("not")))
76
76
 
77
+ def test_min_max_abs(self):
78
+ # `Math.min(a, b)` / `Math.max(a, b)` (two-arg forms only) and
79
+ # `Math.abs()` (#2168 math-methods). JS returns NaN if EITHER
80
+ # min/max operand is NaN.
81
+ self.assertEqual(self.bf.min(3, 7), 3)
82
+ self.assertEqual(self.bf.min(7, 3), 3)
83
+ self.assertEqual(self.bf.min(-2, -5), -5)
84
+ self.assertTrue(_is_nan(self.bf.min("not", 5)))
85
+ self.assertTrue(_is_nan(self.bf.min(5, "not")))
86
+
87
+ self.assertEqual(self.bf.max(3, 7), 7)
88
+ self.assertEqual(self.bf.max(7, 3), 7)
89
+ self.assertEqual(self.bf.max(-2, -5), -2)
90
+ self.assertTrue(_is_nan(self.bf.max("not", 5)))
91
+ self.assertTrue(_is_nan(self.bf.max(5, "not")))
92
+
93
+ self.assertEqual(self.bf.abs(-7.6), 7.6)
94
+ self.assertEqual(self.bf.abs(7.6), 7.6)
95
+ self.assertEqual(self.bf.abs(0), 0)
96
+ self.assertTrue(_is_nan(self.bf.abs("not")))
97
+
77
98
  def test_includes_dispatch(self):
78
99
  # `Array.prototype.includes(x)` + `String.prototype.includes(sub)`
79
100
  # lower to the same `bf.includes(recv, elem)` shape -- see #1448
@@ -158,6 +179,18 @@ class TemplatePrimitivesTest(unittest.TestCase):
158
179
  out.append("mutated")
159
180
  self.assertEqual(src, ["a", "b", "c"])
160
181
 
182
+ def test_slice_string_receiver(self):
183
+ # The `string-slice` divergence (#2182): a string receiver used
184
+ # to fall through the array-only branch and return an empty
185
+ # list instead of a substring.
186
+ word = "barefootjs"
187
+ self.assertEqual(self.bf.slice(word, 0, 4), "bare")
188
+ self.assertEqual(self.bf.slice(word, -4, None), "otjs")
189
+ self.assertEqual(self.bf.slice(word, 4, None), "footjs")
190
+ self.assertEqual(self.bf.slice(word, 5, 2), "")
191
+ # Multi-byte: index by character, not byte.
192
+ self.assertEqual(self.bf.slice("héllo", 0, 2), "hé")
193
+
161
194
  def test_reverse_mutation_isolation(self):
162
195
  self.assertEqual(self.bf.reverse(["a", "b", "c"]), ["c", "b", "a"])
163
196
  self.assertEqual(self.bf.reverse([]), [])
@@ -175,6 +208,18 @@ class TemplatePrimitivesTest(unittest.TestCase):
175
208
  self.assertEqual(self.bf.trim({"a": 1}), "")
176
209
  self.assertEqual(self.bf.trim(42), "42")
177
210
 
211
+ def test_trim_start_and_trim_end(self):
212
+ # The one-sided siblings of `trim` above (#2183). Padding BOTH
213
+ # sides so a swapped side fails visibly.
214
+ self.assertEqual(self.bf.trim_start(" padded "), "padded ")
215
+ self.assertEqual(self.bf.trim_end(" padded "), " padded")
216
+ self.assertEqual(self.bf.trim_start(""), "")
217
+ self.assertEqual(self.bf.trim_end(""), "")
218
+ self.assertEqual(self.bf.trim_start(None), "")
219
+ self.assertEqual(self.bf.trim_end(None), "")
220
+ self.assertEqual(self.bf.trim_start({"a": 1}), "")
221
+ self.assertEqual(self.bf.trim_end([1, 2]), "")
222
+
178
223
  def test_split(self):
179
224
  self.assertEqual(self.bf.split("a,b,c", ","), ["a", "b", "c"])
180
225
  self.assertEqual(self.bf.split("a.b.c", "."), ["a", "b", "c"])
@@ -383,6 +383,27 @@ export function C(props: { count: number }) {
383
383
  })
384
384
  })
385
385
 
386
+ describe('JinjaAdapter - named-slot capture identifier safety (#2168 jsx-element-prop)', () => {
387
+ // A JSX-valued prop under a hyphenated name (`data-slot`, a valid JSX
388
+ // attribute name) must not leak into the `{% set %}` capture variable's
389
+ // identifier — Jinja variable names can't contain `-`. The capture
390
+ // identifier is purely counter-based (never derived from the prop name);
391
+ // the hash KEY passed to `render_child` still carries the real name,
392
+ // quoted via `jinjaHashKey`.
393
+ test('a hyphenated prop name does not appear in the capture variable', () => {
394
+ const { template } = compileAndGenerate(`
395
+ function Card(props) { return null }
396
+ export function Parent() {
397
+ return <Card data-slot={<strong>Title</strong>}>text</Card>
398
+ }
399
+ `)
400
+ expect(template).toContain('{% set bf_prop_0 %}')
401
+ expect(template).toContain("'data-slot': bf_prop_0")
402
+ expect(template).not.toContain('data-slot %}')
403
+ expect(template).not.toContain('data-slot_')
404
+ })
405
+ })
406
+
386
407
  // #2038 nested-callback-predicate loudness is pinned at the shared
387
408
  // conformance layer (workstream C): `filter-nested-callback-predicate` /
388
409
  // `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` with
141
+ // a flag) — the regex-pattern form is refused upstream at the
142
+ // 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
@@ -149,8 +149,16 @@ export class JinjaFilterEmitter implements ParsedExprEmitter {
149
149
  if (property === 'length') {
150
150
  return `bf.length(${emit(object)})`
151
151
  }
152
- // Attribute / dict-key access Jinja `.` resolves both transparently.
153
- return `${emit(object)}.${property}`
152
+ // Bracket/item access, NOT `.` attribute access: Jinja's default
153
+ // `getattr` semantics try a Python ATTRIBUTE first, falling back to a
154
+ // dict key only if no such attribute exists — so `group.items` (a
155
+ // dict key from the JS object) instead resolves to the built-in bound
156
+ // method `dict.items`, raising "not iterable" downstream instead of
157
+ // returning the key's value. `[...]` compiles through Jinja's
158
+ // `getitem`, which tries the KEY first, sidestepping any built-in
159
+ // dict method name (items/keys/values/get/pop/update/...) that would
160
+ // otherwise shadow a same-named JS object field.
161
+ return `${emit(object)}['${escapeJinjaSingleQuoted(property)}']`
154
162
  }
155
163
 
156
164
  indexAccess(object: ParsedExpr, index: ParsedExpr, emit: (e: ParsedExpr) => string): string {
@@ -313,7 +321,7 @@ export class JinjaTopLevelEmitter implements ParsedExprEmitter {
313
321
  return String(value)
314
322
  }
315
323
 
316
- member(object: ParsedExpr, property: string, _computed: boolean, emit: (e: ParsedExpr) => string): string {
324
+ member(object: ParsedExpr, property: string, _computed: boolean, _optional: boolean, emit: (e: ParsedExpr) => string): string {
317
325
  // `props.x` flattens to the bare context var the SSR caller binds each
318
326
  // prop to (props arrive as individual top-level context entries, not a
319
327
  // nested `props` dict).
@@ -331,8 +339,13 @@ export class JinjaTopLevelEmitter implements ParsedExprEmitter {
331
339
  const obj = emit(object)
332
340
  // `.length` → `bf.length` (array count or string char count, JS-compat).
333
341
  if (property === 'length') return `bf.length(${obj})`
334
- // Jinja `.` access works for both dicts and objects.
335
- return `${obj}.${property}`
342
+ // Bracket/item access, NOT `.` attribute access see the sibling
343
+ // `JinjaFilterEmitter.member()` for why: Jinja's `.` tries a Python
344
+ // ATTRIBUTE first, so a dict key that happens to share a name with a
345
+ // built-in dict method (`items`, `keys`, `values`, `get`, ...) resolves
346
+ // to the bound method instead of the value. `[...]` (Jinja `getitem`)
347
+ // tries the key first.
348
+ return `${obj}['${escapeJinjaSingleQuoted(property)}']`
336
349
  }
337
350
 
338
351
  indexAccess(object: ParsedExpr, index: ParsedExpr, emit: (e: ParsedExpr) => string): string {
@@ -143,7 +143,7 @@ import {
143
143
  } from '@barefootjs/jsx'
144
144
  import { isAriaBooleanAttr, isBooleanResultExpr, isExplicitStringCall } from './boolean-result.ts'
145
145
  import type { ParsedExpr, LoweringMatcher } from '@barefootjs/jsx'
146
- import { BF_SLOT, BF_COND, BF_REGION } from '@barefootjs/shared'
146
+ import { BF_SLOT, BF_COND, BF_REGION, escapeHtml } from '@barefootjs/shared'
147
147
 
148
148
  import type { JinjaRenderCtx } from './lib/types.ts'
149
149
  import { JINJA_PRIMITIVE_EMIT_MAP } from './lib/constants.ts'
@@ -206,6 +206,14 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
206
206
  private options: Required<JinjaAdapterOptions>
207
207
  private errors: CompilerError[] = []
208
208
  private inLoop: boolean = false
209
+ /**
210
+ * `IRLoop.depth` of the loop currently being rendered (save/restore
211
+ * around `renderChildren(loop.children)`, mirroring `inLoop` above).
212
+ * `renderAttributes` reads this to derive the `key` → `data-key`/
213
+ * `data-key-N` suffix — the depth is IR-computed (jsx-to-ir.ts), not
214
+ * re-derived here (#2168 nested-loop-outer-binding).
215
+ */
216
+ private currentLoopKeyDepth = 0
209
217
  /**
210
218
  * SolidJS-style props identifier (`function(props: P)`) and the
211
219
  * analyzer-extracted prop names. Stashed at `generate()` entry so the
@@ -401,7 +409,9 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
401
409
  }
402
410
 
403
411
  emitText(node: IRText): string {
404
- return node.value
412
+ // IRText carries the entity-DECODED value (Phase 1 decodes JSX
413
+ // character references); re-escape for direct HTML emission.
414
+ return escapeHtml(node.value)
405
415
  }
406
416
 
407
417
  emitExpression(node: IRExpression): string {
@@ -777,7 +787,11 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
777
787
  // `{...rest}` → `bf.spread_attrs(rest)` emit path both see only the
778
788
  // keys NOT already destructured.
779
789
  const indexLocalLines: string[] = []
780
- if (loop.iterationShape === 'keys') {
790
+ if (loop.objectIteration) {
791
+ // `key`/`value` bind directly in the for-header (see `array` below)
792
+ // via Jinja's own dict iteration — no derived `loop.index0` local
793
+ // needed, unlike the array `iterationShape` cases.
794
+ } else if (loop.iterationShape === 'keys') {
781
795
  indexLocalLines.push(`{% set ${jinjaIdent(param)} = loop.index0 %}`)
782
796
  } else if (loop.index) {
783
797
  indexLocalLines.push(`{% set ${jinjaIdent(loop.index)} = loop.index0 %}`)
@@ -802,10 +816,13 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
802
816
 
803
817
  const prevInLoop = this.inLoop
804
818
  this.inLoop = true
819
+ const prevLoopKeyDepth = this.currentLoopKeyDepth
820
+ this.currentLoopKeyDepth = loop.depth
805
821
  // Re-render children now that inLoop is set (so nested components use the
806
822
  // loop-child naming convention). renderedChildren above was computed with
807
823
  // the previous flag; recompute under the loop flag.
808
824
  const childrenUnderLoop = this.renderChildren(loop.children)
825
+ this.currentLoopKeyDepth = prevLoopKeyDepth
809
826
  this.inLoop = prevInLoop
810
827
  void renderedChildren
811
828
 
@@ -822,7 +839,19 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
822
839
  // Scoped per-call-site marker so sibling `.map()`s under the same parent
823
840
  // each get their own reconciliation range.
824
841
  lines.push(`{{ bf.comment("loop:${loop.markerId}") | safe }}`)
825
- lines.push(`{% for ${jinjaIdent(loopVar)} in ${array} %}`)
842
+ // `objectIteration` (#2168 object-entries-map): Python `dict` preserves
843
+ // JS `Object.entries()`'s insertion-order semantics natively, so this
844
+ // lowers straight to Jinja's own dict-iteration forms — no runtime
845
+ // helper needed. `.items()` binds `index` (the KEY) alongside `param`;
846
+ // `.keys()`/`.values()` bind `param` alone.
847
+ const forHeader = loop.objectIteration === 'entries'
848
+ ? `{% for ${jinjaIdent(loop.index ?? param)}, ${jinjaIdent(param)} in ${array}.items() %}`
849
+ : loop.objectIteration === 'keys'
850
+ ? `{% for ${jinjaIdent(param)} in ${array}.keys() %}`
851
+ : loop.objectIteration === 'values'
852
+ ? `{% for ${jinjaIdent(param)} in ${array}.values() %}`
853
+ : `{% for ${jinjaIdent(loopVar)} in ${array} %}`
854
+ lines.push(forHeader)
826
855
  for (const il of indexLocalLines) lines.push(il)
827
856
 
828
857
  // Handle filter().map() pattern by wrapping children in if-condition
@@ -974,11 +1003,33 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
974
1003
  type Segment = { kind: 'entries'; parts: string[] } | { kind: 'spread'; expr: string }
975
1004
  const segments: Segment[] = [{ kind: 'entries', parts: [] }]
976
1005
  const currentEntries = () => this.componentPropSegmentEntries(segments)
1006
+ // Named JSX-valued props OTHER than the reserved `children`
1007
+ // (`header={<strong>Title</strong>}`, #2168 jsx-element-prop) each get
1008
+ // their own `{% set %}` capture, prepended to the final returned
1009
+ // string below — same mechanism as the reserved children capture,
1010
+ // just keyed by the prop's own name instead of `children`.
1011
+ const namedSlotSetBlocks: string[] = []
977
1012
 
978
1013
  for (const p of comp.props) {
979
1014
  // Skip callback props (onXxx) and `ref` — both are client-only for
980
1015
  // SSR (Hono renders neither; the client JS wires them at hydration).
981
1016
  if ((p.name.match(/^on[A-Z]/) || p.name === 'ref') && p.value.kind === 'expression') continue
1017
+ if (p.value.kind === 'jsx-children' && p.name !== 'children') {
1018
+ const prevInLoop = this.inLoop
1019
+ this.inLoop = false
1020
+ const slotBody = this.renderChildren(p.value.children)
1021
+ this.inLoop = prevInLoop
1022
+ // Purely counter-based — NOT derived from `p.name` or `comp.slotId`.
1023
+ // A JSX prop name can contain characters (`data-slot`) that aren't a
1024
+ // valid Jinja `{% set %}` target, and `comp.slotId` alone would
1025
+ // collide across two named-slot props on the same component
1026
+ // invocation (unlike the reserved children slot, there's only ever
1027
+ // one of those per invocation).
1028
+ const captureName = `bf_prop_${this.childrenCaptureCounter++}`
1029
+ namedSlotSetBlocks.push(`{% set ${captureName} %}${slotBody}{% endset %}`)
1030
+ currentEntries().push(`${jinjaHashKey(p.name)}: ${captureName}`)
1031
+ continue
1032
+ }
982
1033
  if (p.value.kind === 'spread') {
983
1034
  const trimmed = p.value.expr.trim()
984
1035
  // SolidJS-style props identifier (`function(props: P)`) has no
@@ -1042,12 +1093,12 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
1042
1093
  const captureName = `bf_children_${comp.slotId ?? 'c' + this.childrenCaptureCounter++}`
1043
1094
  currentEntries().push(`${jinjaHashKey('children')}: ${captureName}`)
1044
1095
  const dict = this.combineComponentPropSegments(segments)
1045
- return `{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`
1096
+ return `${namedSlotSetBlocks.join('')}{% set ${captureName} %}${childrenBody}{% endset %}{{ bf.render_child('${tplName}', ${dict}) | safe }}`
1046
1097
  }
1047
1098
 
1048
1099
  const isEmpty = segments.every(s => s.kind === 'entries' && s.parts.length === 0)
1049
1100
  const dictEntries = isEmpty ? '' : `, ${this.combineComponentPropSegments(segments)}`
1050
- return `{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`
1101
+ return `${namedSlotSetBlocks.join('')}{{ bf.render_child('${tplName}'${dictEntries}) | safe }}`
1051
1102
  }
1052
1103
 
1053
1104
  private childrenCaptureCounter = 0
@@ -1132,7 +1183,7 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
1132
1183
  * AttrValue lowering for intrinsic-element attributes (Jinja).
1133
1184
  */
1134
1185
  private readonly elementAttrEmitter: AttrValueEmitter = {
1135
- emitLiteral: (value, name) => `${name}="${value.value}"`,
1186
+ emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
1136
1187
  emitExpression: (value, name) => {
1137
1188
  // `style={{ … }}` object literal → a CSS string with dynamic values
1138
1189
  // interpolated, instead of refusing the bare object with BF101 (#1322).
@@ -1337,7 +1388,10 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
1337
1388
  // Rewrite JSX special-prop names to their HTML-attribute counterparts.
1338
1389
  let attrName: string
1339
1390
  if (attr.name === 'className') attrName = 'class'
1340
- else if (attr.name === 'key') attrName = 'data-key'
1391
+ else if (attr.name === 'key') {
1392
+ const depth = this.currentLoopKeyDepth
1393
+ attrName = depth > 0 ? `data-key-${depth}` : 'data-key'
1394
+ }
1341
1395
  else attrName = attr.name
1342
1396
  const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName)
1343
1397
  if (lowered) parts.push(lowered)
@@ -22,6 +22,9 @@ export const JINJA_TEMPLATE_PRIMITIVES: Record<string, PrimitiveSpec> = {
22
22
  'Math.floor': { arity: 1, emit: (args) => `bf.floor(${args[0]})` },
23
23
  'Math.ceil': { arity: 1, emit: (args) => `bf.ceil(${args[0]})` },
24
24
  'Math.round': { arity: 1, emit: (args) => `bf.round(${args[0]})` },
25
+ 'Math.min': { arity: 2, emit: (args) => `bf.min(${args[0]}, ${args[1]})` },
26
+ 'Math.max': { arity: 2, emit: (args) => `bf.max(${args[0]}, ${args[1]})` },
27
+ 'Math.abs': { arity: 1, emit: (args) => `bf.abs(${args[0]})` },
25
28
  }
26
29
 
27
30
  /**
@@ -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
  }
@@ -14,21 +14,4 @@
14
14
 
15
15
  import type { RenderDivergences } from '@barefootjs/jsx'
16
16
 
17
- export const renderDivergences: RenderDivergences = {
18
- 'html-entity-text':
19
- '`&copy;` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes',
20
- 'math-methods':
21
- 'Math.min/max/abs over a signal render empty (only Math.floor is in the template-primitive registry)',
22
- 'static-attr-escape':
23
- 'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
24
- 'object-entries-map':
25
- '`Object.entries(prop).map(([k, v]) => …)` renders an EMPTY list — the object-shaped prop silently produces zero iterations',
26
- 'nested-loop-outer-binding':
27
- 'nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`',
28
- 'jsx-element-prop':
29
- 'a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped',
30
- 'string-slice':
31
- '`.slice()` on a STRING renders empty (array-slice helper misfires on strings)',
32
- 'string-trim-sided':
33
- '`.trimStart()` / `.trimEnd()` render empty (no lowering)',
34
- }
17
+ export const renderDivergences: RenderDivergences = {}