@barefootjs/erb 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/erb-adapter.d.ts +3 -0
- package/dist/adapter/erb-adapter.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/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +29 -25
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/vite.js +119 -72
- package/lib/barefoot_js.rb +16 -0
- package/package.json +5 -5
- package/src/adapter/emit-context.ts +12 -1
- package/src/adapter/erb-adapter.ts +22 -45
- package/src/adapter/expr/emitters.ts +33 -0
- package/src/conformance-pins.ts +4 -0
- package/src/render-divergences.ts +1 -4
- package/src/test-render.ts +14 -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 ErbEmitContext {
|
|
22
22
|
/**
|
|
23
23
|
* 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 `ErbTopLevelEmitter`'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
|
+
* (`convertExpressionToRuby`) 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,cAAc;IAC7B;;;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;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAEtC,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,gBAAgB;IAC/B,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,cAAc;IAC7B;;;;;;;;;;;;OAYG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;CAClG"}
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
import type { ComponentIR, IRNode, IRElement, IRText, IRExpression, IRConditional, IRLoop, IRComponent, IRFragment, IRSlot, IRIfStatement, IRProvider, IRAsync, TemplatePrimitiveRegistry } from '@barefootjs/jsx';
|
|
38
38
|
import { BaseAdapter, type AdapterOutput, type AdapterGenerateOptions, type IRNodeEmitter, type EmitIRNode } from '@barefootjs/jsx';
|
|
39
|
+
import type { ParsedExpr } from '@barefootjs/jsx';
|
|
39
40
|
import type { ErbRenderCtx } from './lib/types.ts';
|
|
40
41
|
export type { ErbAdapterOptions } from './lib/types.ts';
|
|
41
42
|
import type { ErbAdapterOptions } from './lib/types.ts';
|
|
@@ -189,6 +190,8 @@ export declare class ErbAdapter extends BaseAdapter implements IRNodeEmitter<Erb
|
|
|
189
190
|
parseUndefinedAlternateTernary(expr: string): {
|
|
190
191
|
condition: string;
|
|
191
192
|
consequent: string;
|
|
193
|
+
testParsed: ParsedExpr;
|
|
194
|
+
consequentParsed: ParsedExpr;
|
|
192
195
|
} | null;
|
|
193
196
|
/**
|
|
194
197
|
* Inline a const (any scope) whose initializer is a pure numeric or
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"erb-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/erb-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,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,EAC1B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EAClB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"erb-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/erb-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* `nil`/`false`, so `0`, `''`, and `NaN` are Ruby-truthy but JS-falsy. Every
|
|
32
32
|
* JS truthiness test in this file goes through `bf.truthy?` for that reason.
|
|
33
33
|
*/
|
|
34
|
-
import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
|
|
34
|
+
import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart, type LoweringEmitter } from '@barefootjs/jsx';
|
|
35
35
|
import type { ErbEmitContext } from '../emit-context.ts';
|
|
36
36
|
export declare class ErbFilterEmitter implements ParsedExprEmitter {
|
|
37
37
|
private readonly param;
|
|
@@ -76,6 +76,16 @@ export declare class ErbFilterEmitter implements ParsedExprEmitter {
|
|
|
76
76
|
export declare class ErbTopLevelEmitter implements ParsedExprEmitter {
|
|
77
77
|
private readonly ctx;
|
|
78
78
|
constructor(ctx: ErbEmitContext);
|
|
79
|
+
/**
|
|
80
|
+
* Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
|
|
81
|
+
* tries every matcher here BEFORE `call()` itself, so a registered call
|
|
82
|
+
* (the built-in `queryHref`, or any userland plugin) is recognised no
|
|
83
|
+
* matter where it sits in the tree. `render` is what used to live inline
|
|
84
|
+
* in `ErbAdapter.convertExpressionToRuby` before the object-literal
|
|
85
|
+
* support-gate refusal (`checkSupport`'s `call` arm, now itself
|
|
86
|
+
* registry-aware) made the pre-gate special case unnecessary.
|
|
87
|
+
*/
|
|
88
|
+
get lowering(): LoweringEmitter;
|
|
79
89
|
identifier(name: string): string;
|
|
80
90
|
literal(value: string | number | boolean | null, literalType: LiteralType): string;
|
|
81
91
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EACL,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
|
@@ -187307,8 +187307,6 @@ import {
|
|
|
187307
187307
|
lookupStaticRecordLiteral,
|
|
187308
187308
|
searchParamsLocalNames,
|
|
187309
187309
|
prepareLoweringMatchers,
|
|
187310
|
-
queryHrefArgs,
|
|
187311
|
-
isValidHelperId,
|
|
187312
187310
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
187313
187311
|
isDangerousInnerHtmlAttr,
|
|
187314
187312
|
resolveDangerousInnerHtml,
|
|
@@ -187711,7 +187709,9 @@ import {
|
|
|
187711
187709
|
groupObjectLiteralSegments,
|
|
187712
187710
|
identifierPath,
|
|
187713
187711
|
matchSearchParamsMethodCall,
|
|
187714
|
-
sortComparatorFromArrow
|
|
187712
|
+
sortComparatorFromArrow,
|
|
187713
|
+
queryHrefArgs,
|
|
187714
|
+
isValidHelperId
|
|
187715
187715
|
} from "@barefootjs/jsx";
|
|
187716
187716
|
|
|
187717
187717
|
// src/adapter/expr/operand.ts
|
|
@@ -187871,6 +187871,21 @@ class ErbTopLevelEmitter {
|
|
|
187871
187871
|
constructor(ctx) {
|
|
187872
187872
|
this.ctx = ctx;
|
|
187873
187873
|
}
|
|
187874
|
+
get lowering() {
|
|
187875
|
+
return {
|
|
187876
|
+
matchers: this.ctx._loweringMatchers,
|
|
187877
|
+
render: (node, emit) => {
|
|
187878
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
187879
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
187880
|
+
return `bf.query(${qArgs.join(", ")})`;
|
|
187881
|
+
}
|
|
187882
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
187883
|
+
return `bf.${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
187884
|
+
}
|
|
187885
|
+
return null;
|
|
187886
|
+
}
|
|
187887
|
+
};
|
|
187888
|
+
}
|
|
187874
187889
|
identifier(name) {
|
|
187875
187890
|
if (name === "undefined" || name === "null")
|
|
187876
187891
|
return "nil";
|
|
@@ -188430,7 +188445,9 @@ class ErbAdapter extends BaseAdapter {
|
|
|
188430
188445
|
return null;
|
|
188431
188446
|
return {
|
|
188432
188447
|
condition: exprToString(parsed.test),
|
|
188433
|
-
consequent: exprToString(parsed.consequent)
|
|
188448
|
+
consequent: exprToString(parsed.consequent),
|
|
188449
|
+
testParsed: parsed.test,
|
|
188450
|
+
consequentParsed: parsed.consequent
|
|
188434
188451
|
};
|
|
188435
188452
|
}
|
|
188436
188453
|
resolveLiteralConst(name) {
|
|
@@ -188771,7 +188788,7 @@ ${whenTrue}
|
|
|
188771
188788
|
const prevScope = this.scope;
|
|
188772
188789
|
this.scope = prevScope.enterLoopRow(loop);
|
|
188773
188790
|
const renderedChildren = this.renderChildren(loop.children);
|
|
188774
|
-
const children = loop.bodyIsItemConditional && loop.key ? `<%= bf.comment("loop-i:" + bf.
|
|
188791
|
+
const children = loop.bodyIsItemConditional && loop.key ? `<%= bf.comment("loop-i:" + bf.escape_comment_key(${this.convertExpressionToRuby(loop.key)})) %>
|
|
188775
188792
|
${renderedChildren}` : renderedChildren;
|
|
188776
188793
|
const lines = [];
|
|
188777
188794
|
lines.push(`<%= bf.comment("loop:${loop.markerId}") %>`);
|
|
@@ -188975,8 +188992,8 @@ ${children}`;
|
|
|
188975
188992
|
{
|
|
188976
188993
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
188977
188994
|
if (m) {
|
|
188978
|
-
const cond = this.convertExpressionToRuby(m.
|
|
188979
|
-
const val = this.convertExpressionToRuby(m.
|
|
188995
|
+
const cond = this.convertExpressionToRuby("", m.testParsed);
|
|
188996
|
+
const val = this.convertExpressionToRuby("", m.consequentParsed);
|
|
188980
188997
|
return `<% if bf.truthy?(${cond}) %>${name}="<%= bf.h(${val}) %>"<% end %>`;
|
|
188981
188998
|
}
|
|
188982
188999
|
}
|
|
@@ -189106,7 +189123,7 @@ ${children}`;
|
|
|
189106
189123
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
189107
189124
|
return false;
|
|
189108
189125
|
const parsed = parseExpression2(expr.trim());
|
|
189109
|
-
const support = isSupported(parsed);
|
|
189126
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
189110
189127
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
189111
189128
|
return false;
|
|
189112
189129
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -189126,6 +189143,7 @@ ${reason}` : "";
|
|
|
189126
189143
|
get emitCtx() {
|
|
189127
189144
|
return {
|
|
189128
189145
|
_searchParamsLocals: this._searchParamsLocals,
|
|
189146
|
+
_loweringMatchers: this._loweringMatchers,
|
|
189129
189147
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
189130
189148
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
189131
189149
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -189157,20 +189175,8 @@ ${reason}` : "";
|
|
|
189157
189175
|
return "''";
|
|
189158
189176
|
parsed = parseExpression2(trimmed);
|
|
189159
189177
|
}
|
|
189160
|
-
|
|
189161
|
-
|
|
189162
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
189163
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
189164
|
-
const argsRuby = queryHrefArgs(node, (n) => this.renderParsedExprToRuby(n));
|
|
189165
|
-
return `bf.query(${argsRuby.join(", ")})`;
|
|
189166
|
-
}
|
|
189167
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
189168
|
-
const argsX = node.args.map((a) => this.renderParsedExprToRuby(a));
|
|
189169
|
-
return `bf.${node.helper}(${argsX.join(", ")})`;
|
|
189170
|
-
}
|
|
189171
|
-
}
|
|
189172
|
-
}
|
|
189173
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
189178
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
189179
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
189174
189180
|
if (!support.supported) {
|
|
189175
189181
|
this.errors.push({
|
|
189176
189182
|
code: "BF101",
|
|
@@ -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
|
@@ -187307,8 +187307,6 @@ import {
|
|
|
187307
187307
|
lookupStaticRecordLiteral,
|
|
187308
187308
|
searchParamsLocalNames,
|
|
187309
187309
|
prepareLoweringMatchers,
|
|
187310
|
-
queryHrefArgs,
|
|
187311
|
-
isValidHelperId,
|
|
187312
187310
|
sortComparatorFromArrow as sortComparatorFromArrow2,
|
|
187313
187311
|
isDangerousInnerHtmlAttr,
|
|
187314
187312
|
resolveDangerousInnerHtml,
|
|
@@ -187711,7 +187709,9 @@ import {
|
|
|
187711
187709
|
groupObjectLiteralSegments,
|
|
187712
187710
|
identifierPath,
|
|
187713
187711
|
matchSearchParamsMethodCall,
|
|
187714
|
-
sortComparatorFromArrow
|
|
187712
|
+
sortComparatorFromArrow,
|
|
187713
|
+
queryHrefArgs,
|
|
187714
|
+
isValidHelperId
|
|
187715
187715
|
} from "@barefootjs/jsx";
|
|
187716
187716
|
|
|
187717
187717
|
// src/adapter/expr/operand.ts
|
|
@@ -187871,6 +187871,21 @@ class ErbTopLevelEmitter {
|
|
|
187871
187871
|
constructor(ctx) {
|
|
187872
187872
|
this.ctx = ctx;
|
|
187873
187873
|
}
|
|
187874
|
+
get lowering() {
|
|
187875
|
+
return {
|
|
187876
|
+
matchers: this.ctx._loweringMatchers,
|
|
187877
|
+
render: (node, emit) => {
|
|
187878
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
187879
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
187880
|
+
return `bf.query(${qArgs.join(", ")})`;
|
|
187881
|
+
}
|
|
187882
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
187883
|
+
return `bf.${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
187884
|
+
}
|
|
187885
|
+
return null;
|
|
187886
|
+
}
|
|
187887
|
+
};
|
|
187888
|
+
}
|
|
187874
187889
|
identifier(name) {
|
|
187875
187890
|
if (name === "undefined" || name === "null")
|
|
187876
187891
|
return "nil";
|
|
@@ -188430,7 +188445,9 @@ class ErbAdapter extends BaseAdapter {
|
|
|
188430
188445
|
return null;
|
|
188431
188446
|
return {
|
|
188432
188447
|
condition: exprToString(parsed.test),
|
|
188433
|
-
consequent: exprToString(parsed.consequent)
|
|
188448
|
+
consequent: exprToString(parsed.consequent),
|
|
188449
|
+
testParsed: parsed.test,
|
|
188450
|
+
consequentParsed: parsed.consequent
|
|
188434
188451
|
};
|
|
188435
188452
|
}
|
|
188436
188453
|
resolveLiteralConst(name) {
|
|
@@ -188771,7 +188788,7 @@ ${whenTrue}
|
|
|
188771
188788
|
const prevScope = this.scope;
|
|
188772
188789
|
this.scope = prevScope.enterLoopRow(loop);
|
|
188773
188790
|
const renderedChildren = this.renderChildren(loop.children);
|
|
188774
|
-
const children = loop.bodyIsItemConditional && loop.key ? `<%= bf.comment("loop-i:" + bf.
|
|
188791
|
+
const children = loop.bodyIsItemConditional && loop.key ? `<%= bf.comment("loop-i:" + bf.escape_comment_key(${this.convertExpressionToRuby(loop.key)})) %>
|
|
188775
188792
|
${renderedChildren}` : renderedChildren;
|
|
188776
188793
|
const lines = [];
|
|
188777
188794
|
lines.push(`<%= bf.comment("loop:${loop.markerId}") %>`);
|
|
@@ -188975,8 +188992,8 @@ ${children}`;
|
|
|
188975
188992
|
{
|
|
188976
188993
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
188977
188994
|
if (m) {
|
|
188978
|
-
const cond = this.convertExpressionToRuby(m.
|
|
188979
|
-
const val = this.convertExpressionToRuby(m.
|
|
188995
|
+
const cond = this.convertExpressionToRuby("", m.testParsed);
|
|
188996
|
+
const val = this.convertExpressionToRuby("", m.consequentParsed);
|
|
188980
188997
|
return `<% if bf.truthy?(${cond}) %>${name}="<%= bf.h(${val}) %>"<% end %>`;
|
|
188981
188998
|
}
|
|
188982
188999
|
}
|
|
@@ -189106,7 +189123,7 @@ ${children}`;
|
|
|
189106
189123
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
189107
189124
|
return false;
|
|
189108
189125
|
const parsed = parseExpression2(expr.trim());
|
|
189109
|
-
const support = isSupported(parsed);
|
|
189126
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
189110
189127
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
189111
189128
|
return false;
|
|
189112
189129
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -189126,6 +189143,7 @@ ${reason}` : "";
|
|
|
189126
189143
|
get emitCtx() {
|
|
189127
189144
|
return {
|
|
189128
189145
|
_searchParamsLocals: this._searchParamsLocals,
|
|
189146
|
+
_loweringMatchers: this._loweringMatchers,
|
|
189129
189147
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
189130
189148
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
189131
189149
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -189157,20 +189175,8 @@ ${reason}` : "";
|
|
|
189157
189175
|
return "''";
|
|
189158
189176
|
parsed = parseExpression2(trimmed);
|
|
189159
189177
|
}
|
|
189160
|
-
|
|
189161
|
-
|
|
189162
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
189163
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
189164
|
-
const argsRuby = queryHrefArgs(node, (n) => this.renderParsedExprToRuby(n));
|
|
189165
|
-
return `bf.query(${argsRuby.join(", ")})`;
|
|
189166
|
-
}
|
|
189167
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
189168
|
-
const argsX = node.args.map((a) => this.renderParsedExprToRuby(a));
|
|
189169
|
-
return `bf.${node.helper}(${argsX.join(", ")})`;
|
|
189170
|
-
}
|
|
189171
|
-
}
|
|
189172
|
-
}
|
|
189173
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
189178
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
189179
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
189174
189180
|
if (!support.supported) {
|
|
189175
189181
|
this.errors.push({
|
|
189176
189182
|
code: "BF101",
|
|
@@ -189256,9 +189262,7 @@ var conformancePins = {
|
|
|
189256
189262
|
"namespace-import-primitive": [{ code: "BF013", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2771" }]
|
|
189257
189263
|
};
|
|
189258
189264
|
// src/render-divergences.ts
|
|
189259
|
-
var renderDivergences = {
|
|
189260
|
-
"aliased-loop-source": "A `.map()` loop whose source is a local const alias of a signal getter (`const items__alias = items`) throws `undefined method 'length' for nil (NoMethodError)` on real Ruby ERB — 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."
|
|
189261
|
-
};
|
|
189265
|
+
var renderDivergences = {};
|
|
189262
189266
|
export {
|
|
189263
189267
|
renderDivergences,
|
|
189264
189268
|
erbAdapter,
|
|
@@ -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;AAQxD,eAAO,MAAM,iBAAiB,EAAE,
|
|
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",
|
|
@@ -4660,6 +4690,17 @@ function emitParsedExpr(expr, emitter) {
|
|
|
4660
4690
|
case "literal":
|
|
4661
4691
|
return emitter.literal(expr.value, expr.literalType);
|
|
4662
4692
|
case "call": {
|
|
4693
|
+
if (emitter.lowering) {
|
|
4694
|
+
for (const matcher of emitter.lowering.matchers) {
|
|
4695
|
+
const node = matcher(expr.callee, expr.args);
|
|
4696
|
+
if (!node)
|
|
4697
|
+
continue;
|
|
4698
|
+
const rendered = emitter.lowering.render(node, emit);
|
|
4699
|
+
if (rendered !== null)
|
|
4700
|
+
return rendered;
|
|
4701
|
+
break;
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4663
4704
|
const cb = asCallbackMethodCall(expr);
|
|
4664
4705
|
if (cb)
|
|
4665
4706
|
return emitter.callbackMethod(cb.method, cb.object, cb.arrow, cb.args, emit);
|
|
@@ -5717,6 +5758,21 @@ class ErbTopLevelEmitter {
|
|
|
5717
5758
|
constructor(ctx) {
|
|
5718
5759
|
this.ctx = ctx;
|
|
5719
5760
|
}
|
|
5761
|
+
get lowering() {
|
|
5762
|
+
return {
|
|
5763
|
+
matchers: this.ctx._loweringMatchers,
|
|
5764
|
+
render: (node, emit) => {
|
|
5765
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
5766
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
5767
|
+
return `bf.query(${qArgs.join(", ")})`;
|
|
5768
|
+
}
|
|
5769
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
5770
|
+
return `bf.${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
5771
|
+
}
|
|
5772
|
+
return null;
|
|
5773
|
+
}
|
|
5774
|
+
};
|
|
5775
|
+
}
|
|
5720
5776
|
identifier(name) {
|
|
5721
5777
|
if (name === "undefined" || name === "null")
|
|
5722
5778
|
return "nil";
|
|
@@ -6271,7 +6327,9 @@ class ErbAdapter extends BaseAdapter {
|
|
|
6271
6327
|
return null;
|
|
6272
6328
|
return {
|
|
6273
6329
|
condition: exprToString(parsed.test),
|
|
6274
|
-
consequent: exprToString(parsed.consequent)
|
|
6330
|
+
consequent: exprToString(parsed.consequent),
|
|
6331
|
+
testParsed: parsed.test,
|
|
6332
|
+
consequentParsed: parsed.consequent
|
|
6275
6333
|
};
|
|
6276
6334
|
}
|
|
6277
6335
|
resolveLiteralConst(name) {
|
|
@@ -6612,7 +6670,7 @@ ${whenTrue}
|
|
|
6612
6670
|
const prevScope = this.scope;
|
|
6613
6671
|
this.scope = prevScope.enterLoopRow(loop);
|
|
6614
6672
|
const renderedChildren = this.renderChildren(loop.children);
|
|
6615
|
-
const children = loop.bodyIsItemConditional && loop.key ? `<%= bf.comment("loop-i:" + bf.
|
|
6673
|
+
const children = loop.bodyIsItemConditional && loop.key ? `<%= bf.comment("loop-i:" + bf.escape_comment_key(${this.convertExpressionToRuby(loop.key)})) %>
|
|
6616
6674
|
${renderedChildren}` : renderedChildren;
|
|
6617
6675
|
const lines = [];
|
|
6618
6676
|
lines.push(`<%= bf.comment("loop:${loop.markerId}") %>`);
|
|
@@ -6816,8 +6874,8 @@ ${children}`;
|
|
|
6816
6874
|
{
|
|
6817
6875
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
6818
6876
|
if (m) {
|
|
6819
|
-
const cond = this.convertExpressionToRuby(m.
|
|
6820
|
-
const val = this.convertExpressionToRuby(m.
|
|
6877
|
+
const cond = this.convertExpressionToRuby("", m.testParsed);
|
|
6878
|
+
const val = this.convertExpressionToRuby("", m.consequentParsed);
|
|
6821
6879
|
return `<% if bf.truthy?(${cond}) %>${name}="<%= bf.h(${val}) %>"<% end %>`;
|
|
6822
6880
|
}
|
|
6823
6881
|
}
|
|
@@ -6947,7 +7005,7 @@ ${children}`;
|
|
|
6947
7005
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
6948
7006
|
return false;
|
|
6949
7007
|
const parsed = parseExpression(expr.trim());
|
|
6950
|
-
const support = isSupported(parsed);
|
|
7008
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
6951
7009
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
6952
7010
|
return false;
|
|
6953
7011
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -6967,6 +7025,7 @@ ${reason}` : "";
|
|
|
6967
7025
|
get emitCtx() {
|
|
6968
7026
|
return {
|
|
6969
7027
|
_searchParamsLocals: this._searchParamsLocals,
|
|
7028
|
+
_loweringMatchers: this._loweringMatchers,
|
|
6970
7029
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
6971
7030
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
6972
7031
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -6998,20 +7057,8 @@ ${reason}` : "";
|
|
|
6998
7057
|
return "''";
|
|
6999
7058
|
parsed = parseExpression(trimmed);
|
|
7000
7059
|
}
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
7004
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
7005
|
-
const argsRuby = queryHrefArgs(node, (n) => this.renderParsedExprToRuby(n));
|
|
7006
|
-
return `bf.query(${argsRuby.join(", ")})`;
|
|
7007
|
-
}
|
|
7008
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
7009
|
-
const argsX = node.args.map((a) => this.renderParsedExprToRuby(a));
|
|
7010
|
-
return `bf.${node.helper}(${argsX.join(", ")})`;
|
|
7011
|
-
}
|
|
7012
|
-
}
|
|
7013
|
-
}
|
|
7014
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
7060
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
7061
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
7015
7062
|
if (!support.supported) {
|
|
7016
7063
|
this.errors.push({
|
|
7017
7064
|
code: "BF101",
|
package/lib/barefoot_js.rb
CHANGED
|
@@ -184,6 +184,22 @@ module BarefootJS
|
|
|
184
184
|
"<!--bf-#{text}-->"
|
|
185
185
|
end
|
|
186
186
|
|
|
187
|
+
# Neutralize a value for splicing into `comment`'s HTML comment content
|
|
188
|
+
# (#2795 follow-up). `comment` itself does no escaping -- fine for every
|
|
189
|
+
# other caller (marker IDs like "cond-start:s0", "loop:l0", ...), which
|
|
190
|
+
# are entirely compiler-generated, but the whole-item-conditional loop's
|
|
191
|
+
# "loop-i:<key>" anchor carries a user-controlled key. Standard HTML
|
|
192
|
+
# escaping doesn't help inside a comment -- only the literal sequence
|
|
193
|
+
# "-->" terminates it early, and &/</>/"/' are not special there. The
|
|
194
|
+
# key's exact text doesn't need to round-trip (the client's
|
|
195
|
+
# mapArrayAnchored matches items positionally and by its own
|
|
196
|
+
# JS-computed key, never by re-parsing the anchor Comment.nodeValue), so
|
|
197
|
+
# replacing every "-" with the visually-similar U+2010 is sufficient and
|
|
198
|
+
# needs no decoding.
|
|
199
|
+
def escape_comment_key(value)
|
|
200
|
+
string(value).gsub('-', '‐')
|
|
201
|
+
end
|
|
202
|
+
|
|
187
203
|
# Map a JS-boolean-shaped value to the JS `String(bool)` form. See
|
|
188
204
|
# BarefootJS.pm's `bool_str` docstring for the boolean-only contract --
|
|
189
205
|
# callers must have already classified the expression as boolean-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/erb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "ERB (Embedded Ruby) adapter for BarefootJS — compiles IR to .erb templates and ships the Ruby rendering backend; runs under any Rack app (Sinatra, Rails)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"directory": "packages/adapter-erb"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@barefootjs/shared": "0.
|
|
57
|
+
"@barefootjs/shared": "0.35.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
74
|
-
"@barefootjs/jsx": "0.
|
|
75
|
-
"@barefootjs/vite": "0.
|
|
76
|
-
"@barefootjs/client": "0.
|
|
74
|
+
"@barefootjs/jsx": "0.35.0",
|
|
75
|
+
"@barefootjs/vite": "0.35.0",
|
|
76
|
+
"@barefootjs/client": "0.35.0",
|
|
77
77
|
"typescript": "^5.0.0",
|
|
78
78
|
"vite": "^6.0.0"
|
|
79
79
|
}
|
|
@@ -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 ErbEmitContext {
|
|
24
24
|
/**
|
|
@@ -27,6 +27,17 @@ export interface ErbEmitContext {
|
|
|
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 `ErbTopLevelEmitter`'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
|
+
* (`convertExpressionToRuby`) 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.
|
|
@@ -86,8 +86,6 @@ import {
|
|
|
86
86
|
lookupStaticRecordLiteral,
|
|
87
87
|
searchParamsLocalNames,
|
|
88
88
|
prepareLoweringMatchers,
|
|
89
|
-
queryHrefArgs,
|
|
90
|
-
isValidHelperId,
|
|
91
89
|
sortComparatorFromArrow,
|
|
92
90
|
isDangerousInnerHtmlAttr,
|
|
93
91
|
resolveDangerousInnerHtml,
|
|
@@ -417,7 +415,7 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
417
415
|
*/
|
|
418
416
|
parseUndefinedAlternateTernary(
|
|
419
417
|
expr: string,
|
|
420
|
-
): { condition: string; consequent: string } | null {
|
|
418
|
+
): { condition: string; consequent: string; testParsed: ParsedExpr; consequentParsed: ParsedExpr } | null {
|
|
421
419
|
const parsed = parseExpression(expr.trim())
|
|
422
420
|
if (parsed?.kind !== 'conditional') return null
|
|
423
421
|
const alt = parsed.alternate
|
|
@@ -425,13 +423,16 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
425
423
|
(alt.kind === 'identifier' && (alt.name === 'undefined' || alt.name === 'null')) ||
|
|
426
424
|
(alt.kind === 'literal' && (alt.value === null || alt.value === undefined))
|
|
427
425
|
if (!isUndef) return null
|
|
428
|
-
//
|
|
429
|
-
//
|
|
430
|
-
//
|
|
431
|
-
//
|
|
426
|
+
// `condition`/`consequent` are DEBUG text only (`exprToString` renders an
|
|
427
|
+
// unsupported nested shape like an object literal as non-reparseable
|
|
428
|
+
// `[UNSUPPORTED: …]` text) — callers that need to re-lower the
|
|
429
|
+
// sub-expression must use `testParsed`/`consequentParsed` (the actual
|
|
430
|
+
// parsed trees) as `preParsed`, not re-parse these strings.
|
|
432
431
|
return {
|
|
433
432
|
condition: exprToString(parsed.test),
|
|
434
433
|
consequent: exprToString(parsed.consequent),
|
|
434
|
+
testParsed: parsed.test,
|
|
435
|
+
consequentParsed: parsed.consequent,
|
|
435
436
|
}
|
|
436
437
|
}
|
|
437
438
|
|
|
@@ -1036,11 +1037,12 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
1036
1037
|
// `<!--bf-loop-i:KEY-->` anchor before each item's (possibly empty)
|
|
1037
1038
|
// conditional content so the client's `mapArrayAnchored` can hydrate
|
|
1038
1039
|
// every SSR-rendered item by its anchor. `bf.comment` prepends `bf-`,
|
|
1039
|
-
// so `"loop-i:" + KEY` yields `<!--bf-loop-i:KEY-->`. `bf.
|
|
1040
|
-
//
|
|
1040
|
+
// so `"loop-i:" + KEY` yields `<!--bf-loop-i:KEY-->`. `bf.escape_comment_key`
|
|
1041
|
+
// (#2795 follow-up) both stringifies KEY and neutralizes `-` so it can't
|
|
1042
|
+
// spell `-->` and close the comment early — see its doc in `barefoot_js.rb`.
|
|
1041
1043
|
const children =
|
|
1042
1044
|
loop.bodyIsItemConditional && loop.key
|
|
1043
|
-
? `<%= bf.comment("loop-i:" + bf.
|
|
1045
|
+
? `<%= bf.comment("loop-i:" + bf.escape_comment_key(${this.convertExpressionToRuby(loop.key)})) %>\n${renderedChildren}`
|
|
1044
1046
|
: renderedChildren
|
|
1045
1047
|
|
|
1046
1048
|
const lines: string[] = []
|
|
@@ -1501,8 +1503,8 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
1501
1503
|
{
|
|
1502
1504
|
const m = this.parseUndefinedAlternateTernary(value.expr)
|
|
1503
1505
|
if (m) {
|
|
1504
|
-
const cond = this.convertExpressionToRuby(m.
|
|
1505
|
-
const val = this.convertExpressionToRuby(m.
|
|
1506
|
+
const cond = this.convertExpressionToRuby('', m.testParsed)
|
|
1507
|
+
const val = this.convertExpressionToRuby('', m.consequentParsed)
|
|
1506
1508
|
return `<% if bf.truthy?(${cond}) %>${name}="<%= bf.h(${val}) %>"<% end %>`
|
|
1507
1509
|
}
|
|
1508
1510
|
}
|
|
@@ -1819,7 +1821,7 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
1819
1821
|
const hasTaggedTemplate = /[A-Za-z_$][\w$]*\s*`/.test(probe)
|
|
1820
1822
|
if (!startsAsObjectLiteral && !hasTaggedTemplate) return false
|
|
1821
1823
|
const parsed = parseExpression(expr.trim())
|
|
1822
|
-
const support = isSupported(parsed)
|
|
1824
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers })
|
|
1823
1825
|
if (parsed.kind !== 'unsupported' && support.supported) return false
|
|
1824
1826
|
const reason = support.reason ?? (parsed.kind === 'unsupported' ? parsed.reason : undefined)
|
|
1825
1827
|
const reasonLine = reason ? `\n${reason}` : ''
|
|
@@ -1846,6 +1848,7 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
1846
1848
|
private get emitCtx(): ErbEmitContext {
|
|
1847
1849
|
return {
|
|
1848
1850
|
_searchParamsLocals: this._searchParamsLocals,
|
|
1851
|
+
_loweringMatchers: this._loweringMatchers,
|
|
1849
1852
|
resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
|
|
1850
1853
|
resolveLiteralConst: (name) => this.resolveLiteralConst(name),
|
|
1851
1854
|
resolveStaticRecordLiteral: (o, k) => this.resolveStaticRecordLiteral(o, k),
|
|
@@ -1902,42 +1905,16 @@ export class ErbAdapter extends BaseAdapter implements IRNodeEmitter<ErbRenderCt
|
|
|
1902
1905
|
parsed = parseExpression(trimmed)
|
|
1903
1906
|
}
|
|
1904
1907
|
|
|
1905
|
-
// Registered call lowerings, including the built-in `queryHref` plugin,
|
|
1906
|
-
// which lowers `queryHref(base, { … })` to a neutral `guard-list` on
|
|
1907
|
-
// the `query` helper → `bf.query(base, <triples>)`. Recognised before
|
|
1908
|
-
// the support gate because the object-literal arg is otherwise
|
|
1909
|
-
// `unsupported` (BF101). The `bf.query` helper includes a pair iff its
|
|
1910
|
-
// guard is truthy AND its value is a non-empty string (the client's
|
|
1911
|
-
// `if (value)`): a plain `key: v` passes guard `true`, a conditional
|
|
1912
|
-
// `key: cond ? v : undefined` passes the lowered cond. Only the
|
|
1913
|
-
// `query` helper renders to `bf.query`; another guard-list helper must
|
|
1914
|
-
// not be silently mis-rendered as a query.
|
|
1915
|
-
if (parsed.kind === 'call') {
|
|
1916
|
-
for (const matcher of this._loweringMatchers) {
|
|
1917
|
-
const node = matcher(parsed.callee, parsed.args)
|
|
1918
|
-
if (node?.kind === 'guard-list' && node.helper === 'query') {
|
|
1919
|
-
const argsRuby = queryHrefArgs(node, n => this.renderParsedExprToRuby(n))
|
|
1920
|
-
return `bf.query(${argsRuby.join(', ')})`
|
|
1921
|
-
}
|
|
1922
|
-
// Generic `helper-call` (#2069) — the neutral vocabulary's escape
|
|
1923
|
-
// hatch for a userland `LoweringPlugin` that lowers to a single
|
|
1924
|
-
// runtime-helper invocation. `bf.<helper>(args…)` mirrors the
|
|
1925
|
-
// `query` helper's own naming convention exactly: the framework
|
|
1926
|
-
// renders the call, the plugin author registers `<helper>` as a
|
|
1927
|
-
// Ruby-callable method on their own `bf` helper object — same
|
|
1928
|
-
// contract as `bf.query` itself, just not built in.
|
|
1929
|
-
if (node?.kind === 'helper-call' && isValidHelperId(node.helper)) {
|
|
1930
|
-
const argsX = node.args.map(a => this.renderParsedExprToRuby(a))
|
|
1931
|
-
return `bf.${node.helper}(${argsX.join(', ')})`
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
1908
|
// `pos` distinguishes a derived-seed RHS (an assignment, checked via
|
|
1937
1909
|
// `isSupportedValue`) from every other, genuinely rendered call site —
|
|
1938
1910
|
// the rendered gate would otherwise re-refuse a tree the seed plan
|
|
1939
1911
|
// already classified `derived` at value position (#2696 review).
|
|
1940
|
-
|
|
1912
|
+
// Registered call lowerings (#2057) — including the built-in `queryHref`
|
|
1913
|
+
// plugin — are consulted by this gate no matter where the call sits in
|
|
1914
|
+
// the tree (`ErbTopLevelEmitter`'s `lowering` seam does the actual
|
|
1915
|
+
// rendering below, via `emitParsedExpr`'s shared `call` case).
|
|
1916
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers }
|
|
1917
|
+
const support = pos === 'value' ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts)
|
|
1941
1918
|
if (!support.supported) {
|
|
1942
1919
|
this.errors.push({
|
|
1943
1920
|
code: 'BF101',
|
|
@@ -46,6 +46,10 @@ import {
|
|
|
46
46
|
identifierPath,
|
|
47
47
|
matchSearchParamsMethodCall,
|
|
48
48
|
sortComparatorFromArrow,
|
|
49
|
+
type LoweringEmitter,
|
|
50
|
+
type LoweringNode,
|
|
51
|
+
queryHrefArgs,
|
|
52
|
+
isValidHelperId,
|
|
49
53
|
} from '@barefootjs/jsx'
|
|
50
54
|
|
|
51
55
|
import type { ErbEmitContext } from '../emit-context.ts'
|
|
@@ -346,6 +350,35 @@ export class ErbTopLevelEmitter implements ParsedExprEmitter {
|
|
|
346
350
|
this.ctx = ctx
|
|
347
351
|
}
|
|
348
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
|
|
355
|
+
* tries every matcher here BEFORE `call()` itself, so a registered call
|
|
356
|
+
* (the built-in `queryHref`, or any userland plugin) is recognised no
|
|
357
|
+
* matter where it sits in the tree. `render` is what used to live inline
|
|
358
|
+
* in `ErbAdapter.convertExpressionToRuby` before the object-literal
|
|
359
|
+
* support-gate refusal (`checkSupport`'s `call` arm, now itself
|
|
360
|
+
* registry-aware) made the pre-gate special case unnecessary.
|
|
361
|
+
*/
|
|
362
|
+
get lowering(): LoweringEmitter {
|
|
363
|
+
return {
|
|
364
|
+
matchers: this.ctx._loweringMatchers,
|
|
365
|
+
render: (node: LoweringNode, emit: (e: ParsedExpr) => string): string | null => {
|
|
366
|
+
// `query` guard-list — `queryHref`-shaped.
|
|
367
|
+
if (node.kind === 'guard-list' && node.helper === 'query') {
|
|
368
|
+
const qArgs = queryHrefArgs(node, emit)
|
|
369
|
+
return `bf.query(${qArgs.join(', ')})`
|
|
370
|
+
}
|
|
371
|
+
// Generic `helper-call` (#2069) — a userland `LoweringPlugin`'s
|
|
372
|
+
// single runtime-helper invocation; `bf.<helper>(args…)` mirrors
|
|
373
|
+
// the `query` helper's own naming convention.
|
|
374
|
+
if (node.kind === 'helper-call' && isValidHelperId(node.helper)) {
|
|
375
|
+
return `bf.${node.helper}(${node.args.map(emit).join(', ')})`
|
|
376
|
+
}
|
|
377
|
+
return null
|
|
378
|
+
},
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
349
382
|
identifier(name: string): string {
|
|
350
383
|
// `undefined` / `null` nested inside a larger expression tree (e.g.
|
|
351
384
|
// `props.isActive ? 'page' : undefined`) — the top-level short-circuits
|
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
|
+
// `ErbTopLevelEmitter`'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,7 +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
|
-
export const renderDivergences: RenderDivergences = {
|
|
19
|
-
'aliased-loop-source':
|
|
20
|
-
'A `.map()` loop whose source is a local const alias of a signal getter (`const items__alias = items`) throws `undefined method \'length\' for nil (NoMethodError)` on real Ruby ERB — 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.',
|
|
21
|
-
}
|
|
18
|
+
export const renderDivergences: RenderDivergences = {}
|
package/src/test-render.ts
CHANGED
|
@@ -618,6 +618,20 @@ function buildRubyProps(
|
|
|
618
618
|
}
|
|
619
619
|
}
|
|
620
620
|
|
|
621
|
+
// #2813: `extractSsrDefaults` can seed an entry under a name that is
|
|
622
|
+
// none of `propsParams` / `signals` / `memos` above — a bare local-const
|
|
623
|
+
// alias of a signal/memo getter (`const items__alias = items`,
|
|
624
|
+
// `ssr-defaults.ts`) seeds `items__alias` alongside `items`. Production
|
|
625
|
+
// hands the whole manifest-derived stash straight through
|
|
626
|
+
// (`deriveStashFromDefaults` IS the production seeding mechanism here,
|
|
627
|
+
// not a harness stand-in), so any leftover `derivedProps` key must be
|
|
628
|
+
// copied into `obj` too, or this harness would silently omit what
|
|
629
|
+
// production actually provides, mismeasuring this conformance case.
|
|
630
|
+
for (const [name, value] of Object.entries(derivedProps)) {
|
|
631
|
+
if (Object.prototype.hasOwnProperty.call(obj, name)) continue
|
|
632
|
+
obj[name] = value
|
|
633
|
+
}
|
|
634
|
+
|
|
621
635
|
const needsSearchParams = importsSearchParams(ir.metadata)
|
|
622
636
|
|
|
623
637
|
return { obj, needsSearchParams, userProps }
|