@barefootjs/mojolicious 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/emit-context.d.ts +5 -2
- package/dist/adapter/emit-context.d.ts.map +1 -1
- package/dist/adapter/expr/emitters.d.ts +1 -1
- package/dist/adapter/expr/emitters.d.ts.map +1 -1
- package/dist/adapter/index.js +19 -10
- package/dist/adapter/lib/perl-naming.d.ts +3 -0
- package/dist/adapter/lib/perl-naming.d.ts.map +1 -1
- package/dist/adapter/memo/seed.d.ts.map +1 -1
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/adapter/spread/spread-codegen.d.ts.map +1 -1
- package/dist/index.js +20 -15
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/vite.js +92 -46
- package/lib/BarefootJS/Backend/Mojo.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS/DevReload.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS.pm +1 -1
- package/package.json +5 -5
- package/src/__tests__/mojo-adapter.test.ts +14 -0
- package/src/adapter/emit-context.ts +5 -2
- package/src/adapter/expr/emitters.ts +21 -11
- package/src/adapter/lib/perl-naming.ts +7 -1
- package/src/adapter/memo/seed.ts +2 -1
- package/src/adapter/mojo-adapter.ts +8 -3
- package/src/adapter/spread/spread-codegen.ts +8 -3
- package/src/render-divergences.ts +7 -8
|
@@ -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
|
|
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,
|
|
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":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACd,KAAK,YAAY,EAMlB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter/index.js
CHANGED
|
@@ -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
|
|
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,
|
|
784
|
-
|
|
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
|
|
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
|
|
935
|
-
return `'${e.key
|
|
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,
|
|
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,
|
|
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;
|
|
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"}
|
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
|
|
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,
|
|
784
|
-
|
|
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
|
|
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
|
|
935
|
-
return `'${e.key
|
|
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",
|
|
@@ -1930,11 +1939,7 @@ var conformancePins = {
|
|
|
1930
1939
|
"rich-prop-client-read": [{ code: "BF049", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2648" }]
|
|
1931
1940
|
};
|
|
1932
1941
|
// 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
|
-
};
|
|
1942
|
+
var renderDivergences = {};
|
|
1938
1943
|
export {
|
|
1939
1944
|
renderDivergences,
|
|
1940
1945
|
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;
|
|
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
|
|
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
|
-
|
|
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
|
}
|
|
@@ -2915,6 +2936,8 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
|
2915
2936
|
let tz = null;
|
|
2916
2937
|
const probeOptions = {};
|
|
2917
2938
|
for (const prop of options.properties) {
|
|
2939
|
+
if (prop.kind === "spread")
|
|
2940
|
+
return null;
|
|
2918
2941
|
if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
|
|
2919
2942
|
return null;
|
|
2920
2943
|
const value = String(prop.value.value);
|
|
@@ -3905,7 +3928,7 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
|
|
|
3905
3928
|
|
|
3906
3929
|
// ../jsx/src/ssr-seed-plan.ts
|
|
3907
3930
|
function classify(name, origin, expr, parsed, available) {
|
|
3908
|
-
if (!
|
|
3931
|
+
if (!isSupportedValue(parsed).supported)
|
|
3909
3932
|
return { kind: "opaque", name, origin };
|
|
3910
3933
|
const frees = freeIdentifiers(parsed);
|
|
3911
3934
|
if (frees === null)
|
|
@@ -3968,7 +3991,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3968
3991
|
}
|
|
3969
3992
|
}
|
|
3970
3993
|
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));
|
|
3994
|
+
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(signal.parsed ?? parseExpression(`(${expr})`), localConsts), available));
|
|
3972
3995
|
available.add(signal.getter);
|
|
3973
3996
|
}
|
|
3974
3997
|
for (const memo of metadata.memos) {
|
|
@@ -4741,6 +4764,17 @@ function evaluateStaticLiteral(expr, bindings) {
|
|
|
4741
4764
|
case "object-literal": {
|
|
4742
4765
|
const out = {};
|
|
4743
4766
|
for (const prop of expr.properties) {
|
|
4767
|
+
if (prop.kind === "spread") {
|
|
4768
|
+
const resolved2 = evaluateStaticLiteral(prop.expr, bindings);
|
|
4769
|
+
if (!resolved2)
|
|
4770
|
+
return null;
|
|
4771
|
+
if (resolved2.value === null || resolved2.value === undefined)
|
|
4772
|
+
continue;
|
|
4773
|
+
if (typeof resolved2.value !== "object" || Array.isArray(resolved2.value))
|
|
4774
|
+
return null;
|
|
4775
|
+
Object.assign(out, resolved2.value);
|
|
4776
|
+
continue;
|
|
4777
|
+
}
|
|
4744
4778
|
const resolved = evaluateStaticLiteral(prop.value, bindings);
|
|
4745
4779
|
if (!resolved)
|
|
4746
4780
|
return null;
|
|
@@ -4807,6 +4841,8 @@ function matchQueryHrefCall(callee, args, localNames) {
|
|
|
4807
4841
|
return null;
|
|
4808
4842
|
const triples = [];
|
|
4809
4843
|
for (const p of obj.properties) {
|
|
4844
|
+
if (p.kind === "spread")
|
|
4845
|
+
return null;
|
|
4810
4846
|
const v = p.value;
|
|
4811
4847
|
if (v.kind === "conditional" && isOmitBranch(v.alternate)) {
|
|
4812
4848
|
triples.push({ guard: v.test, key: p.key, value: v.consequent });
|
|
@@ -4994,6 +5030,8 @@ function htmlPropValue(parsed) {
|
|
|
4994
5030
|
if (parsed.properties.length !== 1)
|
|
4995
5031
|
return null;
|
|
4996
5032
|
const [prop] = parsed.properties;
|
|
5033
|
+
if (prop.kind === "spread")
|
|
5034
|
+
return null;
|
|
4997
5035
|
if (prop.key !== "__html")
|
|
4998
5036
|
return null;
|
|
4999
5037
|
return prop.value;
|
|
@@ -5245,8 +5283,11 @@ var MOJO_TEMPLATE_PRIMITIVES = {
|
|
|
5245
5283
|
var MOJO_PRIMITIVE_EMIT_MAP = Object.fromEntries(Object.entries(MOJO_TEMPLATE_PRIMITIVES).map(([k, v]) => [k, v.emit]));
|
|
5246
5284
|
|
|
5247
5285
|
// src/adapter/lib/perl-naming.ts
|
|
5286
|
+
function escapePerlSingleQuoted(s) {
|
|
5287
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
5288
|
+
}
|
|
5248
5289
|
function perlHashKey(name) {
|
|
5249
|
-
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${name
|
|
5290
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${escapePerlSingleQuoted(name)}'`;
|
|
5250
5291
|
}
|
|
5251
5292
|
function perlIdentifierFromMarkerId(markerId) {
|
|
5252
5293
|
return markerId.replace(/[^a-zA-Z0-9]/g, (ch) => ch === "_" ? "__" : `_x${ch.charCodeAt(0).toString(16)}`);
|
|
@@ -5908,8 +5949,11 @@ class MojoTopLevelEmitter {
|
|
|
5908
5949
|
unsupported(_raw, _reason) {
|
|
5909
5950
|
return "''";
|
|
5910
5951
|
}
|
|
5911
|
-
objectLiteral(properties, _raw,
|
|
5912
|
-
|
|
5952
|
+
objectLiteral(properties, _raw, emit) {
|
|
5953
|
+
if (properties.length === 0)
|
|
5954
|
+
return "{}";
|
|
5955
|
+
const parts = properties.map((p) => p.kind === "spread" ? `%{${emit(p.expr)}}` : `'${escapePerlSingleQuoted(p.key)}' => ${emit(p.value)}`);
|
|
5956
|
+
return `{ ${parts.join(", ")} }`;
|
|
5913
5957
|
}
|
|
5914
5958
|
}
|
|
5915
5959
|
|
|
@@ -6022,6 +6066,8 @@ function objectLiteralExprToPerlHashref(ctx, expr) {
|
|
|
6022
6066
|
function objectLiteralToPerlHashref(ctx, obj) {
|
|
6023
6067
|
const entries = [];
|
|
6024
6068
|
for (const prop of obj.properties) {
|
|
6069
|
+
if (prop.kind === "spread")
|
|
6070
|
+
return null;
|
|
6025
6071
|
if (prop.shorthand)
|
|
6026
6072
|
return null;
|
|
6027
6073
|
if (prop.keyKind === "numeric")
|
|
@@ -6042,7 +6088,7 @@ function objectLiteralToPerlHashref(ctx, obj) {
|
|
|
6042
6088
|
return null;
|
|
6043
6089
|
}
|
|
6044
6090
|
const valPerl = indexed !== null ? indexed : ctx.convertExpressionToPerl("", val);
|
|
6045
|
-
entries.push(`'${key
|
|
6091
|
+
entries.push(`'${escapePerlSingleQuoted(key)}' => ${valPerl}`);
|
|
6046
6092
|
}
|
|
6047
6093
|
return entries.length === 0 ? "{}" : `{ ${entries.join(", ")} }`;
|
|
6048
6094
|
}
|
|
@@ -6058,8 +6104,8 @@ function recordIndexAccessToPerl(ctx, val) {
|
|
|
6058
6104
|
if (!parsed)
|
|
6059
6105
|
return null;
|
|
6060
6106
|
const entries = parsed.entries.map((e) => {
|
|
6061
|
-
const mapVal = e.value.kind === "number" ? e.value.text : `'${e.value.text
|
|
6062
|
-
return `'${e.key
|
|
6107
|
+
const mapVal = e.value.kind === "number" ? e.value.text : `'${escapePerlSingleQuoted(e.value.text)}'`;
|
|
6108
|
+
return `'${escapePerlSingleQuoted(e.key)}' => ${mapVal}`;
|
|
6063
6109
|
});
|
|
6064
6110
|
return `{ ${entries.join(", ")} }->{$${parsed.indexPropName}}`;
|
|
6065
6111
|
}
|
|
@@ -6089,7 +6135,7 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
6089
6135
|
for (const step of plan.steps) {
|
|
6090
6136
|
if (step.kind !== "derived")
|
|
6091
6137
|
continue;
|
|
6092
|
-
const perl = ctx.convertExpressionToPerl(step.expr, step.parsed);
|
|
6138
|
+
const perl = ctx.convertExpressionToPerl(step.expr, step.parsed, "value");
|
|
6093
6139
|
if (perl === "" || !/\$[A-Za-z_]\w*/.test(perl))
|
|
6094
6140
|
continue;
|
|
6095
6141
|
lines.push(`% my $${step.name} = ${perl};`);
|
|
@@ -6943,9 +6989,9 @@ ${reason}` : "";
|
|
|
6943
6989
|
};
|
|
6944
6990
|
}
|
|
6945
6991
|
get memoCtx() {
|
|
6946
|
-
return { convertExpressionToPerl: (e, preParsed) => this.convertExpressionToPerl(e, preParsed) };
|
|
6992
|
+
return { convertExpressionToPerl: (e, preParsed, pos) => this.convertExpressionToPerl(e, preParsed, pos) };
|
|
6947
6993
|
}
|
|
6948
|
-
convertExpressionToPerl(expr, preParsed) {
|
|
6994
|
+
convertExpressionToPerl(expr, preParsed, pos = "rendered") {
|
|
6949
6995
|
let parsed;
|
|
6950
6996
|
if (preParsed) {
|
|
6951
6997
|
parsed = preParsed;
|
|
@@ -6968,7 +7014,7 @@ ${reason}` : "";
|
|
|
6968
7014
|
}
|
|
6969
7015
|
}
|
|
6970
7016
|
}
|
|
6971
|
-
const support = isSupported(parsed);
|
|
7017
|
+
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
6972
7018
|
if (!support.supported) {
|
|
6973
7019
|
this.errors.push({
|
|
6974
7020
|
code: "BF101",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/mojolicious",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
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.
|
|
55
|
+
"@barefootjs/shared": "0.33.0"
|
|
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.
|
|
74
|
-
"@barefootjs/vite": "0.
|
|
75
|
-
"@barefootjs/client": "0.
|
|
73
|
+
"@barefootjs/jsx": "0.33.0",
|
|
74
|
+
"@barefootjs/vite": "0.33.0",
|
|
75
|
+
"@barefootjs/client": "0.33.0",
|
|
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,
|
|
704
|
-
//
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
|
|
711
|
-
//
|
|
712
|
-
//
|
|
713
|
-
|
|
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
|
|
24
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? name : `'${escapePerlSingleQuoted(name)}'`
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
/**
|
package/src/adapter/memo/seed.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
178
|
-
return `'${e.key
|
|
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
|
}
|
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
import type { RenderDivergences } from '@barefootjs/jsx'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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 = {}
|