@barefootjs/mojolicious 0.33.6 → 0.35.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 +11 -1
- package/dist/adapter/emit-context.d.ts.map +1 -1
- package/dist/adapter/expr/emitters.d.ts +11 -1
- package/dist/adapter/expr/emitters.d.ts.map +1 -1
- package/dist/adapter/index.js +28 -22
- package/dist/adapter/mojo-adapter.d.ts +3 -0
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +29 -26
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/vite.js +119 -72
- 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/adapter/emit-context.ts +12 -1
- package/src/adapter/expr/emitters.ts +33 -0
- package/src/adapter/mojo-adapter.ts +23 -43
- package/src/conformance-pins.ts +4 -0
- package/src/render-divergences.ts +1 -16
- package/src/test-render.ts +38 -0
|
@@ -17,13 +17,23 @@
|
|
|
17
17
|
* genuinely needs it, so the seam documents the real cross-module coupling
|
|
18
18
|
* rather than re-exposing the whole adapter.
|
|
19
19
|
*/
|
|
20
|
-
import type { ParsedExpr, CompilerError, IRMetadata } from '@barefootjs/jsx';
|
|
20
|
+
import type { ParsedExpr, CompilerError, IRMetadata, LoweringMatcher } from '@barefootjs/jsx';
|
|
21
21
|
export interface MojoEmitContext {
|
|
22
22
|
/**
|
|
23
23
|
* (#1922) Local binding names the request-scoped `searchParams()` env signal
|
|
24
24
|
* is imported under. Non-empty enables the env-signal method-call lowering.
|
|
25
25
|
*/
|
|
26
26
|
readonly _searchParamsLocals: Set<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Registered lowering-plugin matchers (#2057), bound to this component's
|
|
29
|
+
* metadata at init. Read by `MojoTopLevelEmitter`'s `lowering` seam (#2843)
|
|
30
|
+
* so a registered call — the built-in `queryHref`, or any userland plugin —
|
|
31
|
+
* is recognised no matter where it sits in an expression tree (a ternary
|
|
32
|
+
* branch, a template-literal interpolation, …), not only when it's the call
|
|
33
|
+
* the adapter's own top-level conversion entry point
|
|
34
|
+
* (`convertExpressionToPerl`) is asked to lower directly.
|
|
35
|
+
*/
|
|
36
|
+
readonly _loweringMatchers: readonly LoweringMatcher[];
|
|
27
37
|
/**
|
|
28
38
|
* Inline a module-scope pure string-literal const by name as the resolved
|
|
29
39
|
* literal value, or null when the name is not such a const.
|
|
@@ -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;
|
|
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,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE7F,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAEzC;;;;;;;;OAQG;IACH,QAAQ,CAAC,iBAAiB,EAAE,SAAS,eAAe,EAAE,CAAA;IAEtD;;;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"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - `MojoTopLevelEmitter` — top-level / stash context; depends on the
|
|
11
11
|
* adapter only through the narrow `MojoEmitContext` seam.
|
|
12
12
|
*/
|
|
13
|
-
import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
|
|
13
|
+
import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart, type LoweringEmitter } from '@barefootjs/jsx';
|
|
14
14
|
import type { MojoEmitContext } from '../emit-context.ts';
|
|
15
15
|
export declare class MojoFilterEmitter implements ParsedExprEmitter {
|
|
16
16
|
private readonly param;
|
|
@@ -55,6 +55,16 @@ export declare class MojoFilterEmitter implements ParsedExprEmitter {
|
|
|
55
55
|
export declare class MojoTopLevelEmitter implements ParsedExprEmitter {
|
|
56
56
|
private readonly ctx;
|
|
57
57
|
constructor(ctx: MojoEmitContext);
|
|
58
|
+
/**
|
|
59
|
+
* Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
|
|
60
|
+
* tries every matcher here BEFORE `call()` itself, so a registered call
|
|
61
|
+
* (the built-in `queryHref`, or any userland plugin) is recognised no
|
|
62
|
+
* matter where it sits in the tree. `render` is what used to live inline
|
|
63
|
+
* in `MojoAdapter.convertExpressionToPerl` before the object-literal
|
|
64
|
+
* support-gate refusal (`checkSupport`'s `call` arm, now itself
|
|
65
|
+
* registry-aware) made the pre-gate special case unnecessary.
|
|
66
|
+
*/
|
|
67
|
+
get lowering(): LoweringEmitter;
|
|
58
68
|
identifier(name: string): string;
|
|
59
69
|
literal(value: string | number | boolean | null, literalType: LiteralType): string;
|
|
60
70
|
member(object: ParsedExpr, property: string, _computed: boolean, _optional: boolean, emit: (e: ParsedExpr) => string): string;
|
|
@@ -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,
|
|
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
|
@@ -17,8 +17,6 @@ import {
|
|
|
17
17
|
lookupStaticRecordLiteral,
|
|
18
18
|
searchParamsLocalNames,
|
|
19
19
|
prepareLoweringMatchers,
|
|
20
|
-
queryHrefArgs,
|
|
21
|
-
isValidHelperId,
|
|
22
20
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
23
21
|
isLowerableLoopDestructure,
|
|
24
22
|
isDangerousInnerHtmlAttr,
|
|
@@ -363,7 +361,9 @@ import {
|
|
|
363
361
|
identifierPath,
|
|
364
362
|
matchSearchParamsMethodCall,
|
|
365
363
|
sortComparatorFromArrow,
|
|
366
|
-
asCallbackMethodCall
|
|
364
|
+
asCallbackMethodCall,
|
|
365
|
+
queryHrefArgs,
|
|
366
|
+
isValidHelperId
|
|
367
367
|
} from "@barefootjs/jsx";
|
|
368
368
|
|
|
369
369
|
// src/adapter/expr/operand.ts
|
|
@@ -525,6 +525,21 @@ class MojoTopLevelEmitter {
|
|
|
525
525
|
constructor(ctx) {
|
|
526
526
|
this.ctx = ctx;
|
|
527
527
|
}
|
|
528
|
+
get lowering() {
|
|
529
|
+
return {
|
|
530
|
+
matchers: this.ctx._loweringMatchers,
|
|
531
|
+
render: (node, emit) => {
|
|
532
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
533
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
534
|
+
return `bf->query(${qArgs.join(", ")})`;
|
|
535
|
+
}
|
|
536
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
537
|
+
return `bf->${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
528
543
|
identifier(name) {
|
|
529
544
|
if (name === "undefined" || name === "null")
|
|
530
545
|
return "undef";
|
|
@@ -1102,7 +1117,9 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1102
1117
|
return null;
|
|
1103
1118
|
return {
|
|
1104
1119
|
condition: exprToString(parsed.test),
|
|
1105
|
-
consequent: exprToString(parsed.consequent)
|
|
1120
|
+
consequent: exprToString(parsed.consequent),
|
|
1121
|
+
testParsed: parsed.test,
|
|
1122
|
+
consequentParsed: parsed.consequent
|
|
1106
1123
|
};
|
|
1107
1124
|
}
|
|
1108
1125
|
resolveLiteralConst(name) {
|
|
@@ -1429,7 +1446,7 @@ ${whenTrue}
|
|
|
1429
1446
|
const prevScope = this.scope;
|
|
1430
1447
|
this.scope = prevScope.enterLoopRow(loop);
|
|
1431
1448
|
const renderedChildren = this.renderChildren(loop.children);
|
|
1432
|
-
const children = loop.bodyIsItemConditional && loop.key ? `<%== bf->comment("loop-i:" . ${this.convertExpressionToPerl(loop.key)}) %>
|
|
1449
|
+
const children = loop.bodyIsItemConditional && loop.key ? `<%== bf->comment("loop-i:" . bf->escape_comment_key(${this.convertExpressionToPerl(loop.key)})) %>
|
|
1433
1450
|
${renderedChildren}` : renderedChildren;
|
|
1434
1451
|
const lines = [];
|
|
1435
1452
|
lines.push(`<%== bf->comment("loop:${loop.markerId}") %>`);
|
|
@@ -1630,8 +1647,8 @@ ${children}`;
|
|
|
1630
1647
|
{
|
|
1631
1648
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
1632
1649
|
if (m) {
|
|
1633
|
-
const cond = this.convertExpressionToPerl(m.
|
|
1634
|
-
const val = this.convertExpressionToPerl(m.
|
|
1650
|
+
const cond = this.convertExpressionToPerl("", m.testParsed);
|
|
1651
|
+
const val = this.convertExpressionToPerl("", m.consequentParsed);
|
|
1635
1652
|
return `<% if (${cond}) { %>${name}="<%= ${val} %>"<% } %>`;
|
|
1636
1653
|
}
|
|
1637
1654
|
}
|
|
@@ -1760,7 +1777,7 @@ ${children}`;
|
|
|
1760
1777
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
1761
1778
|
return false;
|
|
1762
1779
|
const parsed = parseExpression2(expr.trim());
|
|
1763
|
-
const support = isSupported(parsed);
|
|
1780
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
1764
1781
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
1765
1782
|
return false;
|
|
1766
1783
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -1780,6 +1797,7 @@ ${reason}` : "";
|
|
|
1780
1797
|
get emitCtx() {
|
|
1781
1798
|
return {
|
|
1782
1799
|
_searchParamsLocals: this._searchParamsLocals,
|
|
1800
|
+
_loweringMatchers: this._loweringMatchers,
|
|
1783
1801
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
1784
1802
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
1785
1803
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -1810,20 +1828,8 @@ ${reason}` : "";
|
|
|
1810
1828
|
return "''";
|
|
1811
1829
|
parsed = parseExpression2(trimmed);
|
|
1812
1830
|
}
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
1816
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
1817
|
-
const argsGo = queryHrefArgs(node, (n) => this.renderParsedExprToPerl(n));
|
|
1818
|
-
return `bf->query(${argsGo.join(", ")})`;
|
|
1819
|
-
}
|
|
1820
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
1821
|
-
const argsX = node.args.map((a) => this.renderParsedExprToPerl(a));
|
|
1822
|
-
return `bf->${node.helper}(${argsX.join(", ")})`;
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
1831
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
1832
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
1827
1833
|
if (!support.supported) {
|
|
1828
1834
|
this.errors.push({
|
|
1829
1835
|
code: "BF101",
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { ComponentIR, IRNode, IRElement, IRText, IRExpression, IRConditional, IRLoop, IRComponent, IRFragment, IRSlot, IRIfStatement, IRProvider, IRAsync, TemplatePrimitiveRegistry } from '@barefootjs/jsx';
|
|
7
7
|
import { BaseAdapter, type AdapterOutput, type AdapterGenerateOptions, type IRNodeEmitter, type EmitIRNode } from '@barefootjs/jsx';
|
|
8
|
+
import type { ParsedExpr } from '@barefootjs/jsx';
|
|
8
9
|
import type { MojoRenderCtx } from './lib/types.ts';
|
|
9
10
|
export type { MojoAdapterOptions } from './lib/types.ts';
|
|
10
11
|
import type { MojoAdapterOptions } from './lib/types.ts';
|
|
@@ -162,6 +163,8 @@ export declare class MojoAdapter extends BaseAdapter implements IRNodeEmitter<Mo
|
|
|
162
163
|
parseUndefinedAlternateTernary(expr: string): {
|
|
163
164
|
condition: string;
|
|
164
165
|
consequent: string;
|
|
166
|
+
testParsed: ParsedExpr;
|
|
167
|
+
consequentParsed: ParsedExpr;
|
|
165
168
|
} | null;
|
|
166
169
|
/**
|
|
167
170
|
* Inline a const (any scope) whose initializer is a pure numeric or
|
|
@@ -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":"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,
|
|
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,eA0D7B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -17,8 +17,6 @@ import {
|
|
|
17
17
|
lookupStaticRecordLiteral,
|
|
18
18
|
searchParamsLocalNames,
|
|
19
19
|
prepareLoweringMatchers,
|
|
20
|
-
queryHrefArgs,
|
|
21
|
-
isValidHelperId,
|
|
22
20
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
23
21
|
isLowerableLoopDestructure,
|
|
24
22
|
isDangerousInnerHtmlAttr,
|
|
@@ -363,7 +361,9 @@ import {
|
|
|
363
361
|
identifierPath,
|
|
364
362
|
matchSearchParamsMethodCall,
|
|
365
363
|
sortComparatorFromArrow,
|
|
366
|
-
asCallbackMethodCall
|
|
364
|
+
asCallbackMethodCall,
|
|
365
|
+
queryHrefArgs,
|
|
366
|
+
isValidHelperId
|
|
367
367
|
} from "@barefootjs/jsx";
|
|
368
368
|
|
|
369
369
|
// src/adapter/expr/operand.ts
|
|
@@ -525,6 +525,21 @@ class MojoTopLevelEmitter {
|
|
|
525
525
|
constructor(ctx) {
|
|
526
526
|
this.ctx = ctx;
|
|
527
527
|
}
|
|
528
|
+
get lowering() {
|
|
529
|
+
return {
|
|
530
|
+
matchers: this.ctx._loweringMatchers,
|
|
531
|
+
render: (node, emit) => {
|
|
532
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
533
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
534
|
+
return `bf->query(${qArgs.join(", ")})`;
|
|
535
|
+
}
|
|
536
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
537
|
+
return `bf->${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
528
543
|
identifier(name) {
|
|
529
544
|
if (name === "undefined" || name === "null")
|
|
530
545
|
return "undef";
|
|
@@ -1102,7 +1117,9 @@ class MojoAdapter extends BaseAdapter {
|
|
|
1102
1117
|
return null;
|
|
1103
1118
|
return {
|
|
1104
1119
|
condition: exprToString(parsed.test),
|
|
1105
|
-
consequent: exprToString(parsed.consequent)
|
|
1120
|
+
consequent: exprToString(parsed.consequent),
|
|
1121
|
+
testParsed: parsed.test,
|
|
1122
|
+
consequentParsed: parsed.consequent
|
|
1106
1123
|
};
|
|
1107
1124
|
}
|
|
1108
1125
|
resolveLiteralConst(name) {
|
|
@@ -1429,7 +1446,7 @@ ${whenTrue}
|
|
|
1429
1446
|
const prevScope = this.scope;
|
|
1430
1447
|
this.scope = prevScope.enterLoopRow(loop);
|
|
1431
1448
|
const renderedChildren = this.renderChildren(loop.children);
|
|
1432
|
-
const children = loop.bodyIsItemConditional && loop.key ? `<%== bf->comment("loop-i:" . ${this.convertExpressionToPerl(loop.key)}) %>
|
|
1449
|
+
const children = loop.bodyIsItemConditional && loop.key ? `<%== bf->comment("loop-i:" . bf->escape_comment_key(${this.convertExpressionToPerl(loop.key)})) %>
|
|
1433
1450
|
${renderedChildren}` : renderedChildren;
|
|
1434
1451
|
const lines = [];
|
|
1435
1452
|
lines.push(`<%== bf->comment("loop:${loop.markerId}") %>`);
|
|
@@ -1630,8 +1647,8 @@ ${children}`;
|
|
|
1630
1647
|
{
|
|
1631
1648
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
1632
1649
|
if (m) {
|
|
1633
|
-
const cond = this.convertExpressionToPerl(m.
|
|
1634
|
-
const val = this.convertExpressionToPerl(m.
|
|
1650
|
+
const cond = this.convertExpressionToPerl("", m.testParsed);
|
|
1651
|
+
const val = this.convertExpressionToPerl("", m.consequentParsed);
|
|
1635
1652
|
return `<% if (${cond}) { %>${name}="<%= ${val} %>"<% } %>`;
|
|
1636
1653
|
}
|
|
1637
1654
|
}
|
|
@@ -1760,7 +1777,7 @@ ${children}`;
|
|
|
1760
1777
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
1761
1778
|
return false;
|
|
1762
1779
|
const parsed = parseExpression2(expr.trim());
|
|
1763
|
-
const support = isSupported(parsed);
|
|
1780
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
1764
1781
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
1765
1782
|
return false;
|
|
1766
1783
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -1780,6 +1797,7 @@ ${reason}` : "";
|
|
|
1780
1797
|
get emitCtx() {
|
|
1781
1798
|
return {
|
|
1782
1799
|
_searchParamsLocals: this._searchParamsLocals,
|
|
1800
|
+
_loweringMatchers: this._loweringMatchers,
|
|
1783
1801
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
1784
1802
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
1785
1803
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -1810,20 +1828,8 @@ ${reason}` : "";
|
|
|
1810
1828
|
return "''";
|
|
1811
1829
|
parsed = parseExpression2(trimmed);
|
|
1812
1830
|
}
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
1816
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
1817
|
-
const argsGo = queryHrefArgs(node, (n) => this.renderParsedExprToPerl(n));
|
|
1818
|
-
return `bf->query(${argsGo.join(", ")})`;
|
|
1819
|
-
}
|
|
1820
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
1821
|
-
const argsX = node.args.map((a) => this.renderParsedExprToPerl(a));
|
|
1822
|
-
return `bf->${node.helper}(${argsX.join(", ")})`;
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
1831
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
1832
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
1827
1833
|
if (!support.supported) {
|
|
1828
1834
|
this.errors.push({
|
|
1829
1835
|
code: "BF101",
|
|
@@ -1908,10 +1914,7 @@ var conformancePins = {
|
|
|
1908
1914
|
"namespace-import-primitive": [{ code: "BF013", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2771" }]
|
|
1909
1915
|
};
|
|
1910
1916
|
// src/render-divergences.ts
|
|
1911
|
-
var renderDivergences = {
|
|
1912
|
-
"children-passthrough-renamed": "A renamed `children` destructure emits the local alias as a template variable; the stash defines only `children`, so the Perl render dies (#2788).",
|
|
1913
|
-
"aliased-loop-source": "A `.map()` loop whose source is a local const alias of a signal getter (`const items__alias = items`) dies inside `Mojo::Template::process` on real Mojolicious — the seeded loop data is keyed by the signal's real name (`items`), and the alias hop is never resolved when deciding what to seed under `items__alias`. This is the SSR-side twin of #2778 (fixed for the CSR client-JS template in the same PR that added this fixture) — that fix only touches client-JS emission, not SSR data-seeding. Tracked at https://github.com/piconic-ai/barefootjs/issues/2813; graduate by resolving the alias hop at SSR-seeding time using the same `resolveAliasOrigin`/`resolveGetterAliases` mechanism #2778 introduced, rather than a third alias-hop walker."
|
|
1914
|
-
};
|
|
1917
|
+
var renderDivergences = {};
|
|
1915
1918
|
export {
|
|
1916
1919
|
renderDivergences,
|
|
1917
1920
|
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
|
@@ -12,6 +12,41 @@ import ts10 from "typescript";
|
|
|
12
12
|
|
|
13
13
|
// ../jsx/src/expression-parser.ts
|
|
14
14
|
import ts from "typescript";
|
|
15
|
+
|
|
16
|
+
// ../jsx/src/lowering-registry.ts
|
|
17
|
+
var plugins = [];
|
|
18
|
+
function registerLoweringPlugin(plugin) {
|
|
19
|
+
const existing = plugins.findIndex((p) => p.name === plugin.name);
|
|
20
|
+
if (existing >= 0)
|
|
21
|
+
plugins[existing] = plugin;
|
|
22
|
+
else
|
|
23
|
+
plugins.push(plugin);
|
|
24
|
+
}
|
|
25
|
+
function prepareLoweringMatchers(metadata) {
|
|
26
|
+
const matchers = [];
|
|
27
|
+
for (const plugin of plugins) {
|
|
28
|
+
const matcher = plugin.prepare(metadata);
|
|
29
|
+
if (matcher)
|
|
30
|
+
matchers.push(matcher);
|
|
31
|
+
}
|
|
32
|
+
return matchers;
|
|
33
|
+
}
|
|
34
|
+
function loweringNodeChildren(node) {
|
|
35
|
+
if (node.kind === "helper-call")
|
|
36
|
+
return [...node.args];
|
|
37
|
+
const children = [node.base];
|
|
38
|
+
for (const t of node.triples) {
|
|
39
|
+
if (t.guard)
|
|
40
|
+
children.push(t.guard);
|
|
41
|
+
children.push(t.value);
|
|
42
|
+
}
|
|
43
|
+
return children;
|
|
44
|
+
}
|
|
45
|
+
function isValidHelperId(helper) {
|
|
46
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(helper);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ../jsx/src/expression-parser.ts
|
|
15
50
|
var UNSUPPORTED_METHODS = new Set([
|
|
16
51
|
"filter",
|
|
17
52
|
"map",
|
|
@@ -263,7 +298,7 @@ function convertNode(node, raw) {
|
|
|
263
298
|
}
|
|
264
299
|
if (n === undefined || Number.isNaN(n)) {
|
|
265
300
|
const parsedDepth = convertNode(depthNode, raw);
|
|
266
|
-
if (checkSupport(parsedDepth, "rendered").supported) {
|
|
301
|
+
if (checkSupport(parsedDepth, "rendered", []).supported) {
|
|
267
302
|
depthExpr = parsedDepth;
|
|
268
303
|
flatDepth = 1;
|
|
269
304
|
} else {
|
|
@@ -1041,13 +1076,13 @@ function getUnaryOperatorString(op) {
|
|
|
1041
1076
|
return "unknown";
|
|
1042
1077
|
}
|
|
1043
1078
|
}
|
|
1044
|
-
function isSupported(expr) {
|
|
1045
|
-
return checkSupport(expr, "rendered");
|
|
1079
|
+
function isSupported(expr, opts) {
|
|
1080
|
+
return checkSupport(expr, "rendered", opts?.loweringMatchers ?? []);
|
|
1046
1081
|
}
|
|
1047
|
-
function isSupportedValue(expr) {
|
|
1048
|
-
return checkSupport(expr, "value");
|
|
1082
|
+
function isSupportedValue(expr, opts) {
|
|
1083
|
+
return checkSupport(expr, "value", opts?.loweringMatchers ?? []);
|
|
1049
1084
|
}
|
|
1050
|
-
function checkSupport(expr, pos) {
|
|
1085
|
+
function checkSupport(expr, pos, matchers) {
|
|
1051
1086
|
switch (expr.kind) {
|
|
1052
1087
|
case "unsupported":
|
|
1053
1088
|
return { supported: false, reason: expr.reason };
|
|
@@ -1056,7 +1091,7 @@ function checkSupport(expr, pos) {
|
|
|
1056
1091
|
return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
|
|
1057
1092
|
}
|
|
1058
1093
|
for (const prop of expr.properties) {
|
|
1059
|
-
const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos);
|
|
1094
|
+
const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos, matchers);
|
|
1060
1095
|
if (!propSupport.supported)
|
|
1061
1096
|
return propSupport;
|
|
1062
1097
|
}
|
|
@@ -1071,7 +1106,7 @@ function checkSupport(expr, pos) {
|
|
|
1071
1106
|
return { supported: false, reason: "Standalone arrow functions / regex literals are not supported" };
|
|
1072
1107
|
case "array-literal": {
|
|
1073
1108
|
for (const el of expr.elements) {
|
|
1074
|
-
const elSupport = checkSupport(el, pos);
|
|
1109
|
+
const elSupport = checkSupport(el, pos, matchers);
|
|
1075
1110
|
if (!elSupport.supported)
|
|
1076
1111
|
return elSupport;
|
|
1077
1112
|
}
|
|
@@ -1084,28 +1119,39 @@ function checkSupport(expr, pos) {
|
|
|
1084
1119
|
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 */`
|
|
1085
1120
|
};
|
|
1086
1121
|
}
|
|
1087
|
-
const objSupport = checkSupport(expr.object, pos);
|
|
1122
|
+
const objSupport = checkSupport(expr.object, pos, matchers);
|
|
1088
1123
|
if (!objSupport.supported)
|
|
1089
1124
|
return objSupport;
|
|
1090
1125
|
for (const arg of expr.args) {
|
|
1091
|
-
const argSupport = checkSupport(arg, pos);
|
|
1126
|
+
const argSupport = checkSupport(arg, pos, matchers);
|
|
1092
1127
|
if (!argSupport.supported)
|
|
1093
1128
|
return argSupport;
|
|
1094
1129
|
}
|
|
1095
1130
|
if (expr.method === "flat" && expr.depthExpr) {
|
|
1096
|
-
const depthSupport = checkSupport(expr.depthExpr, pos);
|
|
1131
|
+
const depthSupport = checkSupport(expr.depthExpr, pos, matchers);
|
|
1097
1132
|
if (!depthSupport.supported)
|
|
1098
1133
|
return depthSupport;
|
|
1099
1134
|
}
|
|
1100
1135
|
return { supported: true, level: "L2" };
|
|
1101
1136
|
}
|
|
1102
1137
|
case "call": {
|
|
1138
|
+
for (const matcher of matchers) {
|
|
1139
|
+
const node = matcher(expr.callee, expr.args);
|
|
1140
|
+
if (!node)
|
|
1141
|
+
continue;
|
|
1142
|
+
for (const child of loweringNodeChildren(node)) {
|
|
1143
|
+
const childSupport = checkSupport(child, pos, matchers);
|
|
1144
|
+
if (!childSupport.supported)
|
|
1145
|
+
return childSupport;
|
|
1146
|
+
}
|
|
1147
|
+
return { supported: true, level: "L2" };
|
|
1148
|
+
}
|
|
1103
1149
|
const cb = asCallbackMethodCall(expr);
|
|
1104
1150
|
if (cb) {
|
|
1105
|
-
const objSupport = checkSupport(cb.object, pos);
|
|
1151
|
+
const objSupport = checkSupport(cb.object, pos, matchers);
|
|
1106
1152
|
if (!objSupport.supported)
|
|
1107
1153
|
return objSupport;
|
|
1108
|
-
const bodySupport = checkSupport(cb.arrow.body, pos);
|
|
1154
|
+
const bodySupport = checkSupport(cb.arrow.body, pos, matchers);
|
|
1109
1155
|
if (!bodySupport.supported) {
|
|
1110
1156
|
return {
|
|
1111
1157
|
supported: false,
|
|
@@ -1114,13 +1160,13 @@ function checkSupport(expr, pos) {
|
|
|
1114
1160
|
};
|
|
1115
1161
|
}
|
|
1116
1162
|
for (const rest of cb.args) {
|
|
1117
|
-
const restSupport = checkSupport(rest, pos);
|
|
1163
|
+
const restSupport = checkSupport(rest, pos, matchers);
|
|
1118
1164
|
if (!restSupport.supported)
|
|
1119
1165
|
return restSupport;
|
|
1120
1166
|
}
|
|
1121
1167
|
return { supported: true, level: "L5" };
|
|
1122
1168
|
}
|
|
1123
|
-
const calleeSupport = checkSupport(expr.callee, pos);
|
|
1169
|
+
const calleeSupport = checkSupport(expr.callee, pos, matchers);
|
|
1124
1170
|
if (!calleeSupport.supported) {
|
|
1125
1171
|
return calleeSupport;
|
|
1126
1172
|
}
|
|
@@ -1139,7 +1185,7 @@ function checkSupport(expr, pos) {
|
|
|
1139
1185
|
return { supported: true, level: "L1" };
|
|
1140
1186
|
}
|
|
1141
1187
|
for (const arg of expr.args) {
|
|
1142
|
-
const argSupport = checkSupport(arg, pos);
|
|
1188
|
+
const argSupport = checkSupport(arg, pos, matchers);
|
|
1143
1189
|
if (!argSupport.supported) {
|
|
1144
1190
|
return argSupport;
|
|
1145
1191
|
}
|
|
@@ -1147,7 +1193,7 @@ function checkSupport(expr, pos) {
|
|
|
1147
1193
|
return { supported: true, level: "L2" };
|
|
1148
1194
|
}
|
|
1149
1195
|
case "member": {
|
|
1150
|
-
const objSupport = checkSupport(expr.object, pos);
|
|
1196
|
+
const objSupport = checkSupport(expr.object, pos, matchers);
|
|
1151
1197
|
if (!objSupport.supported) {
|
|
1152
1198
|
return objSupport;
|
|
1153
1199
|
}
|
|
@@ -1157,19 +1203,19 @@ function checkSupport(expr, pos) {
|
|
|
1157
1203
|
return { supported: true, level: "L2" };
|
|
1158
1204
|
}
|
|
1159
1205
|
case "index-access": {
|
|
1160
|
-
const objSupport = checkSupport(expr.object, pos);
|
|
1206
|
+
const objSupport = checkSupport(expr.object, pos, matchers);
|
|
1161
1207
|
if (!objSupport.supported)
|
|
1162
1208
|
return objSupport;
|
|
1163
|
-
const indexSupport = checkSupport(expr.index, pos);
|
|
1209
|
+
const indexSupport = checkSupport(expr.index, pos, matchers);
|
|
1164
1210
|
if (!indexSupport.supported)
|
|
1165
1211
|
return indexSupport;
|
|
1166
1212
|
return { supported: true, level: "L2" };
|
|
1167
1213
|
}
|
|
1168
1214
|
case "binary": {
|
|
1169
|
-
const leftSupport = checkSupport(expr.left, pos);
|
|
1215
|
+
const leftSupport = checkSupport(expr.left, pos, matchers);
|
|
1170
1216
|
if (!leftSupport.supported)
|
|
1171
1217
|
return leftSupport;
|
|
1172
|
-
const rightSupport = checkSupport(expr.right, pos);
|
|
1218
|
+
const rightSupport = checkSupport(expr.right, pos, matchers);
|
|
1173
1219
|
if (!rightSupport.supported)
|
|
1174
1220
|
return rightSupport;
|
|
1175
1221
|
if (["===", "==", "!==", "!=", ">", "<", ">=", "<="].includes(expr.op)) {
|
|
@@ -1181,7 +1227,7 @@ function checkSupport(expr, pos) {
|
|
|
1181
1227
|
return { supported: false, reason: `Unknown operator: ${expr.op}` };
|
|
1182
1228
|
}
|
|
1183
1229
|
case "unary": {
|
|
1184
|
-
const argSupport = checkSupport(expr.argument, pos);
|
|
1230
|
+
const argSupport = checkSupport(expr.argument, pos, matchers);
|
|
1185
1231
|
if (!argSupport.supported)
|
|
1186
1232
|
return argSupport;
|
|
1187
1233
|
if (expr.op === "!") {
|
|
@@ -1193,25 +1239,25 @@ function checkSupport(expr, pos) {
|
|
|
1193
1239
|
return { supported: false, reason: `Unsupported unary operator: ${expr.op}` };
|
|
1194
1240
|
}
|
|
1195
1241
|
case "logical": {
|
|
1196
|
-
const leftSupport = checkSupport(expr.left, pos);
|
|
1242
|
+
const leftSupport = checkSupport(expr.left, pos, matchers);
|
|
1197
1243
|
if (!leftSupport.supported)
|
|
1198
1244
|
return leftSupport;
|
|
1199
1245
|
if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
|
|
1200
1246
|
return { supported: true, level: "L4" };
|
|
1201
1247
|
}
|
|
1202
|
-
const rightSupport = checkSupport(expr.right, pos);
|
|
1248
|
+
const rightSupport = checkSupport(expr.right, pos, matchers);
|
|
1203
1249
|
if (!rightSupport.supported)
|
|
1204
1250
|
return rightSupport;
|
|
1205
1251
|
return { supported: true, level: "L4" };
|
|
1206
1252
|
}
|
|
1207
1253
|
case "conditional": {
|
|
1208
|
-
const testSupport = checkSupport(expr.test, pos);
|
|
1254
|
+
const testSupport = checkSupport(expr.test, pos, matchers);
|
|
1209
1255
|
if (!testSupport.supported)
|
|
1210
1256
|
return testSupport;
|
|
1211
|
-
const consSupport = checkSupport(expr.consequent, pos);
|
|
1257
|
+
const consSupport = checkSupport(expr.consequent, pos, matchers);
|
|
1212
1258
|
if (!consSupport.supported)
|
|
1213
1259
|
return consSupport;
|
|
1214
|
-
const altSupport = checkSupport(expr.alternate, pos);
|
|
1260
|
+
const altSupport = checkSupport(expr.alternate, pos, matchers);
|
|
1215
1261
|
if (!altSupport.supported)
|
|
1216
1262
|
return altSupport;
|
|
1217
1263
|
return { supported: true, level: "L4" };
|
|
@@ -1219,7 +1265,7 @@ function checkSupport(expr, pos) {
|
|
|
1219
1265
|
case "template-literal": {
|
|
1220
1266
|
for (const part of expr.parts) {
|
|
1221
1267
|
if (part.type === "expression") {
|
|
1222
|
-
const partSupport = checkSupport(part.expr, pos);
|
|
1268
|
+
const partSupport = checkSupport(part.expr, pos, matchers);
|
|
1223
1269
|
if (!partSupport.supported)
|
|
1224
1270
|
return partSupport;
|
|
1225
1271
|
}
|
|
@@ -2228,6 +2274,12 @@ class BindingScope {
|
|
|
2228
2274
|
}
|
|
2229
2275
|
}
|
|
2230
2276
|
|
|
2277
|
+
// ../jsx/src/ir-to-client-js/safe-html.ts
|
|
2278
|
+
function safeHtml(expr) {
|
|
2279
|
+
return expr;
|
|
2280
|
+
}
|
|
2281
|
+
var EMPTY_MARKUP = safeHtml("''");
|
|
2282
|
+
|
|
2231
2283
|
// ../jsx/src/ir-to-client-js/html-template.ts
|
|
2232
2284
|
var VOID_ELEMENTS = new Set([
|
|
2233
2285
|
"area",
|
|
@@ -2514,6 +2566,7 @@ var CLIENT_EXPORTS = new Set([
|
|
|
2514
2566
|
"isSSRPortal",
|
|
2515
2567
|
"findSiblingSlot",
|
|
2516
2568
|
"cleanupPortalPlaceholder",
|
|
2569
|
+
"trackPosition",
|
|
2517
2570
|
"createSearchParams",
|
|
2518
2571
|
"queryHref",
|
|
2519
2572
|
"formatDate",
|
|
@@ -2574,7 +2627,8 @@ var BROWSER_ONLY_CLIENT_APIS = new Set([
|
|
|
2574
2627
|
"createPortal",
|
|
2575
2628
|
"isSSRPortal",
|
|
2576
2629
|
"findSiblingSlot",
|
|
2577
|
-
"cleanupPortalPlaceholder"
|
|
2630
|
+
"cleanupPortalPlaceholder",
|
|
2631
|
+
"trackPosition"
|
|
2578
2632
|
]);
|
|
2579
2633
|
var REACTIVE_PRIMITIVES = new Set([
|
|
2580
2634
|
"createSignal",
|
|
@@ -3173,30 +3227,6 @@ import ts16 from "typescript";
|
|
|
3173
3227
|
|
|
3174
3228
|
// ../jsx/src/relocate.ts
|
|
3175
3229
|
import ts18 from "typescript";
|
|
3176
|
-
|
|
3177
|
-
// ../jsx/src/lowering-registry.ts
|
|
3178
|
-
var plugins = [];
|
|
3179
|
-
function registerLoweringPlugin(plugin) {
|
|
3180
|
-
const existing = plugins.findIndex((p) => p.name === plugin.name);
|
|
3181
|
-
if (existing >= 0)
|
|
3182
|
-
plugins[existing] = plugin;
|
|
3183
|
-
else
|
|
3184
|
-
plugins.push(plugin);
|
|
3185
|
-
}
|
|
3186
|
-
function prepareLoweringMatchers(metadata) {
|
|
3187
|
-
const matchers = [];
|
|
3188
|
-
for (const plugin of plugins) {
|
|
3189
|
-
const matcher = plugin.prepare(metadata);
|
|
3190
|
-
if (matcher)
|
|
3191
|
-
matchers.push(matcher);
|
|
3192
|
-
}
|
|
3193
|
-
return matchers;
|
|
3194
|
-
}
|
|
3195
|
-
function isValidHelperId(helper) {
|
|
3196
|
-
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(helper);
|
|
3197
|
-
}
|
|
3198
|
-
|
|
3199
|
-
// ../jsx/src/relocate.ts
|
|
3200
3230
|
var REGISTRY_SAFE_BINDING_KINDS = new Set([
|
|
3201
3231
|
"global",
|
|
3202
3232
|
"module-import",
|
|
@@ -4664,6 +4694,17 @@ function emitParsedExpr(expr, emitter) {
|
|
|
4664
4694
|
case "literal":
|
|
4665
4695
|
return emitter.literal(expr.value, expr.literalType);
|
|
4666
4696
|
case "call": {
|
|
4697
|
+
if (emitter.lowering) {
|
|
4698
|
+
for (const matcher of emitter.lowering.matchers) {
|
|
4699
|
+
const node = matcher(expr.callee, expr.args);
|
|
4700
|
+
if (!node)
|
|
4701
|
+
continue;
|
|
4702
|
+
const rendered = emitter.lowering.render(node, emit);
|
|
4703
|
+
if (rendered !== null)
|
|
4704
|
+
return rendered;
|
|
4705
|
+
break;
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4667
4708
|
const cb = asCallbackMethodCall(expr);
|
|
4668
4709
|
if (cb)
|
|
4669
4710
|
return emitter.callbackMethod(cb.method, cb.object, cb.arrow, cb.args, emit);
|
|
@@ -5727,6 +5768,21 @@ class MojoTopLevelEmitter {
|
|
|
5727
5768
|
constructor(ctx) {
|
|
5728
5769
|
this.ctx = ctx;
|
|
5729
5770
|
}
|
|
5771
|
+
get lowering() {
|
|
5772
|
+
return {
|
|
5773
|
+
matchers: this.ctx._loweringMatchers,
|
|
5774
|
+
render: (node, emit) => {
|
|
5775
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
5776
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
5777
|
+
return `bf->query(${qArgs.join(", ")})`;
|
|
5778
|
+
}
|
|
5779
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
5780
|
+
return `bf->${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
5781
|
+
}
|
|
5782
|
+
return null;
|
|
5783
|
+
}
|
|
5784
|
+
};
|
|
5785
|
+
}
|
|
5730
5786
|
identifier(name) {
|
|
5731
5787
|
if (name === "undefined" || name === "null")
|
|
5732
5788
|
return "undef";
|
|
@@ -6296,7 +6352,9 @@ class MojoAdapter extends BaseAdapter {
|
|
|
6296
6352
|
return null;
|
|
6297
6353
|
return {
|
|
6298
6354
|
condition: exprToString(parsed.test),
|
|
6299
|
-
consequent: exprToString(parsed.consequent)
|
|
6355
|
+
consequent: exprToString(parsed.consequent),
|
|
6356
|
+
testParsed: parsed.test,
|
|
6357
|
+
consequentParsed: parsed.consequent
|
|
6300
6358
|
};
|
|
6301
6359
|
}
|
|
6302
6360
|
resolveLiteralConst(name) {
|
|
@@ -6623,7 +6681,7 @@ ${whenTrue}
|
|
|
6623
6681
|
const prevScope = this.scope;
|
|
6624
6682
|
this.scope = prevScope.enterLoopRow(loop);
|
|
6625
6683
|
const renderedChildren = this.renderChildren(loop.children);
|
|
6626
|
-
const children = loop.bodyIsItemConditional && loop.key ? `<%== bf->comment("loop-i:" . ${this.convertExpressionToPerl(loop.key)}) %>
|
|
6684
|
+
const children = loop.bodyIsItemConditional && loop.key ? `<%== bf->comment("loop-i:" . bf->escape_comment_key(${this.convertExpressionToPerl(loop.key)})) %>
|
|
6627
6685
|
${renderedChildren}` : renderedChildren;
|
|
6628
6686
|
const lines = [];
|
|
6629
6687
|
lines.push(`<%== bf->comment("loop:${loop.markerId}") %>`);
|
|
@@ -6824,8 +6882,8 @@ ${children}`;
|
|
|
6824
6882
|
{
|
|
6825
6883
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
6826
6884
|
if (m) {
|
|
6827
|
-
const cond = this.convertExpressionToPerl(m.
|
|
6828
|
-
const val = this.convertExpressionToPerl(m.
|
|
6885
|
+
const cond = this.convertExpressionToPerl("", m.testParsed);
|
|
6886
|
+
const val = this.convertExpressionToPerl("", m.consequentParsed);
|
|
6829
6887
|
return `<% if (${cond}) { %>${name}="<%= ${val} %>"<% } %>`;
|
|
6830
6888
|
}
|
|
6831
6889
|
}
|
|
@@ -6954,7 +7012,7 @@ ${children}`;
|
|
|
6954
7012
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
6955
7013
|
return false;
|
|
6956
7014
|
const parsed = parseExpression(expr.trim());
|
|
6957
|
-
const support = isSupported(parsed);
|
|
7015
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
6958
7016
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
6959
7017
|
return false;
|
|
6960
7018
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -6974,6 +7032,7 @@ ${reason}` : "";
|
|
|
6974
7032
|
get emitCtx() {
|
|
6975
7033
|
return {
|
|
6976
7034
|
_searchParamsLocals: this._searchParamsLocals,
|
|
7035
|
+
_loweringMatchers: this._loweringMatchers,
|
|
6977
7036
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
6978
7037
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
6979
7038
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -7004,20 +7063,8 @@ ${reason}` : "";
|
|
|
7004
7063
|
return "''";
|
|
7005
7064
|
parsed = parseExpression(trimmed);
|
|
7006
7065
|
}
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
7010
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
7011
|
-
const argsGo = queryHrefArgs(node, (n) => this.renderParsedExprToPerl(n));
|
|
7012
|
-
return `bf->query(${argsGo.join(", ")})`;
|
|
7013
|
-
}
|
|
7014
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
7015
|
-
const argsX = node.args.map((a) => this.renderParsedExprToPerl(a));
|
|
7016
|
-
return `bf->${node.helper}(${argsX.join(", ")})`;
|
|
7017
|
-
}
|
|
7018
|
-
}
|
|
7019
|
-
}
|
|
7020
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
7066
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
7067
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
7021
7068
|
if (!support.supported) {
|
|
7022
7069
|
this.errors.push({
|
|
7023
7070
|
code: "BF101",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/mojolicious",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.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.35.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.35.0",
|
|
74
|
+
"@barefootjs/vite": "0.35.0",
|
|
75
|
+
"@barefootjs/client": "0.35.0",
|
|
76
76
|
"vite": "^6.0.0"
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* rather than re-exposing the whole adapter.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import type { ParsedExpr, CompilerError, IRMetadata } from '@barefootjs/jsx'
|
|
21
|
+
import type { ParsedExpr, CompilerError, IRMetadata, LoweringMatcher } from '@barefootjs/jsx'
|
|
22
22
|
|
|
23
23
|
export interface MojoEmitContext {
|
|
24
24
|
/**
|
|
@@ -27,6 +27,17 @@ export interface MojoEmitContext {
|
|
|
27
27
|
*/
|
|
28
28
|
readonly _searchParamsLocals: Set<string>
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Registered lowering-plugin matchers (#2057), bound to this component's
|
|
32
|
+
* metadata at init. Read by `MojoTopLevelEmitter`'s `lowering` seam (#2843)
|
|
33
|
+
* so a registered call — the built-in `queryHref`, or any userland plugin —
|
|
34
|
+
* is recognised no matter where it sits in an expression tree (a ternary
|
|
35
|
+
* branch, a template-literal interpolation, …), not only when it's the call
|
|
36
|
+
* the adapter's own top-level conversion entry point
|
|
37
|
+
* (`convertExpressionToPerl`) is asked to lower directly.
|
|
38
|
+
*/
|
|
39
|
+
readonly _loweringMatchers: readonly LoweringMatcher[]
|
|
40
|
+
|
|
30
41
|
/**
|
|
31
42
|
* Inline a module-scope pure string-literal const by name as the resolved
|
|
32
43
|
* literal value, or null when the name is not such a const.
|
|
@@ -27,6 +27,10 @@ import { groupBinaryOperand,
|
|
|
27
27
|
matchSearchParamsMethodCall,
|
|
28
28
|
sortComparatorFromArrow,
|
|
29
29
|
asCallbackMethodCall,
|
|
30
|
+
type LoweringEmitter,
|
|
31
|
+
type LoweringNode,
|
|
32
|
+
queryHrefArgs,
|
|
33
|
+
isValidHelperId,
|
|
30
34
|
} from '@barefootjs/jsx'
|
|
31
35
|
|
|
32
36
|
import type { MojoEmitContext } from '../emit-context.ts'
|
|
@@ -323,6 +327,35 @@ export class MojoTopLevelEmitter implements ParsedExprEmitter {
|
|
|
323
327
|
this.ctx = ctx
|
|
324
328
|
}
|
|
325
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
|
|
332
|
+
* tries every matcher here BEFORE `call()` itself, so a registered call
|
|
333
|
+
* (the built-in `queryHref`, or any userland plugin) is recognised no
|
|
334
|
+
* matter where it sits in the tree. `render` is what used to live inline
|
|
335
|
+
* in `MojoAdapter.convertExpressionToPerl` before the object-literal
|
|
336
|
+
* support-gate refusal (`checkSupport`'s `call` arm, now itself
|
|
337
|
+
* registry-aware) made the pre-gate special case unnecessary.
|
|
338
|
+
*/
|
|
339
|
+
get lowering(): LoweringEmitter {
|
|
340
|
+
return {
|
|
341
|
+
matchers: this.ctx._loweringMatchers,
|
|
342
|
+
render: (node: LoweringNode, emit: (e: ParsedExpr) => string): string | null => {
|
|
343
|
+
// `query` guard-list — `queryHref`-shaped.
|
|
344
|
+
if (node.kind === 'guard-list' && node.helper === 'query') {
|
|
345
|
+
const qArgs = queryHrefArgs(node, emit)
|
|
346
|
+
return `bf->query(${qArgs.join(', ')})`
|
|
347
|
+
}
|
|
348
|
+
// Generic `helper-call` (#2069) — a userland `LoweringPlugin`'s
|
|
349
|
+
// single runtime-helper invocation; `bf-><helper>(args…)` mirrors
|
|
350
|
+
// the `query` helper's own naming convention.
|
|
351
|
+
if (node.kind === 'helper-call' && isValidHelperId(node.helper)) {
|
|
352
|
+
return `bf->${node.helper}(${node.args.map(emit).join(', ')})`
|
|
353
|
+
}
|
|
354
|
+
return null
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
326
359
|
identifier(name: string): string {
|
|
327
360
|
// `undefined` / `null` nested inside a larger expression tree
|
|
328
361
|
// (#1897, pagination's `props.isActive ? 'page' : undefined`) — the
|
|
@@ -56,8 +56,6 @@ import {
|
|
|
56
56
|
lookupStaticRecordLiteral,
|
|
57
57
|
searchParamsLocalNames,
|
|
58
58
|
prepareLoweringMatchers,
|
|
59
|
-
queryHrefArgs,
|
|
60
|
-
isValidHelperId,
|
|
61
59
|
sortComparatorFromArrow,
|
|
62
60
|
isLowerableLoopDestructure,
|
|
63
61
|
isDangerousInnerHtmlAttr,
|
|
@@ -404,7 +402,7 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
404
402
|
*/
|
|
405
403
|
parseUndefinedAlternateTernary(
|
|
406
404
|
expr: string,
|
|
407
|
-
): { condition: string; consequent: string } | null {
|
|
405
|
+
): { condition: string; consequent: string; testParsed: ParsedExpr; consequentParsed: ParsedExpr } | null {
|
|
408
406
|
const parsed = parseExpression(expr.trim())
|
|
409
407
|
if (parsed?.kind !== 'conditional') return null
|
|
410
408
|
const alt = parsed.alternate
|
|
@@ -412,13 +410,16 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
412
410
|
(alt.kind === 'identifier' && (alt.name === 'undefined' || alt.name === 'null')) ||
|
|
413
411
|
(alt.kind === 'literal' && (alt.value === null || alt.value === undefined))
|
|
414
412
|
if (!isUndef) return null
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
//
|
|
413
|
+
// `condition`/`consequent` are DEBUG text only (`exprToString` renders an
|
|
414
|
+
// unsupported nested shape like an object literal as non-reparseable
|
|
415
|
+
// `[UNSUPPORTED: …]` text) — callers that need to re-lower the
|
|
416
|
+
// sub-expression must use `testParsed`/`consequentParsed` (the actual
|
|
417
|
+
// parsed trees) as `preParsed`, not re-parse these strings.
|
|
419
418
|
return {
|
|
420
419
|
condition: exprToString(parsed.test),
|
|
421
420
|
consequent: exprToString(parsed.consequent),
|
|
421
|
+
testParsed: parsed.test,
|
|
422
|
+
consequentParsed: parsed.consequent,
|
|
422
423
|
}
|
|
423
424
|
}
|
|
424
425
|
|
|
@@ -994,9 +995,13 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
994
995
|
// conditional content so the client's `mapArrayAnchored` can hydrate
|
|
995
996
|
// every SSR-rendered item by its anchor. `bf->comment` prepends `bf-`,
|
|
996
997
|
// so `"loop-i:" . KEY` yields `<!--bf-loop-i:KEY-->`.
|
|
998
|
+
// `bf->escape_comment_key` (#2795 follow-up) both stringifies the key
|
|
999
|
+
// (JS `String()` semantics, matching the other adapters) and neutralizes
|
|
1000
|
+
// `-` so it can't spell `-->` and close the comment early — see its doc
|
|
1001
|
+
// in `BarefootJS.pm`.
|
|
997
1002
|
const children =
|
|
998
1003
|
loop.bodyIsItemConditional && loop.key
|
|
999
|
-
? `<%== bf->comment("loop-i:" . ${this.convertExpressionToPerl(loop.key)}) %>\n${renderedChildren}`
|
|
1004
|
+
? `<%== bf->comment("loop-i:" . bf->escape_comment_key(${this.convertExpressionToPerl(loop.key)})) %>\n${renderedChildren}`
|
|
1000
1005
|
: renderedChildren
|
|
1001
1006
|
|
|
1002
1007
|
const lines: string[] = []
|
|
@@ -1459,8 +1464,8 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
1459
1464
|
{
|
|
1460
1465
|
const m = this.parseUndefinedAlternateTernary(value.expr)
|
|
1461
1466
|
if (m) {
|
|
1462
|
-
const cond = this.convertExpressionToPerl(m.
|
|
1463
|
-
const val = this.convertExpressionToPerl(m.
|
|
1467
|
+
const cond = this.convertExpressionToPerl('', m.testParsed)
|
|
1468
|
+
const val = this.convertExpressionToPerl('', m.consequentParsed)
|
|
1464
1469
|
return `<% if (${cond}) { %>${name}="<%= ${val} %>"<% } %>`
|
|
1465
1470
|
}
|
|
1466
1471
|
}
|
|
@@ -1782,7 +1787,7 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
1782
1787
|
const hasTaggedTemplate = /[A-Za-z_$][\w$]*\s*`/.test(probe)
|
|
1783
1788
|
if (!startsAsObjectLiteral && !hasTaggedTemplate) return false
|
|
1784
1789
|
const parsed = parseExpression(expr.trim())
|
|
1785
|
-
const support = isSupported(parsed)
|
|
1790
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers })
|
|
1786
1791
|
if (parsed.kind !== 'unsupported' && support.supported) return false
|
|
1787
1792
|
// Surface the `isSupported` reason so the diagnostic is as
|
|
1788
1793
|
// actionable as the Go adapter's BF101 — keeps cross-adapter
|
|
@@ -1812,6 +1817,7 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
1812
1817
|
private get emitCtx(): MojoEmitContext {
|
|
1813
1818
|
return {
|
|
1814
1819
|
_searchParamsLocals: this._searchParamsLocals,
|
|
1820
|
+
_loweringMatchers: this._loweringMatchers,
|
|
1815
1821
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
1816
1822
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
1817
1823
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -1868,42 +1874,16 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
1868
1874
|
parsed = parseExpression(trimmed)
|
|
1869
1875
|
}
|
|
1870
1876
|
|
|
1871
|
-
// Registered call lowerings (#2057) — including the built-in `queryHref`
|
|
1872
|
-
// plugin (#2042), which lowers `queryHref(base, { … })` to a neutral
|
|
1873
|
-
// `guard-list` on the `query` helper → `bf->query(base, <triples>)`.
|
|
1874
|
-
// Recognised before the support gate because the object-literal arg is
|
|
1875
|
-
// otherwise `unsupported` (BF101). The `bf->query` helper includes a pair iff
|
|
1876
|
-
// its guard is truthy AND its value is a non-empty string (the client's
|
|
1877
|
-
// `if (value)`): a plain `key: v` passes guard `1`, a conditional
|
|
1878
|
-
// `key: cond ? v : undefined` passes the lowered cond. Only the `query`
|
|
1879
|
-
// helper renders to `bf->query`; another guard-list helper must not be
|
|
1880
|
-
// silently mis-rendered as a query.
|
|
1881
|
-
if (parsed.kind === 'call') {
|
|
1882
|
-
for (const matcher of this._loweringMatchers) {
|
|
1883
|
-
const node = matcher(parsed.callee, parsed.args)
|
|
1884
|
-
if (node?.kind === 'guard-list' && node.helper === 'query') {
|
|
1885
|
-
const argsGo = queryHrefArgs(node, n => this.renderParsedExprToPerl(n))
|
|
1886
|
-
return `bf->query(${argsGo.join(', ')})`
|
|
1887
|
-
}
|
|
1888
|
-
// Generic `helper-call` (#2069) — the neutral vocabulary's escape
|
|
1889
|
-
// hatch for a userland `LoweringPlugin` that lowers to a single
|
|
1890
|
-
// runtime-helper invocation. `bf-><helper>(args…)` mirrors the
|
|
1891
|
-
// `query` helper's own naming convention exactly: the framework
|
|
1892
|
-
// renders the call, the plugin author registers `<helper>` as a
|
|
1893
|
-
// method on their own Mojolicious `bf` helper object — same
|
|
1894
|
-
// contract as `bf->query` itself, just not built in.
|
|
1895
|
-
if (node?.kind === 'helper-call' && isValidHelperId(node.helper)) {
|
|
1896
|
-
const argsX = node.args.map(a => this.renderParsedExprToPerl(a))
|
|
1897
|
-
return `bf->${node.helper}(${argsX.join(', ')})`
|
|
1898
|
-
}
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
1877
|
// `pos` distinguishes a derived-seed RHS (an assignment, checked via
|
|
1903
1878
|
// `isSupportedValue`) from every other, genuinely rendered call site —
|
|
1904
1879
|
// the rendered gate would otherwise re-refuse a tree the seed plan
|
|
1905
1880
|
// already classified `derived` at value position (#2696 review).
|
|
1906
|
-
|
|
1881
|
+
// Registered call lowerings (#2057) — including the built-in `queryHref`
|
|
1882
|
+
// plugin — are consulted by this gate no matter where the call sits in
|
|
1883
|
+
// the tree (`MojoTopLevelEmitter`'s `lowering` seam does the actual
|
|
1884
|
+
// rendering below, via `emitParsedExpr`'s shared `call` case).
|
|
1885
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers }
|
|
1886
|
+
const support = pos === 'value' ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts)
|
|
1907
1887
|
if (!support.supported) {
|
|
1908
1888
|
this.errors.push({
|
|
1909
1889
|
code: 'BF101',
|
package/src/conformance-pins.ts
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
import type { ConformancePins } from '@barefootjs/jsx'
|
|
11
11
|
|
|
12
12
|
export const conformancePins: ConformancePins = {
|
|
13
|
+
// #2843: graduated — a registered lowering call inside a ternary
|
|
14
|
+
// attribute branch (or any nested value position) is now recognised via
|
|
15
|
+
// `MojoTopLevelEmitter`'s `lowering` seam + the registry-aware support
|
|
16
|
+
// gate, matching the direct-call attribute path exactly.
|
|
13
17
|
'filter-typeof-predicate': [{ code: 'BF021', severity: 'error' }],
|
|
14
18
|
'map-array-builder-body': [{ code: 'BF021', severity: 'error' }],
|
|
15
19
|
'map-array-builder-escaping': [{ code: 'BF021', severity: 'error' }],
|
|
@@ -15,19 +15,4 @@ import type { RenderDivergences } from '@barefootjs/jsx'
|
|
|
15
15
|
// at value position and the runtime evaluator's `object-literal` case
|
|
16
16
|
// now merges it, so the seed classifies `derived` and SSRs identically
|
|
17
17
|
// to Hono.
|
|
18
|
-
|
|
19
|
-
// `children` destructure (`const { children: kids } = props`) interpolates
|
|
20
|
-
// the LOCAL alias into the `.html.ep`, and the stash only carries the
|
|
21
|
-
// caller-facing `children`, so Perl dies inside `Mojo::Template::process`
|
|
22
|
-
// at render time rather than at build. Seven adapters resolve the alias;
|
|
23
|
-
// only Mojo does not. Same family as `aliased-destructured-prop`'s
|
|
24
|
-
// `{ n: count }` shape, one level in — the reserved children slot.
|
|
25
|
-
// Delete this entry when #2788 is fixed: `children-passthrough-renamed`
|
|
26
|
-
// already asserts the correct (Hono-generated) output, so it becomes the
|
|
27
|
-
// regression test the moment the skip comes off.
|
|
28
|
-
export const renderDivergences: RenderDivergences = {
|
|
29
|
-
'children-passthrough-renamed':
|
|
30
|
-
'A renamed `children` destructure emits the local alias as a template variable; the stash defines only `children`, so the Perl render dies (#2788).',
|
|
31
|
-
'aliased-loop-source':
|
|
32
|
-
'A `.map()` loop whose source is a local const alias of a signal getter (`const items__alias = items`) dies inside `Mojo::Template::process` on real Mojolicious — the seeded loop data is keyed by the signal\'s real name (`items`), and the alias hop is never resolved when deciding what to seed under `items__alias`. This is the SSR-side twin of #2778 (fixed for the CSR client-JS template in the same PR that added this fixture) — that fix only touches client-JS emission, not SSR data-seeding. Tracked at https://github.com/piconic-ai/barefootjs/issues/2813; graduate by resolving the alias hop at SSR-seeding time using the same `resolveAliasOrigin`/`resolveGetterAliases` mechanism #2778 introduced, rather than a third alias-hop walker.',
|
|
33
|
-
}
|
|
18
|
+
export const renderDivergences: RenderDivergences = {}
|
package/src/test-render.ts
CHANGED
|
@@ -548,6 +548,21 @@ function buildChildDefaultsPerl(ir: ComponentIR): string {
|
|
|
548
548
|
`${memo.name} => ${value !== undefined && value !== null ? toPerlLiteral(value) : 'undef'}`,
|
|
549
549
|
)
|
|
550
550
|
}
|
|
551
|
+
// #2788: `extractSsrDefaults` can seed an entry under a name that is
|
|
552
|
+
// none of `propsParams` / `signals` / `memos` above — a bare-props-form
|
|
553
|
+
// component's body-level RENAMED destructure (`const { children: kids }
|
|
554
|
+
// = props`) seeds `kids` alongside the caller-facing `children`
|
|
555
|
+
// (`ssr-defaults.ts`). Real production hands `$entry->{ssrDefaults}`
|
|
556
|
+
// straight through to `_derive_stash_from_defaults`, which iterates
|
|
557
|
+
// every key it contains — so any leftover entry here must be added too,
|
|
558
|
+
// or this harness's hand-built stash literal would silently omit a key
|
|
559
|
+
// production's manifest-driven path already provides, mismeasuring
|
|
560
|
+
// this conformance case's real behavior.
|
|
561
|
+
for (const name of Object.keys(ssrDefaults)) {
|
|
562
|
+
if (declared.has(name)) continue
|
|
563
|
+
declared.add(name)
|
|
564
|
+
entries.push(`${name} => ${ssrDefaultEntryToPerl(ssrDefaults[name])}`)
|
|
565
|
+
}
|
|
551
566
|
return `{${entries.join(', ')}}`
|
|
552
567
|
}
|
|
553
568
|
|
|
@@ -758,6 +773,29 @@ function buildPerlProps(
|
|
|
758
773
|
}
|
|
759
774
|
}
|
|
760
775
|
|
|
776
|
+
// #2813: `extractSsrDefaults` can seed an entry under a name that is
|
|
777
|
+
// none of `propsParams` / the inherited-attribute scan / `signals` /
|
|
778
|
+
// `memos` above — a bare local-const alias of a signal/memo getter
|
|
779
|
+
// (`const items__alias = items`, `ssr-defaults.ts`) seeds `items__alias`
|
|
780
|
+
// alongside `items`. Production hands the whole manifest-derived stash
|
|
781
|
+
// straight through (`deriveStashFromDefaults` IS the production seeding
|
|
782
|
+
// mechanism here, not a harness stand-in), so any leftover
|
|
783
|
+
// `derivedProps` key must be pushed too, or this harness would silently
|
|
784
|
+
// omit what production actually provides, mismeasuring this
|
|
785
|
+
// conformance case — the same gap `buildChildDefaultsPerl` (above) was
|
|
786
|
+
// already fixed for child components.
|
|
787
|
+
const seededNames = new Set<string>([
|
|
788
|
+
...ir.metadata.propsParams.map(p => p.name),
|
|
789
|
+
...(ir.metadata.propsObjectName ? [...collectPropsObjectAccesses(ir, ir.metadata.propsObjectName)] : []),
|
|
790
|
+
...(restPropsName ? [restPropsName] : []),
|
|
791
|
+
...ir.metadata.signals.filter(s => !s.envReader).map(s => s.getter),
|
|
792
|
+
...ir.metadata.memos.map(m => m.name),
|
|
793
|
+
])
|
|
794
|
+
for (const [name, value] of Object.entries(derivedProps)) {
|
|
795
|
+
if (seededNames.has(name)) continue
|
|
796
|
+
entries.push(`${name} => ${toPerlLiteral(value)}`)
|
|
797
|
+
}
|
|
798
|
+
|
|
761
799
|
// (#1922) Request-scoped `searchParams()`: bind `$searchParams` to an
|
|
762
800
|
// empty-query reader via the lazy-loading factory (so the render script
|
|
763
801
|
// needn't `use BarefootJS::SearchParams`). The conformance harness issues no
|