@barefootjs/mojolicious 0.32.0 → 0.33.1

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.
@@ -89,8 +89,11 @@ export interface MojoMemoContext {
89
89
  * re-parsing `expr` — mirrors go-template's
90
90
  * `convertExpressionToGo(jsExpr, out?, preParsed?)`. With `preParsed` set,
91
91
  * `expr` is unused for parsing (the converter derives any diagnostic text
92
- * from the tree), so callers may pass `''`.
92
+ * from the tree), so callers may pass `''`. `pos` (default `'rendered'`)
93
+ * must be `'value'` for a derived-seed RHS — an assignment, not a render —
94
+ * so the internal support gate matches the `isSupportedValue`
95
+ * classification the seed plan already used.
93
96
  */
94
- convertExpressionToPerl(expr: string, preParsed?: ParsedExpr): string;
97
+ convertExpressionToPerl(expr: string, preParsed?: ParsedExpr, pos?: 'rendered' | 'value'): string;
95
98
  }
96
99
  //# sourceMappingURL=emit-context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"emit-context.d.ts","sourceRoot":"","sources":["../../src/adapter/emit-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5E,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAEzC;;;OAGG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAErD,mFAAmF;IACnF,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAEhD;;;OAGG;IACH,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE1E,uEAAuE;IACvE,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAEzC,wDAAwD;IACxD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAExD,wEAAwE;IACxE,2BAA2B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACrE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAE9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAA;IAEhC,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAA;IAErD,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAExC;;;;;;;;;OASG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;OASG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACtE"}
1
+ {"version":3,"file":"emit-context.d.ts","sourceRoot":"","sources":["../../src/adapter/emit-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5E,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAEzC;;;OAGG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAErD,mFAAmF;IACnF,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAEhD;;;OAGG;IACH,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE1E,uEAAuE;IACvE,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAEzC,wDAAwD;IACxD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAExD,wEAAwE;IACxE,2BAA2B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACrE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAE9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAA;IAEhC,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,gBAAgB,CAAC,CAAA;IAErD,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAExC;;;;;;;;;OASG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;;;;OAYG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;CAClG"}
@@ -77,6 +77,6 @@ export declare class MojoTopLevelEmitter implements ParsedExprEmitter {
77
77
  arrow(_params: string[], _body: ParsedExpr, _emit: (e: ParsedExpr) => string): string;
78
78
  regex(_raw: string): string;
79
79
  unsupported(_raw: string, _reason: string): string;
80
- objectLiteral(properties: ObjectLiteralProperty[], _raw: string, _emit: (e: ParsedExpr) => string): string;
80
+ objectLiteral(properties: ObjectLiteralProperty[], _raw: string, emit: (e: ParsedExpr) => string): string;
81
81
  }
82
82
  //# sourceMappingURL=emitters.d.ts.map
@@ -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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"}
@@ -6,6 +6,7 @@ import {
6
6
  stringifyParsedExpr as stringifyParsedExpr2,
7
7
  parseStyleObjectEntries,
8
8
  isSupported,
9
+ isSupportedValue,
9
10
  exprToString,
10
11
  parseProviderObjectLiteral,
11
12
  emitParsedExpr as emitParsedExpr2,
@@ -101,8 +102,11 @@ var MOJO_TEMPLATE_PRIMITIVES = {
101
102
  var MOJO_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(MOJO_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
102
103
 
103
104
  // src/adapter/lib/perl-naming.ts
105
+ function escapePerlSingleQuoted(s) {
106
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
107
+ }
104
108
  function perlHashKey(name) {
105
- return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "\\'")}'`;
109
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${escapePerlSingleQuoted(name)}'`;
106
110
  }
107
111
  function perlIdentifierFromMarkerId(markerId) {
108
112
  return markerId.replace(/[^a-zA-Z0-9]/g, (ch) => ch === "_" ? "__" : `_x${ch.charCodeAt(0).toString(16)}`);
@@ -780,8 +784,11 @@ class MojoTopLevelEmitter {
780
784
  unsupported(_raw, _reason) {
781
785
  return "''";
782
786
  }
783
- objectLiteral(properties, _raw, _emit) {
784
- return properties.length === 0 ? "{}" : "''";
787
+ objectLiteral(properties, _raw, emit) {
788
+ if (properties.length === 0)
789
+ return "{}";
790
+ const parts = properties.map((p) => p.kind === "spread" ? `%{${emit(p.expr)}}` : `'${escapePerlSingleQuoted(p.key)}' => ${emit(p.value)}`);
791
+ return `{ ${parts.join(", ")} }`;
785
792
  }
786
793
  }
787
794
 
@@ -895,6 +902,8 @@ function objectLiteralExprToPerlHashref(ctx, expr) {
895
902
  function objectLiteralToPerlHashref(ctx, obj) {
896
903
  const entries = [];
897
904
  for (const prop of obj.properties) {
905
+ if (prop.kind === "spread")
906
+ return null;
898
907
  if (prop.shorthand)
899
908
  return null;
900
909
  if (prop.keyKind === "numeric")
@@ -915,7 +924,7 @@ function objectLiteralToPerlHashref(ctx, obj) {
915
924
  return null;
916
925
  }
917
926
  const valPerl = indexed !== null ? indexed : ctx.convertExpressionToPerl("", val);
918
- entries.push(`'${key.replace(/'/g, "\\'")}' => ${valPerl}`);
927
+ entries.push(`'${escapePerlSingleQuoted(key)}' => ${valPerl}`);
919
928
  }
920
929
  return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`;
921
930
  }
@@ -931,8 +940,8 @@ function recordIndexAccessToPerl(ctx, val) {
931
940
  if (!parsed)
932
941
  return null;
933
942
  const entries = parsed.entries.map((e) => {
934
- const mapVal = e.value.kind === "number" ? e.value.text : `'${e.value.text.replace(/'/g, "\\'")}'`;
935
- return `'${e.key.replace(/'/g, "\\'")}' => ${mapVal}`;
943
+ const mapVal = e.value.kind === "number" ? e.value.text : `'${escapePerlSingleQuoted(e.value.text)}'`;
944
+ return `'${escapePerlSingleQuoted(e.key)}' => ${mapVal}`;
936
945
  });
937
946
  return `{ ${entries.join(", ")} }->{$${parsed.indexPropName}}`;
938
947
  }
@@ -966,7 +975,7 @@ function generateDerivedMemoSeed(ctx, ir) {
966
975
  for (const step of plan.steps) {
967
976
  if (step.kind !== "derived")
968
977
  continue;
969
- const perl = ctx.convertExpressionToPerl(step.expr, step.parsed);
978
+ const perl = ctx.convertExpressionToPerl(step.expr, step.parsed, "value");
970
979
  if (perl === "" || !/\$[A-Za-z_]\w*/.test(perl))
971
980
  continue;
972
981
  lines.push(`% my $${step.name} = ${perl};`);
@@ -1823,9 +1832,9 @@ ${reason}` : "";
1823
1832
  };
1824
1833
  }
1825
1834
  get memoCtx() {
1826
- return { convertExpressionToPerl: (e, preParsed) => this.convertExpressionToPerl(e, preParsed) };
1835
+ return { convertExpressionToPerl: (e, preParsed, pos) => this.convertExpressionToPerl(e, preParsed, pos) };
1827
1836
  }
1828
- convertExpressionToPerl(expr, preParsed) {
1837
+ convertExpressionToPerl(expr, preParsed, pos = "rendered") {
1829
1838
  let parsed;
1830
1839
  if (preParsed) {
1831
1840
  parsed = preParsed;
@@ -1848,7 +1857,7 @@ ${reason}` : "";
1848
1857
  }
1849
1858
  }
1850
1859
  }
1851
- const support = isSupported(parsed);
1860
+ const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
1852
1861
  if (!support.supported) {
1853
1862
  this.errors.push({
1854
1863
  code: "BF101",
@@ -6,6 +6,9 @@
6
6
  * module scope as the single source of truth for Perl-identifier quoting
7
7
  * and marker-id encoding.
8
8
  */
9
+ /** Escape a string for a Perl single-quoted literal: backslash first (so
10
+ * it doesn't double-escape the quote we add next), then the quote. */
11
+ export declare function escapePerlSingleQuoted(s: string): string;
9
12
  /**
10
13
  * (#checkbox) Quote a `render_child` named-arg / hashref key when it isn't a
11
14
  * bare Perl identifier. A JSX attribute name like `data-slot` would otherwise
@@ -1 +1 @@
1
- {"version":3,"file":"perl-naming.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/perl-naming.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAInE"}
1
+ {"version":3,"file":"perl-naming.d.ts","sourceRoot":"","sources":["../../../src/adapter/lib/perl-naming.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;uEACuE;AACvE,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAInE"}
@@ -1 +1 @@
1
- {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/adapter/memo/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,EAGrB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAM7D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,CAWnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW,GAAG,MAAM,CAarF"}
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/adapter/memo/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,EAGrB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAM7D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,CAWnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,eAAe,EAAE,EAAE,EAAE,WAAW,GAAG,MAAM,CAcrF"}
@@ -1 +1 @@
1
- {"version":3,"file":"mojo-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/mojo-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,WAAW,EAEX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAMP,yBAAyB,EAE1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,EAgChB,MAAM,iBAAiB,CAAA;AAKxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AA8BnD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAuCxD,qBAAa,WAAY,SAAQ,WAAY,YAAW,aAAa,CAAC,aAAa,CAAC;IAClF,IAAI,SAAgB;IACpB,SAAS,SAAa;IACtB,qBAAqB,UAAO;IAE5B;;;;;;;;;;;OAWG;IACH,kBAAkB,EAAE,yBAAyB,CAA0B;IAEvE,OAAO,CAAC,aAAa,CAAa;IAClC;;;;wCAIoC;IACpC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,MAAM,CAAsB;IACpC;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB,CAAI;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,iBAAiB,CAAyB;IAClD;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB,CAAyB;IAClD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAyB;IACjD;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB,CAAyB;IAEpD;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB,CAAwB;IACjD;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB,CAAiC;IAC3D;;;;;;OAMG;IACH,OAAO,CAAC,cAAc,CAAmC;IACzD;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,KAAK,CAAmC;IAChD;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,qBAAqB,CAAyB;IAEtD,YAAY,OAAO,GAAE,kBAAuB,EAM3C;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,CAsFzE;IAGD;;;;;OAKG;IACH;;;;;OAKG;IACH;;;;;OAKG;IACH,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAW3C;IAED;;;;OAIG;IACH,8BAA8B,CAC5B,IAAI,EAAE,MAAM,GACX;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAgBlD;IAED;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,0BAA0B;IAQlC,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,2BAA2B;IA4CnC;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/B;IAMD,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE1F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7B;IAED,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAElG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEpF;IAED,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE9F;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE5F;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAElG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAc5F;IAED,sEAAsE;IACtE,OAAO,CAAC,iBAAiB;IAkBzB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;;;;OAOG;IACH,OAAO,CAAC,6BAA6B;IAMrC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEtF;IAMD,aAAa,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAsCxC;IAED;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IA2BhC,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA4B3C;IAMD,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAsC7C;IAED,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAcnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqS/B;IAMD;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CA0CpC;IAED,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAmEzC;IAED,OAAO,CAAC,sBAAsB,CAAI;IAElC;+DAC2D;IAC3D,OAAO,CAAC,kBAAkB,CAAI;IAE9B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAIT,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAgB1C;IAMD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAyNlC;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,gBAAgB;IA0CxB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAIjD;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvC;IAMD;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,iCAAiC;IAmCzC;;;;;;;OAOG;IACH,OAAO,CAAC,gCAAgC;IAmBxC;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,+BAA+B;IA8BvC;;;;;;;OAOG;IACH,OAAO,KAAK,OAAO,GAUlB;IAED;;;;;OAKG;IACH,OAAO,KAAK,SAAS,GAQpB;IAED,sEAAsE;IACtE,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,uBAAuB;IAgF/B;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAI9B;;;;OAIG;IACH;4EACwE;IACxE,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,gBAAgB;IAcxB,iFAAiF;IACjF,OAAO,CAAC,2BAA2B;CAGpC;AAED,eAAO,MAAM,WAAW,aAAoB,CAAA"}
1
+ {"version":3,"file":"mojo-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/mojo-adapter.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"spread-codegen.d.ts","sourceRoot":"","sources":["../../../src/adapter/spread/spread-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE3D;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,UAAU,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAef;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,UAAU,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAGf;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,iBAAiB,EACtB,GAAG,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GACnD,MAAM,GAAG,IAAI,CAiDf;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CA4B9F"}
1
+ {"version":3,"file":"spread-codegen.d.ts","sourceRoot":"","sources":["../../../src/adapter/spread/spread-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,UAAU,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAef;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,UAAU,GAAG,SAAS,GAC3B,MAAM,GAAG,IAAI,CAGf;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,iBAAiB,EACtB,GAAG,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC,GACnD,MAAM,GAAG,IAAI,CAqDf;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CA4B9F"}
@@ -1 +1 @@
1
- {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAwC7B,CAAA"}
1
+ {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eA+C7B,CAAA"}
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  stringifyParsedExpr as stringifyParsedExpr2,
7
7
  parseStyleObjectEntries,
8
8
  isSupported,
9
+ isSupportedValue,
9
10
  exprToString,
10
11
  parseProviderObjectLiteral,
11
12
  emitParsedExpr as emitParsedExpr2,
@@ -101,8 +102,11 @@ var MOJO_TEMPLATE_PRIMITIVES = {
101
102
  var MOJO_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(MOJO_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
102
103
 
103
104
  // src/adapter/lib/perl-naming.ts
105
+ function escapePerlSingleQuoted(s) {
106
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
107
+ }
104
108
  function perlHashKey(name) {
105
- return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "\\'")}'`;
109
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${escapePerlSingleQuoted(name)}'`;
106
110
  }
107
111
  function perlIdentifierFromMarkerId(markerId) {
108
112
  return markerId.replace(/[^a-zA-Z0-9]/g, (ch) => ch === "_" ? "__" : `_x${ch.charCodeAt(0).toString(16)}`);
@@ -780,8 +784,11 @@ class MojoTopLevelEmitter {
780
784
  unsupported(_raw, _reason) {
781
785
  return "''";
782
786
  }
783
- objectLiteral(properties, _raw, _emit) {
784
- return properties.length === 0 ? "{}" : "''";
787
+ objectLiteral(properties, _raw, emit) {
788
+ if (properties.length === 0)
789
+ return "{}";
790
+ const parts = properties.map((p) => p.kind === "spread" ? `%{${emit(p.expr)}}` : `'${escapePerlSingleQuoted(p.key)}' => ${emit(p.value)}`);
791
+ return `{ ${parts.join(", ")} }`;
785
792
  }
786
793
  }
787
794
 
@@ -895,6 +902,8 @@ function objectLiteralExprToPerlHashref(ctx, expr) {
895
902
  function objectLiteralToPerlHashref(ctx, obj) {
896
903
  const entries = [];
897
904
  for (const prop of obj.properties) {
905
+ if (prop.kind === "spread")
906
+ return null;
898
907
  if (prop.shorthand)
899
908
  return null;
900
909
  if (prop.keyKind === "numeric")
@@ -915,7 +924,7 @@ function objectLiteralToPerlHashref(ctx, obj) {
915
924
  return null;
916
925
  }
917
926
  const valPerl = indexed !== null ? indexed : ctx.convertExpressionToPerl("", val);
918
- entries.push(`'${key.replace(/'/g, "\\'")}' => ${valPerl}`);
927
+ entries.push(`'${escapePerlSingleQuoted(key)}' => ${valPerl}`);
919
928
  }
920
929
  return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`;
921
930
  }
@@ -931,8 +940,8 @@ function recordIndexAccessToPerl(ctx, val) {
931
940
  if (!parsed)
932
941
  return null;
933
942
  const entries = parsed.entries.map((e) => {
934
- const mapVal = e.value.kind === "number" ? e.value.text : `'${e.value.text.replace(/'/g, "\\'")}'`;
935
- return `'${e.key.replace(/'/g, "\\'")}' => ${mapVal}`;
943
+ const mapVal = e.value.kind === "number" ? e.value.text : `'${escapePerlSingleQuoted(e.value.text)}'`;
944
+ return `'${escapePerlSingleQuoted(e.key)}' => ${mapVal}`;
936
945
  });
937
946
  return `{ ${entries.join(", ")} }->{$${parsed.indexPropName}}`;
938
947
  }
@@ -966,7 +975,7 @@ function generateDerivedMemoSeed(ctx, ir) {
966
975
  for (const step of plan.steps) {
967
976
  if (step.kind !== "derived")
968
977
  continue;
969
- const perl = ctx.convertExpressionToPerl(step.expr, step.parsed);
978
+ const perl = ctx.convertExpressionToPerl(step.expr, step.parsed, "value");
970
979
  if (perl === "" || !/\$[A-Za-z_]\w*/.test(perl))
971
980
  continue;
972
981
  lines.push(`% my $${step.name} = ${perl};`);
@@ -1823,9 +1832,9 @@ ${reason}` : "";
1823
1832
  };
1824
1833
  }
1825
1834
  get memoCtx() {
1826
- return { convertExpressionToPerl: (e, preParsed) => this.convertExpressionToPerl(e, preParsed) };
1835
+ return { convertExpressionToPerl: (e, preParsed, pos) => this.convertExpressionToPerl(e, preParsed, pos) };
1827
1836
  }
1828
- convertExpressionToPerl(expr, preParsed) {
1837
+ convertExpressionToPerl(expr, preParsed, pos = "rendered") {
1829
1838
  let parsed;
1830
1839
  if (preParsed) {
1831
1840
  parsed = preParsed;
@@ -1848,7 +1857,7 @@ ${reason}` : "";
1848
1857
  }
1849
1858
  }
1850
1859
  }
1851
- const support = isSupported(parsed);
1860
+ const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
1852
1861
  if (!support.supported) {
1853
1862
  this.errors.push({
1854
1863
  code: "BF101",
@@ -1927,14 +1936,12 @@ var conformancePins = {
1927
1936
  ],
1928
1937
  "filter-nested-find-predicate": [{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2320" }],
1929
1938
  "date-method-uncatalogued": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2356" }],
1930
- "rich-prop-client-read": [{ code: "BF049", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2648" }]
1939
+ "rich-prop-client-read": [{ code: "BF049", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2648" }],
1940
+ "jsx-element-prop-ternary": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2667" }],
1941
+ "jsx-element-prop-array": [{ code: "BF021", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2667" }]
1931
1942
  };
1932
1943
  // src/render-divergences.ts
1933
- var renderDivergences = {
1934
- "todo-app": "the `todos` signal seeds from `(props.initialTodos ?? []).map(t => ({ ...t, editing: false }))` — a different-prop-derived `.map()` chain `extractSsrDefaults` cannot statically resolve, and `computeSsrSeedPlan` classifies it opaque (no in-template recompute), so it seeds `undef`; the non-`/* @client */`-marked `{todos().length > 0 && ...}` toggle-all block SSRs as if there are zero todos regardless of `initialTodos` (https://github.com/piconic-ai/barefootjs/issues/2696)",
1935
- "todo-app-ssr": "same root cause as `todo-app` (https://github.com/piconic-ai/barefootjs/issues/2696), but this fixture's todo-list loop carries no `/* @client */` marker — the compiled Mojo::Template loop iterates the undef-seeded `todos` directly and Perl's strict vars abort the render instead of producing HTML",
1936
- "callback-param-shadows-prop": "the `first` signal seeds from `[{ a: 'p' }].map((title) => title.a).join(',')` — a constant expression `extractSsrDefaults` still cannot statically resolve (`.map()` is unsupported for any receiver) and, unlike the sibling `joined` memo's structurally similar chain, gets no in-template recompute (`computeSsrSeedPlan` classifies it opaque too); `<span>{first()}</span>` SSRs empty instead of `p` (https://github.com/piconic-ai/barefootjs/issues/2696)"
1937
- };
1944
+ var renderDivergences = {};
1938
1945
  export {
1939
1946
  renderDivergences,
1940
1947
  mojoAdapter,
@@ -1 +1 @@
1
- {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAO/B,CAAA"}
1
+ {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAQxD,eAAO,MAAM,iBAAiB,EAAE,iBAAsB,CAAA"}
package/dist/vite.js CHANGED
@@ -263,7 +263,7 @@ function convertNode(node, raw) {
263
263
  }
264
264
  if (n === undefined || Number.isNaN(n)) {
265
265
  const parsedDepth = convertNode(depthNode, raw);
266
- if (checkSupport(parsedDepth).supported) {
266
+ if (checkSupport(parsedDepth, "rendered").supported) {
267
267
  depthExpr = parsedDepth;
268
268
  flatDepth = 1;
269
269
  } else {
@@ -357,10 +357,12 @@ function convertNode(node, raw) {
357
357
  const k = objectLiteralKeyName(prop.name);
358
358
  if (k === null)
359
359
  return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts.SyntaxKind[node.kind]}` };
360
- properties.push({ key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
360
+ properties.push({ kind: "prop", key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
361
361
  } else if (ts.isShorthandPropertyAssignment(prop)) {
362
362
  const key = prop.name.text;
363
- properties.push({ key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
363
+ properties.push({ kind: "prop", key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
364
+ } else if (ts.isSpreadAssignment(prop)) {
365
+ properties.push({ kind: "spread", expr: convertNode(prop.expression, raw) });
364
366
  } else {
365
367
  return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts.SyntaxKind[node.kind]}` };
366
368
  }
@@ -1040,14 +1042,26 @@ function getUnaryOperatorString(op) {
1040
1042
  }
1041
1043
  }
1042
1044
  function isSupported(expr) {
1043
- return checkSupport(expr);
1045
+ return checkSupport(expr, "rendered");
1044
1046
  }
1045
- function checkSupport(expr) {
1047
+ function isSupportedValue(expr) {
1048
+ return checkSupport(expr, "value");
1049
+ }
1050
+ function checkSupport(expr, pos) {
1046
1051
  switch (expr.kind) {
1047
1052
  case "unsupported":
1048
1053
  return { supported: false, reason: expr.reason };
1049
- case "object-literal":
1050
- return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
1054
+ case "object-literal": {
1055
+ if (pos !== "value") {
1056
+ return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
1057
+ }
1058
+ for (const prop of expr.properties) {
1059
+ const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos);
1060
+ if (!propSupport.supported)
1061
+ return propSupport;
1062
+ }
1063
+ return { supported: true, level: "L2" };
1064
+ }
1051
1065
  case "identifier":
1052
1066
  return { supported: true, level: "L1" };
1053
1067
  case "literal":
@@ -1057,7 +1071,7 @@ function checkSupport(expr) {
1057
1071
  return { supported: false, reason: "Standalone arrow functions / regex literals are not supported" };
1058
1072
  case "array-literal": {
1059
1073
  for (const el of expr.elements) {
1060
- const elSupport = checkSupport(el);
1074
+ const elSupport = checkSupport(el, pos);
1061
1075
  if (!elSupport.supported)
1062
1076
  return elSupport;
1063
1077
  }
@@ -1070,16 +1084,16 @@ function checkSupport(expr) {
1070
1084
  reason: `String.prototype.${expr.method} supports only a string pattern + string replacement (the regex form is deferred); use a string pattern or wrap the expression in /* @client */`
1071
1085
  };
1072
1086
  }
1073
- const objSupport = checkSupport(expr.object);
1087
+ const objSupport = checkSupport(expr.object, pos);
1074
1088
  if (!objSupport.supported)
1075
1089
  return objSupport;
1076
1090
  for (const arg of expr.args) {
1077
- const argSupport = checkSupport(arg);
1091
+ const argSupport = checkSupport(arg, pos);
1078
1092
  if (!argSupport.supported)
1079
1093
  return argSupport;
1080
1094
  }
1081
1095
  if (expr.method === "flat" && expr.depthExpr) {
1082
- const depthSupport = checkSupport(expr.depthExpr);
1096
+ const depthSupport = checkSupport(expr.depthExpr, pos);
1083
1097
  if (!depthSupport.supported)
1084
1098
  return depthSupport;
1085
1099
  }
@@ -1088,10 +1102,10 @@ function checkSupport(expr) {
1088
1102
  case "call": {
1089
1103
  const cb = asCallbackMethodCall(expr);
1090
1104
  if (cb) {
1091
- const objSupport = checkSupport(cb.object);
1105
+ const objSupport = checkSupport(cb.object, pos);
1092
1106
  if (!objSupport.supported)
1093
1107
  return objSupport;
1094
- const bodySupport = checkSupport(cb.arrow.body);
1108
+ const bodySupport = checkSupport(cb.arrow.body, pos);
1095
1109
  if (!bodySupport.supported) {
1096
1110
  return {
1097
1111
  supported: false,
@@ -1100,13 +1114,13 @@ function checkSupport(expr) {
1100
1114
  };
1101
1115
  }
1102
1116
  for (const rest of cb.args) {
1103
- const restSupport = checkSupport(rest);
1117
+ const restSupport = checkSupport(rest, pos);
1104
1118
  if (!restSupport.supported)
1105
1119
  return restSupport;
1106
1120
  }
1107
1121
  return { supported: true, level: "L5" };
1108
1122
  }
1109
- const calleeSupport = checkSupport(expr.callee);
1123
+ const calleeSupport = checkSupport(expr.callee, pos);
1110
1124
  if (!calleeSupport.supported) {
1111
1125
  return calleeSupport;
1112
1126
  }
@@ -1125,7 +1139,7 @@ function checkSupport(expr) {
1125
1139
  return { supported: true, level: "L1" };
1126
1140
  }
1127
1141
  for (const arg of expr.args) {
1128
- const argSupport = checkSupport(arg);
1142
+ const argSupport = checkSupport(arg, pos);
1129
1143
  if (!argSupport.supported) {
1130
1144
  return argSupport;
1131
1145
  }
@@ -1133,7 +1147,7 @@ function checkSupport(expr) {
1133
1147
  return { supported: true, level: "L2" };
1134
1148
  }
1135
1149
  case "member": {
1136
- const objSupport = checkSupport(expr.object);
1150
+ const objSupport = checkSupport(expr.object, pos);
1137
1151
  if (!objSupport.supported) {
1138
1152
  return objSupport;
1139
1153
  }
@@ -1143,19 +1157,19 @@ function checkSupport(expr) {
1143
1157
  return { supported: true, level: "L2" };
1144
1158
  }
1145
1159
  case "index-access": {
1146
- const objSupport = checkSupport(expr.object);
1160
+ const objSupport = checkSupport(expr.object, pos);
1147
1161
  if (!objSupport.supported)
1148
1162
  return objSupport;
1149
- const indexSupport = checkSupport(expr.index);
1163
+ const indexSupport = checkSupport(expr.index, pos);
1150
1164
  if (!indexSupport.supported)
1151
1165
  return indexSupport;
1152
1166
  return { supported: true, level: "L2" };
1153
1167
  }
1154
1168
  case "binary": {
1155
- const leftSupport = checkSupport(expr.left);
1169
+ const leftSupport = checkSupport(expr.left, pos);
1156
1170
  if (!leftSupport.supported)
1157
1171
  return leftSupport;
1158
- const rightSupport = checkSupport(expr.right);
1172
+ const rightSupport = checkSupport(expr.right, pos);
1159
1173
  if (!rightSupport.supported)
1160
1174
  return rightSupport;
1161
1175
  if (["===", "==", "!==", "!=", ">", "<", ">=", "<="].includes(expr.op)) {
@@ -1167,7 +1181,7 @@ function checkSupport(expr) {
1167
1181
  return { supported: false, reason: `Unknown operator: ${expr.op}` };
1168
1182
  }
1169
1183
  case "unary": {
1170
- const argSupport = checkSupport(expr.argument);
1184
+ const argSupport = checkSupport(expr.argument, pos);
1171
1185
  if (!argSupport.supported)
1172
1186
  return argSupport;
1173
1187
  if (expr.op === "!") {
@@ -1179,25 +1193,25 @@ function checkSupport(expr) {
1179
1193
  return { supported: false, reason: `Unsupported unary operator: ${expr.op}` };
1180
1194
  }
1181
1195
  case "logical": {
1182
- const leftSupport = checkSupport(expr.left);
1196
+ const leftSupport = checkSupport(expr.left, pos);
1183
1197
  if (!leftSupport.supported)
1184
1198
  return leftSupport;
1185
1199
  if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
1186
1200
  return { supported: true, level: "L4" };
1187
1201
  }
1188
- const rightSupport = checkSupport(expr.right);
1202
+ const rightSupport = checkSupport(expr.right, pos);
1189
1203
  if (!rightSupport.supported)
1190
1204
  return rightSupport;
1191
1205
  return { supported: true, level: "L4" };
1192
1206
  }
1193
1207
  case "conditional": {
1194
- const testSupport = checkSupport(expr.test);
1208
+ const testSupport = checkSupport(expr.test, pos);
1195
1209
  if (!testSupport.supported)
1196
1210
  return testSupport;
1197
- const consSupport = checkSupport(expr.consequent);
1211
+ const consSupport = checkSupport(expr.consequent, pos);
1198
1212
  if (!consSupport.supported)
1199
1213
  return consSupport;
1200
- const altSupport = checkSupport(expr.alternate);
1214
+ const altSupport = checkSupport(expr.alternate, pos);
1201
1215
  if (!altSupport.supported)
1202
1216
  return altSupport;
1203
1217
  return { supported: true, level: "L4" };
@@ -1205,7 +1219,7 @@ function checkSupport(expr) {
1205
1219
  case "template-literal": {
1206
1220
  for (const part of expr.parts) {
1207
1221
  if (part.type === "expression") {
1208
- const partSupport = checkSupport(part.expr);
1222
+ const partSupport = checkSupport(part.expr, pos);
1209
1223
  if (!partSupport.supported)
1210
1224
  return partSupport;
1211
1225
  }
@@ -1321,7 +1335,7 @@ function isPureInit(e, pureCallNames) {
1321
1335
  case "array-literal":
1322
1336
  return e.elements.every(pure);
1323
1337
  case "object-literal":
1324
- return e.properties.every((p) => pure(p.value));
1338
+ return e.properties.every((p) => pure(p.kind === "spread" ? p.expr : p.value));
1325
1339
  case "call":
1326
1340
  return e.callee.kind === "identifier" && e.args.length === 0 && pureCallNames !== undefined && pureCallNames.has(e.callee.name);
1327
1341
  case "array-method":
@@ -1375,7 +1389,7 @@ function usesPerPath(name, expr) {
1375
1389
  }
1376
1390
  return add(walk(e.object), sum(e.args));
1377
1391
  case "object-literal":
1378
- return sum(e.properties.map((p) => p.value));
1392
+ return sum(e.properties.map((p) => p.kind === "spread" ? p.expr : p.value));
1379
1393
  case "arrow":
1380
1394
  return walk(e.body).max > 0 ? { min: 0, max: Number.POSITIVE_INFINITY } : { min: 0, max: 0 };
1381
1395
  }
@@ -1441,7 +1455,7 @@ function inlineBinding(expr, name, value) {
1441
1455
  case "object-literal":
1442
1456
  return {
1443
1457
  kind: "object-literal",
1444
- properties: e.properties.map((p) => ({ ...p, value: walk(p.value, enclosing) })),
1458
+ properties: e.properties.map((p) => p.kind === "spread" ? { ...p, expr: walk(p.expr, enclosing) } : { ...p, value: walk(p.value, enclosing) }),
1445
1459
  raw: e.raw
1446
1460
  };
1447
1461
  case "literal":
@@ -1657,7 +1671,7 @@ function freeVarsInBody(body, params) {
1657
1671
  return;
1658
1672
  case "object-literal":
1659
1673
  for (const p of e.properties)
1660
- visit(p.value, bound);
1674
+ visit(p.kind === "spread" ? p.expr : p.value, bound);
1661
1675
  return;
1662
1676
  case "array-method":
1663
1677
  if (e.method === "includes" || e.method === "join") {
@@ -1732,7 +1746,7 @@ function freeIdentifiers(expr) {
1732
1746
  return true;
1733
1747
  case "object-literal":
1734
1748
  for (const p of e.properties)
1735
- if (!visit(p.value, bound))
1749
+ if (!visit(p.kind === "spread" ? p.expr : p.value, bound))
1736
1750
  return false;
1737
1751
  return true;
1738
1752
  case "arrow": {
@@ -1879,10 +1893,17 @@ function toEvalNode(e) {
1879
1893
  case "object-literal": {
1880
1894
  const properties = [];
1881
1895
  for (const p of e.properties) {
1896
+ if (p.kind === "spread") {
1897
+ const spreadExpr = toEvalNode(p.expr);
1898
+ if (!spreadExpr)
1899
+ return null;
1900
+ properties.push({ kind: "spread", expr: spreadExpr });
1901
+ continue;
1902
+ }
1882
1903
  const value = toEvalNode(p.value);
1883
1904
  if (!value)
1884
1905
  return null;
1885
- properties.push({ key: p.key, value });
1906
+ properties.push({ kind: "prop", key: p.key, value });
1886
1907
  }
1887
1908
  return { kind: "object-literal", properties };
1888
1909
  }
@@ -2252,6 +2273,7 @@ var ErrorCodes = {
2252
2273
  MISSING_KEY_IN_LIST: "BF023",
2253
2274
  MISSING_KEY_IN_NESTED_LIST: "BF024",
2254
2275
  UNSUPPORTED_DESTRUCTURE_REST: "BF025",
2276
+ RETURN_VALUE_NOT_JSX: "BF027",
2255
2277
  PROPS_DESTRUCTURING: "BF043",
2256
2278
  SIGNAL_GETTER_NOT_CALLED: "BF044",
2257
2279
  JSX_IN_LOCAL_FUNCTION: "BF045",
@@ -2283,6 +2305,7 @@ var errorMessages = {
2283
2305
  [ErrorCodes.MISSING_KEY_IN_LIST]: "Missing key attribute in list rendering. Add a key prop for efficient updates",
2284
2306
  [ErrorCodes.MISSING_KEY_IN_NESTED_LIST]: "Nested .map() loop requires key attribute for event delegation. Add a key prop to elements in the inner loop",
2285
2307
  [ErrorCodes.UNSUPPORTED_DESTRUCTURE_REST]: "Computed property key in .map() callback destructure is not supported. Rewrite the callback to destructure explicit bindings (e.g., `({ a, b }) => ...`) so the compiler can rewrite references to per-item signal accessors.",
2308
+ [ErrorCodes.RETURN_VALUE_NOT_JSX]: "Component's return value is not recognized as JSX — return the JSX expression directly instead of binding it to a local variable first.",
2286
2309
  [ErrorCodes.PROPS_DESTRUCTURING]: "Props destructuring in function parameters breaks reactivity. Use props object directly.",
2287
2310
  [ErrorCodes.SIGNAL_GETTER_NOT_CALLED]: "Signal/memo getter passed without calling it. Use getter() to read the value.",
2288
2311
  [ErrorCodes.JSX_IN_LOCAL_FUNCTION]: "Local function returns JSX but cannot be inlined. Extract it as a top-level PascalCase component or use a single return statement.",
@@ -2915,6 +2938,8 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
2915
2938
  let tz = null;
2916
2939
  const probeOptions = {};
2917
2940
  for (const prop of options.properties) {
2941
+ if (prop.kind === "spread")
2942
+ return null;
2918
2943
  if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
2919
2944
  return null;
2920
2945
  const value = String(prop.value.value);
@@ -3905,7 +3930,7 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3905
3930
 
3906
3931
  // ../jsx/src/ssr-seed-plan.ts
3907
3932
  function classify(name, origin, expr, parsed, available) {
3908
- if (!isSupported(parsed).supported)
3933
+ if (!isSupportedValue(parsed).supported)
3909
3934
  return { kind: "opaque", name, origin };
3910
3935
  const frees = freeIdentifiers(parsed);
3911
3936
  if (frees === null)
@@ -3968,7 +3993,7 @@ function computeSsrSeedPlan(metadata) {
3968
3993
  }
3969
3994
  }
3970
3995
  const expr = signal.initialValue.trim();
3971
- steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
3996
+ steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(signal.parsed ?? parseExpression(`(${expr})`), localConsts), available));
3972
3997
  available.add(signal.getter);
3973
3998
  }
3974
3999
  for (const memo of metadata.memos) {
@@ -4741,6 +4766,17 @@ function evaluateStaticLiteral(expr, bindings) {
4741
4766
  case "object-literal": {
4742
4767
  const out = {};
4743
4768
  for (const prop of expr.properties) {
4769
+ if (prop.kind === "spread") {
4770
+ const resolved2 = evaluateStaticLiteral(prop.expr, bindings);
4771
+ if (!resolved2)
4772
+ return null;
4773
+ if (resolved2.value === null || resolved2.value === undefined)
4774
+ continue;
4775
+ if (typeof resolved2.value !== "object" || Array.isArray(resolved2.value))
4776
+ return null;
4777
+ Object.assign(out, resolved2.value);
4778
+ continue;
4779
+ }
4744
4780
  const resolved = evaluateStaticLiteral(prop.value, bindings);
4745
4781
  if (!resolved)
4746
4782
  return null;
@@ -4807,6 +4843,8 @@ function matchQueryHrefCall(callee, args, localNames) {
4807
4843
  return null;
4808
4844
  const triples = [];
4809
4845
  for (const p of obj.properties) {
4846
+ if (p.kind === "spread")
4847
+ return null;
4810
4848
  const v = p.value;
4811
4849
  if (v.kind === "conditional" && isOmitBranch(v.alternate)) {
4812
4850
  triples.push({ guard: v.test, key: p.key, value: v.consequent });
@@ -4994,6 +5032,8 @@ function htmlPropValue(parsed) {
4994
5032
  if (parsed.properties.length !== 1)
4995
5033
  return null;
4996
5034
  const [prop] = parsed.properties;
5035
+ if (prop.kind === "spread")
5036
+ return null;
4997
5037
  if (prop.key !== "__html")
4998
5038
  return null;
4999
5039
  return prop.value;
@@ -5245,8 +5285,11 @@ var MOJO_TEMPLATE_PRIMITIVES = {
5245
5285
  var MOJO_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(MOJO_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
5246
5286
 
5247
5287
  // src/adapter/lib/perl-naming.ts
5288
+ function escapePerlSingleQuoted(s) {
5289
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
5290
+ }
5248
5291
  function perlHashKey(name) {
5249
- return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "\\'")}'`;
5292
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${escapePerlSingleQuoted(name)}'`;
5250
5293
  }
5251
5294
  function perlIdentifierFromMarkerId(markerId) {
5252
5295
  return markerId.replace(/[^a-zA-Z0-9]/g, (ch) => ch === "_" ? "__" : `_x${ch.charCodeAt(0).toString(16)}`);
@@ -5908,8 +5951,11 @@ class MojoTopLevelEmitter {
5908
5951
  unsupported(_raw, _reason) {
5909
5952
  return "''";
5910
5953
  }
5911
- objectLiteral(properties, _raw, _emit) {
5912
- return properties.length === 0 ? "{}" : "''";
5954
+ objectLiteral(properties, _raw, emit) {
5955
+ if (properties.length === 0)
5956
+ return "{}";
5957
+ const parts = properties.map((p) => p.kind === "spread" ? `%{${emit(p.expr)}}` : `'${escapePerlSingleQuoted(p.key)}' => ${emit(p.value)}`);
5958
+ return `{ ${parts.join(", ")} }`;
5913
5959
  }
5914
5960
  }
5915
5961
 
@@ -6022,6 +6068,8 @@ function objectLiteralExprToPerlHashref(ctx, expr) {
6022
6068
  function objectLiteralToPerlHashref(ctx, obj) {
6023
6069
  const entries = [];
6024
6070
  for (const prop of obj.properties) {
6071
+ if (prop.kind === "spread")
6072
+ return null;
6025
6073
  if (prop.shorthand)
6026
6074
  return null;
6027
6075
  if (prop.keyKind === "numeric")
@@ -6042,7 +6090,7 @@ function objectLiteralToPerlHashref(ctx, obj) {
6042
6090
  return null;
6043
6091
  }
6044
6092
  const valPerl = indexed !== null ? indexed : ctx.convertExpressionToPerl("", val);
6045
- entries.push(`'${key.replace(/'/g, "\\'")}' => ${valPerl}`);
6093
+ entries.push(`'${escapePerlSingleQuoted(key)}' => ${valPerl}`);
6046
6094
  }
6047
6095
  return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`;
6048
6096
  }
@@ -6058,8 +6106,8 @@ function recordIndexAccessToPerl(ctx, val) {
6058
6106
  if (!parsed)
6059
6107
  return null;
6060
6108
  const entries = parsed.entries.map((e) => {
6061
- const mapVal = e.value.kind === "number" ? e.value.text : `'${e.value.text.replace(/'/g, "\\'")}'`;
6062
- return `'${e.key.replace(/'/g, "\\'")}' => ${mapVal}`;
6109
+ const mapVal = e.value.kind === "number" ? e.value.text : `'${escapePerlSingleQuoted(e.value.text)}'`;
6110
+ return `'${escapePerlSingleQuoted(e.key)}' => ${mapVal}`;
6063
6111
  });
6064
6112
  return `{ ${entries.join(", ")} }->{$${parsed.indexPropName}}`;
6065
6113
  }
@@ -6089,7 +6137,7 @@ function generateDerivedMemoSeed(ctx, ir) {
6089
6137
  for (const step of plan.steps) {
6090
6138
  if (step.kind !== "derived")
6091
6139
  continue;
6092
- const perl = ctx.convertExpressionToPerl(step.expr, step.parsed);
6140
+ const perl = ctx.convertExpressionToPerl(step.expr, step.parsed, "value");
6093
6141
  if (perl === "" || !/\$[A-Za-z_]\w*/.test(perl))
6094
6142
  continue;
6095
6143
  lines.push(`% my $${step.name} = ${perl};`);
@@ -6943,9 +6991,9 @@ ${reason}` : "";
6943
6991
  };
6944
6992
  }
6945
6993
  get memoCtx() {
6946
- return { convertExpressionToPerl: (e, preParsed) => this.convertExpressionToPerl(e, preParsed) };
6994
+ return { convertExpressionToPerl: (e, preParsed, pos) => this.convertExpressionToPerl(e, preParsed, pos) };
6947
6995
  }
6948
- convertExpressionToPerl(expr, preParsed) {
6996
+ convertExpressionToPerl(expr, preParsed, pos = "rendered") {
6949
6997
  let parsed;
6950
6998
  if (preParsed) {
6951
6999
  parsed = preParsed;
@@ -6968,7 +7016,7 @@ ${reason}` : "";
6968
7016
  }
6969
7017
  }
6970
7018
  }
6971
- const support = isSupported(parsed);
7019
+ const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
6972
7020
  if (!support.supported) {
6973
7021
  this.errors.push({
6974
7022
  code: "BF101",
@@ -1,5 +1,5 @@
1
1
  package BarefootJS::Backend::Mojo;
2
- our $VERSION = "0.31.10";
2
+ our $VERSION = "0.33.0";
3
3
  use Mojo::Base -base, -signatures;
4
4
 
5
5
  use Mojo::ByteStream qw(b);
@@ -1,5 +1,5 @@
1
1
  package Mojolicious::Plugin::BarefootJS::DevReload;
2
- our $VERSION = "0.31.10";
2
+ our $VERSION = "0.33.0";
3
3
  use Mojo::Base 'Mojolicious::Plugin', -signatures;
4
4
 
5
5
  =head1 NAME
@@ -1,5 +1,5 @@
1
1
  package Mojolicious::Plugin::BarefootJS;
2
- our $VERSION = "0.31.10";
2
+ our $VERSION = "0.33.0";
3
3
  use Mojo::Base 'Mojolicious::Plugin', -signatures;
4
4
 
5
5
  use Mojo::File qw(path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/mojolicious",
3
- "version": "0.32.0",
3
+ "version": "0.33.1",
4
4
  "description": "Mojolicious EP template adapter for BarefootJS - generates .html.ep files from IR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -52,7 +52,7 @@
52
52
  "directory": "packages/adapter-mojolicious"
53
53
  },
54
54
  "dependencies": {
55
- "@barefootjs/shared": "0.32.0"
55
+ "@barefootjs/shared": "0.33.1"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@barefootjs/jsx": ">=0.2.0",
@@ -70,9 +70,9 @@
70
70
  },
71
71
  "devDependencies": {
72
72
  "@barefootjs/adapter-tests": "0.1.0",
73
- "@barefootjs/jsx": "0.32.0",
74
- "@barefootjs/vite": "0.32.0",
75
- "@barefootjs/client": "0.32.0",
73
+ "@barefootjs/jsx": "0.33.1",
74
+ "@barefootjs/vite": "0.33.1",
75
+ "@barefootjs/client": "0.33.1",
76
76
  "vite": "^6.0.0"
77
77
  }
78
78
  }
@@ -11,6 +11,7 @@ import { renderMojoComponent, PerlNotAvailableError } from '../test-render'
11
11
  import { compileJSX, type ComponentIR } from '@barefootjs/jsx'
12
12
  import { conformancePins } from '../conformance-pins'
13
13
  import { renderDivergences } from '../render-divergences'
14
+ import { escapePerlSingleQuoted, perlHashKey } from '../adapter/lib/perl-naming'
14
15
 
15
16
  runAdapterConformanceTests({
16
17
  name: 'mojo',
@@ -2276,3 +2277,16 @@ export function Counter() {
2276
2277
  expect(template).not.toContain('<link')
2277
2278
  })
2278
2279
  })
2280
+
2281
+ // A backslash ahead of a quote must be escaped first, or the doubled
2282
+ // quote-escape eats the closing quote (`'a\'` unterminated) instead of
2283
+ // round-tripping the original bytes (PR #2698 review).
2284
+ describe('MojoAdapter - Perl single-quote escaping order (#2698 review)', () => {
2285
+ test('escapePerlSingleQuoted doubles a backslash before escaping a quote', () => {
2286
+ expect(escapePerlSingleQuoted("a\\'b")).toBe("a\\\\\\'b")
2287
+ })
2288
+
2289
+ test('perlHashKey applies the same backslash-first rule to a non-identifier key', () => {
2290
+ expect(perlHashKey("a\\'b")).toBe("'a\\\\\\'b'")
2291
+ })
2292
+ })
@@ -101,7 +101,10 @@ export interface MojoMemoContext {
101
101
  * re-parsing `expr` — mirrors go-template's
102
102
  * `convertExpressionToGo(jsExpr, out?, preParsed?)`. With `preParsed` set,
103
103
  * `expr` is unused for parsing (the converter derives any diagnostic text
104
- * from the tree), so callers may pass `''`.
104
+ * from the tree), so callers may pass `''`. `pos` (default `'rendered'`)
105
+ * must be `'value'` for a derived-seed RHS — an assignment, not a render —
106
+ * so the internal support gate matches the `isSupportedValue`
107
+ * classification the seed plan already used.
105
108
  */
106
- convertExpressionToPerl(expr: string, preParsed?: ParsedExpr): string
109
+ convertExpressionToPerl(expr: string, preParsed?: ParsedExpr, pos?: 'rendered' | 'value'): string
107
110
  }
@@ -31,6 +31,7 @@ import { groupBinaryOperand,
31
31
 
32
32
  import type { MojoEmitContext } from '../emit-context.ts'
33
33
  import { MOJO_TEMPLATE_PRIMITIVES } from '../lib/constants.ts'
34
+ import { escapePerlSingleQuoted } from '../lib/perl-naming.ts'
34
35
  import { emitIndexAccessPerl } from './operand.ts'
35
36
  import {
36
37
  renderArrayMethod,
@@ -700,16 +701,25 @@ export class MojoTopLevelEmitter implements ParsedExprEmitter {
700
701
  return "''"
701
702
  }
702
703
 
703
- objectLiteral(properties: ObjectLiteralProperty[], _raw: string, _emit: (e: ParsedExpr) => string): string {
704
- // The shared `isSupported` gate only ever lets this dispatcher see an
705
- // object literal as the EMPTY (`?? {}`) fallback operand of `??`
706
- // (expression-parser.ts, `logical` case) any other object literal is
707
- // refused before reaching here. Emit Perl's real empty hashref literal,
708
- // matching the `'{}'` convention `objectLiteralToPerlHashref` already
709
- // uses for the zero-property case in the spread path. A populated
710
- // literal is structurally unreachable given the gate, but still
711
- // degrades safely to the pre-existing empty-string sentinel rather
712
- // than silently dropping keys.
713
- return properties.length === 0 ? '{}' : "''"
704
+ objectLiteral(properties: ObjectLiteralProperty[], _raw: string, emit: (e: ParsedExpr) => string): string {
705
+ // Reachable here in VALUE position (a `.map()` receiver/callback body, an
706
+ // array-literal element, …) since `isSupportedValue` admits an object
707
+ // literal whose every property value is itself supported
708
+ // (expression-parser.ts, `checkSupport`'s `pos` parameter). Emit a Perl
709
+ // hashref literal, quoted the same way `objectLiteralToPerlHashref`
710
+ // quotes the spread-path literal.
711
+ if (properties.length === 0) return '{}'
712
+ // Spread (`{ ...t, editing: false }`, #2696 Step 2): real Perl hashref
713
+ // construction is a flat key/value LIST — `%{$expr}` (hash-dereference)
714
+ // interpolates every key/value pair of `$expr` into that list at its
715
+ // source position, and Perl's own list-to-hash construction keeps the
716
+ // LAST occurrence of a duplicate key, exactly matching JS spread's
717
+ // left-to-right override. So every entry (prop or spread) contributes
718
+ // its own list segment to ONE hashref literal — no merge CALL needed,
719
+ // unlike the other 6 adapters.
720
+ const parts = properties.map(p =>
721
+ p.kind === 'spread' ? `%{${emit(p.expr)}}` : `'${escapePerlSingleQuoted(p.key)}' => ${emit(p.value)}`,
722
+ )
723
+ return `{ ${parts.join(', ')} }`
714
724
  }
715
725
  }
@@ -7,6 +7,12 @@
7
7
  * and marker-id encoding.
8
8
  */
9
9
 
10
+ /** Escape a string for a Perl single-quoted literal: backslash first (so
11
+ * it doesn't double-escape the quote we add next), then the quote. */
12
+ export function escapePerlSingleQuoted(s: string): string {
13
+ return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'")
14
+ }
15
+
10
16
  /**
11
17
  * (#checkbox) Quote a `render_child` named-arg / hashref key when it isn't a
12
18
  * bare Perl identifier. A JSX attribute name like `data-slot` would otherwise
@@ -15,7 +21,7 @@
15
21
  * through unquoted to keep the generated template readable.
16
22
  */
17
23
  export function perlHashKey(name: string): string {
18
- return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name.replace(/'/g, "\\'")}'`
24
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${escapePerlSingleQuoted(name)}'`
19
25
  }
20
26
 
21
27
  /**
@@ -65,7 +65,8 @@ export function generateDerivedMemoSeed(ctx: MojoMemoContext, ir: ComponentIR):
65
65
  const lines: string[] = []
66
66
  for (const step of plan.steps) {
67
67
  if (step.kind !== 'derived') continue
68
- const perl = ctx.convertExpressionToPerl(step.expr, step.parsed)
68
+ // `'value'` this RHS is an assignment, not a render (#2696 review).
69
+ const perl = ctx.convertExpressionToPerl(step.expr, step.parsed, 'value')
69
70
  if (perl === '' || !/\$[A-Za-z_]\w*/.test(perl)) continue
70
71
  lines.push(`% my $${step.name} = ${perl};`)
71
72
  }
@@ -41,6 +41,7 @@ import {
41
41
  stringifyParsedExpr,
42
42
  parseStyleObjectEntries,
43
43
  isSupported,
44
+ isSupportedValue,
44
45
  exprToString,
45
46
  parseProviderObjectLiteral,
46
47
  emitParsedExpr,
@@ -1830,10 +1831,10 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
1830
1831
 
1831
1832
  /** Build the narrow context the extracted memo seeding depends on. */
1832
1833
  private get memoCtx(): MojoMemoContext {
1833
- return { convertExpressionToPerl: (e, preParsed) => this.convertExpressionToPerl(e, preParsed) }
1834
+ return { convertExpressionToPerl: (e, preParsed, pos) => this.convertExpressionToPerl(e, preParsed, pos) }
1834
1835
  }
1835
1836
 
1836
- private convertExpressionToPerl(expr: string, preParsed?: ParsedExpr): string {
1837
+ private convertExpressionToPerl(expr: string, preParsed?: ParsedExpr, pos: 'rendered' | 'value' = 'rendered'): string {
1837
1838
  // Parse-first lowering — parity with the Go adapter's
1838
1839
  // `convertExpressionToGo`. Parse the JS expression once, gate it on
1839
1840
  // the shared `isSupported`, and render every supported shape through
@@ -1890,7 +1891,11 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
1890
1891
  }
1891
1892
  }
1892
1893
 
1893
- const support = isSupported(parsed)
1894
+ // `pos` distinguishes a derived-seed RHS (an assignment, checked via
1895
+ // `isSupportedValue`) from every other, genuinely rendered call site —
1896
+ // the rendered gate would otherwise re-refuse a tree the seed plan
1897
+ // already classified `derived` at value position (#2696 review).
1898
+ const support = pos === 'value' ? isSupportedValue(parsed) : isSupported(parsed)
1894
1899
  if (!support.supported) {
1895
1900
  this.errors.push({
1896
1901
  code: 'BF101',
@@ -27,6 +27,7 @@ import { parseRecordIndexAccess, stringifyParsedExpr } from '@barefootjs/jsx'
27
27
  import type { ParsedExpr } from '@barefootjs/jsx'
28
28
 
29
29
  import type { MojoSpreadContext } from '../emit-context.ts'
30
+ import { escapePerlSingleQuoted } from '../lib/perl-naming.ts'
30
31
 
31
32
  /**
32
33
  * Lower a `cond ? {…} : {…}` conditional-spread expression — carried as the
@@ -80,6 +81,10 @@ export function objectLiteralToPerlHashref(
80
81
  ): string | null {
81
82
  const entries: string[] = []
82
83
  for (const prop of obj.properties) {
84
+ // A spread (`{ ...t }`, #2696 Step 2) isn't a per-key entry this
85
+ // conditional-spread inline lowering can express — bail, same as any
86
+ // other unsupported shape (the caller falls back to the generic path).
87
+ if (prop.kind === 'spread') return null
83
88
  // Shorthand `{ a }` was a `ShorthandPropertyAssignment` (not a
84
89
  // `PropertyAssignment`), so the former parser rejected it — keep refusing.
85
90
  if (prop.shorthand) return null
@@ -123,7 +128,7 @@ export function objectLiteralToPerlHashref(
123
128
  // Thread the carried `val` tree straight through as `preParsed` (#2018)
124
129
  // — no stringify→re-parse round-trip.
125
130
  : ctx.convertExpressionToPerl('', val)
126
- entries.push(`'${key.replace(/'/g, "\\'")}' => ${valPerl}`)
131
+ entries.push(`'${escapePerlSingleQuoted(key)}' => ${valPerl}`)
127
132
  }
128
133
  return entries.length === 0 ? '{}' : `{ ${entries.join(', ')} }`
129
134
  }
@@ -174,8 +179,8 @@ export function recordIndexAccessToPerl(ctx: MojoSpreadContext, val: ParsedExpr)
174
179
  if (!parsed) return null
175
180
  const entries = parsed.entries.map(e => {
176
181
  const mapVal =
177
- e.value.kind === 'number' ? e.value.text : `'${e.value.text.replace(/'/g, "\\'")}'`
178
- return `'${e.key.replace(/'/g, "\\'")}' => ${mapVal}`
182
+ e.value.kind === 'number' ? e.value.text : `'${escapePerlSingleQuoted(e.value.text)}'`
183
+ return `'${escapePerlSingleQuoted(e.key)}' => ${mapVal}`
179
184
  })
180
185
  return `{ ${entries.join(', ')} }->{$${parsed.indexPropName}}`
181
186
  }
@@ -49,4 +49,11 @@ export const conformancePins: ConformancePins = {
49
49
  'filter-nested-find-predicate': [{ code: 'BF101', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2320' }],
50
50
  'date-method-uncatalogued': [{ code: 'BF021', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2356' }],
51
51
  'rich-prop-client-read': [{ code: 'BF049', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2648' }],
52
+ // #2667: a ternary/array LITERALLY WRAPPING JSX at a non-children prop
53
+ // position (e.g. `header={cond ? <a/> : <b/>}`) is refused ahead of
54
+ // `adapter.generate()` in the shared jsx-to-ir.ts phase, so it is pinned
55
+ // identically on every adapter (including Hono) — same reasoning as
56
+ // `rich-prop-client-read` above.
57
+ 'jsx-element-prop-ternary': [{ code: 'BF021', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2667' }],
58
+ 'jsx-element-prop-array': [{ code: 'BF021', severity: 'error', issue: 'https://github.com/piconic-ai/barefootjs/issues/2667' }],
52
59
  }
@@ -9,11 +9,10 @@
9
9
 
10
10
  import type { RenderDivergences } from '@barefootjs/jsx'
11
11
 
12
- export const renderDivergences: RenderDivergences = {
13
- 'todo-app':
14
- 'the `todos` signal seeds from `(props.initialTodos ?? []).map(t => ({ ...t, editing: false }))` — a different-prop-derived `.map()` chain `extractSsrDefaults` cannot statically resolve, and `computeSsrSeedPlan` classifies it opaque (no in-template recompute), so it seeds `undef`; the non-`/* @client */`-marked `{todos().length > 0 && ...}` toggle-all block SSRs as if there are zero todos regardless of `initialTodos` (https://github.com/piconic-ai/barefootjs/issues/2696)',
15
- 'todo-app-ssr':
16
- "same root cause as `todo-app` (https://github.com/piconic-ai/barefootjs/issues/2696), but this fixture's todo-list loop carries no `/* @client */` marker — the compiled Mojo::Template loop iterates the undef-seeded `todos` directly and Perl's strict vars abort the render instead of producing HTML",
17
- 'callback-param-shadows-prop':
18
- "the `first` signal seeds from `[{ a: 'p' }].map((title) => title.a).join(',')` — a constant expression `extractSsrDefaults` still cannot statically resolve (`.map()` is unsupported for any receiver) and, unlike the sibling `joined` memo's structurally similar chain, gets no in-template recompute (`computeSsrSeedPlan` classifies it opaque too); `<span>{first()}</span>` SSRs empty instead of `p` (https://github.com/piconic-ai/barefootjs/issues/2696)",
19
- }
12
+ // #2696 graduated: `todo-app` / `todo-app-ssr` seeded `todos` opaque
13
+ // because their `.map(t => ({ ...t, editing: false }))` callback body's
14
+ // object-literal SPREAD refused (`checkSupport`). Step 2 admits a spread
15
+ // at value position and the runtime evaluator's `object-literal` case
16
+ // now merges it, so the seed classifies `derived` and SSRs identically
17
+ // to Hono.
18
+ export const renderDivergences: RenderDivergences = {}