@barefootjs/jinja 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/jinja-adapter.d.ts +14 -0
- package/dist/adapter/jinja-adapter.d.ts.map +1 -1
- 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/package.json +5 -5
- package/python/barefootjs/runtime.py +16 -0
- package/src/__tests__/jinja-adapter-unit.test.ts +2 -2
- package/src/adapter/emit-context.ts +12 -1
- package/src/adapter/expr/emitters.ts +43 -0
- package/src/adapter/jinja-adapter.ts +39 -39
- package/src/conformance-pins.ts +4 -0
- package/src/render-divergences.ts +1 -4
- package/src/test-render.ts +20 -0
|
@@ -18,13 +18,23 @@
|
|
|
18
18
|
* genuinely needs it, so the seam documents the real cross-module coupling
|
|
19
19
|
* rather than re-exposing the whole adapter.
|
|
20
20
|
*/
|
|
21
|
-
import type { ParsedExpr, CompilerError, IRMetadata } from '@barefootjs/jsx';
|
|
21
|
+
import type { ParsedExpr, CompilerError, IRMetadata, LoweringMatcher } from '@barefootjs/jsx';
|
|
22
22
|
export interface JinjaEmitContext {
|
|
23
23
|
/**
|
|
24
24
|
* (#1922) Local binding names the request-scoped `searchParams()` env signal
|
|
25
25
|
* is imported under. Non-empty enables the env-signal method-call lowering.
|
|
26
26
|
*/
|
|
27
27
|
readonly _searchParamsLocals: Set<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Registered lowering-plugin matchers (#2057), bound to this component's
|
|
30
|
+
* metadata at init. Read by `JinjaTopLevelEmitter`'s `lowering` seam
|
|
31
|
+
* (#2843) so a registered call — the built-in `queryHref`, or any
|
|
32
|
+
* userland plugin — is recognised no matter where it sits in an
|
|
33
|
+
* expression tree (a ternary branch, a template-literal interpolation, …),
|
|
34
|
+
* not only when it's the call the adapter's own top-level conversion
|
|
35
|
+
* entry point (`convertExpressionToJinja`) is asked to lower directly.
|
|
36
|
+
*/
|
|
37
|
+
readonly _loweringMatchers: readonly LoweringMatcher[];
|
|
28
38
|
/**
|
|
29
39
|
* Inline a module-scope pure string-literal const by name as the resolved
|
|
30
40
|
* 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;;;;;;;;;;;;;;;;;;;GAmBG;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;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE7F,MAAM,WAAW,gBAAgB;IAC/B;;;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,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAEtD,oFAAoF;IACpF,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAEjD;;;OAGG;IACH,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IAE3E,wDAAwD;IACxD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAExD,yEAAyE;IACzE,4BAA4B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,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;;;;;;;;OAQG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;IAEtE;;;;;;OAMG;IACH,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACtE;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;IAElG;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CACjC"}
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
* unaffected and still used for that path plus the filter-predicate
|
|
48
48
|
* entry point `_renderJinjaFilterExprPublic`.
|
|
49
49
|
*/
|
|
50
|
-
import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
|
|
50
|
+
import { type ParsedExprEmitter, type LoweringEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
|
|
51
51
|
import type { JinjaEmitContext } from '../emit-context.ts';
|
|
52
52
|
/**
|
|
53
53
|
* Route a condition-TEST position through `bf.truthy(...)` unless the node
|
|
@@ -110,6 +110,16 @@ export declare class JinjaFilterEmitter implements ParsedExprEmitter {
|
|
|
110
110
|
export declare class JinjaTopLevelEmitter implements ParsedExprEmitter {
|
|
111
111
|
private readonly ctx;
|
|
112
112
|
constructor(ctx: JinjaEmitContext);
|
|
113
|
+
/**
|
|
114
|
+
* Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
|
|
115
|
+
* tries every matcher here BEFORE `call()` itself, so a registered call
|
|
116
|
+
* (the built-in `queryHref`, or any userland plugin) is recognised no
|
|
117
|
+
* matter where it sits in the tree. `render` is what used to live inline
|
|
118
|
+
* in `JinjaAdapter.convertExpressionToJinja` before the object-literal
|
|
119
|
+
* support-gate refusal (`checkSupport`'s `call` arm, now itself
|
|
120
|
+
* registry-aware) made the pre-gate special case unnecessary.
|
|
121
|
+
*/
|
|
122
|
+
get lowering(): LoweringEmitter;
|
|
113
123
|
identifier(name: string): string;
|
|
114
124
|
literal(value: string | number | boolean | null, literalType: LiteralType): string;
|
|
115
125
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAEL,KAAK,iBAAiB,
|
|
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,
|
|
@@ -187691,7 +187689,9 @@ import {
|
|
|
187691
187689
|
groupObjectLiteralSegments,
|
|
187692
187690
|
identifierPath,
|
|
187693
187691
|
matchSearchParamsMethodCall,
|
|
187694
|
-
sortComparatorFromArrow
|
|
187692
|
+
sortComparatorFromArrow,
|
|
187693
|
+
queryHrefArgs,
|
|
187694
|
+
isValidHelperId
|
|
187695
187695
|
} from "@barefootjs/jsx";
|
|
187696
187696
|
var PREDICATE_METHODS = new Set([
|
|
187697
187697
|
"filter",
|
|
@@ -187820,6 +187820,21 @@ class JinjaTopLevelEmitter {
|
|
|
187820
187820
|
constructor(ctx) {
|
|
187821
187821
|
this.ctx = ctx;
|
|
187822
187822
|
}
|
|
187823
|
+
get lowering() {
|
|
187824
|
+
return {
|
|
187825
|
+
matchers: this.ctx._loweringMatchers,
|
|
187826
|
+
render: (node, emit) => {
|
|
187827
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
187828
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
187829
|
+
return `bf.query(${qArgs.join(", ")})`;
|
|
187830
|
+
}
|
|
187831
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
187832
|
+
return `bf.${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
187833
|
+
}
|
|
187834
|
+
return null;
|
|
187835
|
+
}
|
|
187836
|
+
};
|
|
187837
|
+
}
|
|
187823
187838
|
identifier(name) {
|
|
187824
187839
|
if (name === "undefined" || name === "null")
|
|
187825
187840
|
return "none";
|
|
@@ -188677,7 +188692,7 @@ ${whenTrue}
|
|
|
188677
188692
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188678
188693
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188679
188694
|
this.inLoop = prevInLoop;
|
|
188680
|
-
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.
|
|
188695
|
+
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.escape_comment_key(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
188681
188696
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
188682
188697
|
this.scope = prevScope;
|
|
188683
188698
|
const lines = [];
|
|
@@ -188882,8 +188897,8 @@ ${body}
|
|
|
188882
188897
|
{
|
|
188883
188898
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
188884
188899
|
if (m) {
|
|
188885
|
-
const cond = this.convertConditionToJinja(m.condition);
|
|
188886
|
-
const val = this.convertExpressionToJinja(m.consequent);
|
|
188900
|
+
const cond = this.convertConditionToJinja(m.condition, m.testParsed);
|
|
188901
|
+
const val = this.convertExpressionToJinja(m.consequent, m.consequentParsed);
|
|
188887
188902
|
return `
|
|
188888
188903
|
{% if ${cond} %}
|
|
188889
188904
|
${name}="{{ bf.string(${val}) }}"
|
|
@@ -189016,7 +189031,7 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
189016
189031
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
189017
189032
|
return false;
|
|
189018
189033
|
const parsed = parseExpression2(expr.trim());
|
|
189019
|
-
const support = isSupported(parsed);
|
|
189034
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
189020
189035
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
189021
189036
|
return false;
|
|
189022
189037
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -189036,6 +189051,7 @@ ${reason}` : "";
|
|
|
189036
189051
|
get emitCtx() {
|
|
189037
189052
|
return {
|
|
189038
189053
|
_searchParamsLocals: this._searchParamsLocals,
|
|
189054
|
+
_loweringMatchers: this._loweringMatchers,
|
|
189039
189055
|
_resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
|
|
189040
189056
|
_resolveLiteralConst: (name) => this._resolveLiteralConst(name),
|
|
189041
189057
|
_resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
|
|
@@ -189069,20 +189085,8 @@ ${reason}` : "";
|
|
|
189069
189085
|
return "''";
|
|
189070
189086
|
parsed = parseExpression2(trimmed);
|
|
189071
189087
|
}
|
|
189072
|
-
|
|
189073
|
-
|
|
189074
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
189075
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
189076
|
-
const qArgs = queryHrefArgs(node, (n) => this.renderParsedExprToJinja(n));
|
|
189077
|
-
return `bf.query(${qArgs.join(", ")})`;
|
|
189078
|
-
}
|
|
189079
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
189080
|
-
const argsX = node.args.map((a) => this.renderParsedExprToJinja(a));
|
|
189081
|
-
return `bf.${node.helper}(${argsX.join(", ")})`;
|
|
189082
|
-
}
|
|
189083
|
-
}
|
|
189084
|
-
}
|
|
189085
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
189088
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
189089
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
189086
189090
|
if (!support.supported) {
|
|
189087
189091
|
this.errors.push({
|
|
189088
189092
|
code: "BF101",
|
|
@@ -189127,7 +189131,9 @@ Options:
|
|
|
189127
189131
|
return null;
|
|
189128
189132
|
return {
|
|
189129
189133
|
condition: exprToString(parsed.test),
|
|
189130
|
-
consequent: exprToString(parsed.consequent)
|
|
189134
|
+
consequent: exprToString(parsed.consequent),
|
|
189135
|
+
testParsed: parsed.test,
|
|
189136
|
+
consequentParsed: parsed.consequent
|
|
189131
189137
|
};
|
|
189132
189138
|
}
|
|
189133
189139
|
isBooleanTypedPropRef(expr) {
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
*/
|
|
90
90
|
import type { ComponentIR, IRNode, IRElement, IRText, IRExpression, IRConditional, IRLoop, IRComponent, IRFragment, IRSlot, IRIfStatement, IRProvider, IRAsync, TemplatePrimitiveRegistry } from '@barefootjs/jsx';
|
|
91
91
|
import { BaseAdapter, type AdapterOutput, type AdapterGenerateOptions, type IRNodeEmitter, type EmitIRNode } from '@barefootjs/jsx';
|
|
92
|
+
import type { ParsedExpr } from '@barefootjs/jsx';
|
|
92
93
|
import type { JinjaRenderCtx } from './lib/types.ts';
|
|
93
94
|
export type { JinjaAdapterOptions } from './lib/types.ts';
|
|
94
95
|
import type { JinjaAdapterOptions } from './lib/types.ts';
|
|
@@ -390,10 +391,23 @@ export declare class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<J
|
|
|
390
391
|
* Parse `cond ? value : undefined` (or `: null`), returning the
|
|
391
392
|
* condition/consequent source spans, else `null`. Used for the
|
|
392
393
|
* attribute-omission rule (#1897).
|
|
394
|
+
*
|
|
395
|
+
* `testParsed`/`consequentParsed` (#2843 review) are the ACTUAL parsed
|
|
396
|
+
* sub-trees, for the caller to pass through as `preParsed` — `condition`/
|
|
397
|
+
* `consequent` are `exprToString` output, a DEBUG formatter that renders
|
|
398
|
+
* any nested `object-literal` as the non-reparseable `[UNSUPPORTED: …]`
|
|
399
|
+
* placeholder (unlike `stringifyParsedExpr`, meant for round-tripping).
|
|
400
|
+
* Re-parsing THAT string for a consequent like `queryHref(base, { tag })`
|
|
401
|
+
* would corrupt the call's args before the lowering registry — now
|
|
402
|
+
* consulted at any nesting depth (#2843) — ever sees them. Kept for any
|
|
403
|
+
* caller that only needs the string form; the parsed trees are the
|
|
404
|
+
* correct input wherever the caller can accept `preParsed`.
|
|
393
405
|
*/
|
|
394
406
|
parseUndefinedAlternateTernary(expr: string): {
|
|
395
407
|
condition: string;
|
|
396
408
|
consequent: string;
|
|
409
|
+
testParsed: ParsedExpr;
|
|
410
|
+
consequentParsed: ParsedExpr;
|
|
397
411
|
} | null;
|
|
398
412
|
isBooleanTypedPropRef(expr: string): boolean;
|
|
399
413
|
/** Position-accurate loop-bound-name check — see `this.scope`'s docstring. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,OAAO,EAKP,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":"jinja-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/jinja-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,eAiE7B,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,
|
|
@@ -187691,7 +187689,9 @@ import {
|
|
|
187691
187689
|
groupObjectLiteralSegments,
|
|
187692
187690
|
identifierPath,
|
|
187693
187691
|
matchSearchParamsMethodCall,
|
|
187694
|
-
sortComparatorFromArrow
|
|
187692
|
+
sortComparatorFromArrow,
|
|
187693
|
+
queryHrefArgs,
|
|
187694
|
+
isValidHelperId
|
|
187695
187695
|
} from "@barefootjs/jsx";
|
|
187696
187696
|
var PREDICATE_METHODS = new Set([
|
|
187697
187697
|
"filter",
|
|
@@ -187820,6 +187820,21 @@ class JinjaTopLevelEmitter {
|
|
|
187820
187820
|
constructor(ctx) {
|
|
187821
187821
|
this.ctx = ctx;
|
|
187822
187822
|
}
|
|
187823
|
+
get lowering() {
|
|
187824
|
+
return {
|
|
187825
|
+
matchers: this.ctx._loweringMatchers,
|
|
187826
|
+
render: (node, emit) => {
|
|
187827
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
187828
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
187829
|
+
return `bf.query(${qArgs.join(", ")})`;
|
|
187830
|
+
}
|
|
187831
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
187832
|
+
return `bf.${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
187833
|
+
}
|
|
187834
|
+
return null;
|
|
187835
|
+
}
|
|
187836
|
+
};
|
|
187837
|
+
}
|
|
187823
187838
|
identifier(name) {
|
|
187824
187839
|
if (name === "undefined" || name === "null")
|
|
187825
187840
|
return "none";
|
|
@@ -188677,7 +188692,7 @@ ${whenTrue}
|
|
|
188677
188692
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
188678
188693
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
188679
188694
|
this.inLoop = prevInLoop;
|
|
188680
|
-
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.
|
|
188695
|
+
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.escape_comment_key(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
188681
188696
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
188682
188697
|
this.scope = prevScope;
|
|
188683
188698
|
const lines = [];
|
|
@@ -188882,8 +188897,8 @@ ${body}
|
|
|
188882
188897
|
{
|
|
188883
188898
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
188884
188899
|
if (m) {
|
|
188885
|
-
const cond = this.convertConditionToJinja(m.condition);
|
|
188886
|
-
const val = this.convertExpressionToJinja(m.consequent);
|
|
188900
|
+
const cond = this.convertConditionToJinja(m.condition, m.testParsed);
|
|
188901
|
+
const val = this.convertExpressionToJinja(m.consequent, m.consequentParsed);
|
|
188887
188902
|
return `
|
|
188888
188903
|
{% if ${cond} %}
|
|
188889
188904
|
${name}="{{ bf.string(${val}) }}"
|
|
@@ -189016,7 +189031,7 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
189016
189031
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
189017
189032
|
return false;
|
|
189018
189033
|
const parsed = parseExpression2(expr.trim());
|
|
189019
|
-
const support = isSupported(parsed);
|
|
189034
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
189020
189035
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
189021
189036
|
return false;
|
|
189022
189037
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -189036,6 +189051,7 @@ ${reason}` : "";
|
|
|
189036
189051
|
get emitCtx() {
|
|
189037
189052
|
return {
|
|
189038
189053
|
_searchParamsLocals: this._searchParamsLocals,
|
|
189054
|
+
_loweringMatchers: this._loweringMatchers,
|
|
189039
189055
|
_resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
|
|
189040
189056
|
_resolveLiteralConst: (name) => this._resolveLiteralConst(name),
|
|
189041
189057
|
_resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
|
|
@@ -189069,20 +189085,8 @@ ${reason}` : "";
|
|
|
189069
189085
|
return "''";
|
|
189070
189086
|
parsed = parseExpression2(trimmed);
|
|
189071
189087
|
}
|
|
189072
|
-
|
|
189073
|
-
|
|
189074
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
189075
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
189076
|
-
const qArgs = queryHrefArgs(node, (n) => this.renderParsedExprToJinja(n));
|
|
189077
|
-
return `bf.query(${qArgs.join(", ")})`;
|
|
189078
|
-
}
|
|
189079
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
189080
|
-
const argsX = node.args.map((a) => this.renderParsedExprToJinja(a));
|
|
189081
|
-
return `bf.${node.helper}(${argsX.join(", ")})`;
|
|
189082
|
-
}
|
|
189083
|
-
}
|
|
189084
|
-
}
|
|
189085
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
189088
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
189089
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
189086
189090
|
if (!support.supported) {
|
|
189087
189091
|
this.errors.push({
|
|
189088
189092
|
code: "BF101",
|
|
@@ -189127,7 +189131,9 @@ Options:
|
|
|
189127
189131
|
return null;
|
|
189128
189132
|
return {
|
|
189129
189133
|
condition: exprToString(parsed.test),
|
|
189130
|
-
consequent: exprToString(parsed.consequent)
|
|
189134
|
+
consequent: exprToString(parsed.consequent),
|
|
189135
|
+
testParsed: parsed.test,
|
|
189136
|
+
consequentParsed: parsed.consequent
|
|
189131
189137
|
};
|
|
189132
189138
|
}
|
|
189133
189139
|
isBooleanTypedPropRef(expr) {
|
|
@@ -189238,9 +189244,7 @@ var conformancePins = {
|
|
|
189238
189244
|
"namespace-import-primitive": [{ code: "BF013", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2771" }]
|
|
189239
189245
|
};
|
|
189240
189246
|
// src/render-divergences.ts
|
|
189241
|
-
var renderDivergences = {
|
|
189242
|
-
"aliased-loop-source": "A `.map()` loop whose source is a local const alias of a signal getter (`const items__alias = items`) SSRs an empty `<ul>` on real Jinja2 — 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."
|
|
189243
|
-
};
|
|
189247
|
+
var renderDivergences = {};
|
|
189244
189248
|
export {
|
|
189245
189249
|
renderDivergences,
|
|
189246
189250
|
jinjaAdapter,
|
|
@@ -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
|
}
|
|
@@ -2280,6 +2326,12 @@ class BindingScope {
|
|
|
2280
2326
|
}
|
|
2281
2327
|
}
|
|
2282
2328
|
|
|
2329
|
+
// ../jsx/src/ir-to-client-js/safe-html.ts
|
|
2330
|
+
function safeHtml(expr) {
|
|
2331
|
+
return expr;
|
|
2332
|
+
}
|
|
2333
|
+
var EMPTY_MARKUP = safeHtml("''");
|
|
2334
|
+
|
|
2283
2335
|
// ../jsx/src/ir-to-client-js/html-template.ts
|
|
2284
2336
|
var VOID_ELEMENTS = new Set([
|
|
2285
2337
|
"area",
|
|
@@ -2566,6 +2618,7 @@ var CLIENT_EXPORTS = new Set([
|
|
|
2566
2618
|
"isSSRPortal",
|
|
2567
2619
|
"findSiblingSlot",
|
|
2568
2620
|
"cleanupPortalPlaceholder",
|
|
2621
|
+
"trackPosition",
|
|
2569
2622
|
"createSearchParams",
|
|
2570
2623
|
"queryHref",
|
|
2571
2624
|
"formatDate",
|
|
@@ -2626,7 +2679,8 @@ var BROWSER_ONLY_CLIENT_APIS = new Set([
|
|
|
2626
2679
|
"createPortal",
|
|
2627
2680
|
"isSSRPortal",
|
|
2628
2681
|
"findSiblingSlot",
|
|
2629
|
-
"cleanupPortalPlaceholder"
|
|
2682
|
+
"cleanupPortalPlaceholder",
|
|
2683
|
+
"trackPosition"
|
|
2630
2684
|
]);
|
|
2631
2685
|
var REACTIVE_PRIMITIVES = new Set([
|
|
2632
2686
|
"createSignal",
|
|
@@ -3225,30 +3279,6 @@ import ts16 from "typescript";
|
|
|
3225
3279
|
|
|
3226
3280
|
// ../jsx/src/relocate.ts
|
|
3227
3281
|
import ts18 from "typescript";
|
|
3228
|
-
|
|
3229
|
-
// ../jsx/src/lowering-registry.ts
|
|
3230
|
-
var plugins = [];
|
|
3231
|
-
function registerLoweringPlugin(plugin) {
|
|
3232
|
-
const existing = plugins.findIndex((p) => p.name === plugin.name);
|
|
3233
|
-
if (existing >= 0)
|
|
3234
|
-
plugins[existing] = plugin;
|
|
3235
|
-
else
|
|
3236
|
-
plugins.push(plugin);
|
|
3237
|
-
}
|
|
3238
|
-
function prepareLoweringMatchers(metadata) {
|
|
3239
|
-
const matchers = [];
|
|
3240
|
-
for (const plugin of plugins) {
|
|
3241
|
-
const matcher = plugin.prepare(metadata);
|
|
3242
|
-
if (matcher)
|
|
3243
|
-
matchers.push(matcher);
|
|
3244
|
-
}
|
|
3245
|
-
return matchers;
|
|
3246
|
-
}
|
|
3247
|
-
function isValidHelperId(helper) {
|
|
3248
|
-
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(helper);
|
|
3249
|
-
}
|
|
3250
|
-
|
|
3251
|
-
// ../jsx/src/relocate.ts
|
|
3252
3282
|
var REGISTRY_SAFE_BINDING_KINDS = new Set([
|
|
3253
3283
|
"global",
|
|
3254
3284
|
"module-import",
|
|
@@ -4715,6 +4745,17 @@ function emitParsedExpr(expr, emitter) {
|
|
|
4715
4745
|
case "literal":
|
|
4716
4746
|
return emitter.literal(expr.value, expr.literalType);
|
|
4717
4747
|
case "call": {
|
|
4748
|
+
if (emitter.lowering) {
|
|
4749
|
+
for (const matcher of emitter.lowering.matchers) {
|
|
4750
|
+
const node = matcher(expr.callee, expr.args);
|
|
4751
|
+
if (!node)
|
|
4752
|
+
continue;
|
|
4753
|
+
const rendered = emitter.lowering.render(node, emit);
|
|
4754
|
+
if (rendered !== null)
|
|
4755
|
+
return rendered;
|
|
4756
|
+
break;
|
|
4757
|
+
}
|
|
4758
|
+
}
|
|
4718
4759
|
const cb = asCallbackMethodCall(expr);
|
|
4719
4760
|
if (cb)
|
|
4720
4761
|
return emitter.callbackMethod(cb.method, cb.object, cb.arrow, cb.args, emit);
|
|
@@ -5723,6 +5764,21 @@ class JinjaTopLevelEmitter {
|
|
|
5723
5764
|
constructor(ctx) {
|
|
5724
5765
|
this.ctx = ctx;
|
|
5725
5766
|
}
|
|
5767
|
+
get lowering() {
|
|
5768
|
+
return {
|
|
5769
|
+
matchers: this.ctx._loweringMatchers,
|
|
5770
|
+
render: (node, emit) => {
|
|
5771
|
+
if (node.kind === "guard-list" && node.helper === "query") {
|
|
5772
|
+
const qArgs = queryHrefArgs(node, emit);
|
|
5773
|
+
return `bf.query(${qArgs.join(", ")})`;
|
|
5774
|
+
}
|
|
5775
|
+
if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
5776
|
+
return `bf.${node.helper}(${node.args.map(emit).join(", ")})`;
|
|
5777
|
+
}
|
|
5778
|
+
return null;
|
|
5779
|
+
}
|
|
5780
|
+
};
|
|
5781
|
+
}
|
|
5726
5782
|
identifier(name) {
|
|
5727
5783
|
if (name === "undefined" || name === "null")
|
|
5728
5784
|
return "none";
|
|
@@ -6571,7 +6627,7 @@ ${whenTrue}
|
|
|
6571
6627
|
const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `{% set ${jinjaIdent(d.name)} = ${this.convertExpressionToJinja(d.raw, d.valueParsed)} %}`);
|
|
6572
6628
|
const childrenUnderLoop = this.renderChildren(loop.children);
|
|
6573
6629
|
this.inLoop = prevInLoop;
|
|
6574
|
-
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.
|
|
6630
|
+
const bodyChildren = loop.bodyIsItemConditional && loop.key ? `{{ bf.comment("loop-i:" ~ bf.escape_comment_key(${this.convertExpressionToJinja(loop.key)})) | safe }}
|
|
6575
6631
|
${childrenUnderLoop}` : childrenUnderLoop;
|
|
6576
6632
|
this.scope = prevScope;
|
|
6577
6633
|
const lines = [];
|
|
@@ -6776,8 +6832,8 @@ ${body}
|
|
|
6776
6832
|
{
|
|
6777
6833
|
const m = this.parseUndefinedAlternateTernary(value.expr);
|
|
6778
6834
|
if (m) {
|
|
6779
|
-
const cond = this.convertConditionToJinja(m.condition);
|
|
6780
|
-
const val = this.convertExpressionToJinja(m.consequent);
|
|
6835
|
+
const cond = this.convertConditionToJinja(m.condition, m.testParsed);
|
|
6836
|
+
const val = this.convertExpressionToJinja(m.consequent, m.consequentParsed);
|
|
6781
6837
|
return `
|
|
6782
6838
|
{% if ${cond} %}
|
|
6783
6839
|
${name}="{{ bf.string(${val}) }}"
|
|
@@ -6910,7 +6966,7 @@ ${name}="{{ bf.string(${val}) }}"
|
|
|
6910
6966
|
if (!startsAsObjectLiteral && !hasTaggedTemplate)
|
|
6911
6967
|
return false;
|
|
6912
6968
|
const parsed = parseExpression(expr.trim());
|
|
6913
|
-
const support = isSupported(parsed);
|
|
6969
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
|
|
6914
6970
|
if (parsed.kind !== "unsupported" && support.supported)
|
|
6915
6971
|
return false;
|
|
6916
6972
|
const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
|
|
@@ -6930,6 +6986,7 @@ ${reason}` : "";
|
|
|
6930
6986
|
get emitCtx() {
|
|
6931
6987
|
return {
|
|
6932
6988
|
_searchParamsLocals: this._searchParamsLocals,
|
|
6989
|
+
_loweringMatchers: this._loweringMatchers,
|
|
6933
6990
|
_resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
|
|
6934
6991
|
_resolveLiteralConst: (name) => this._resolveLiteralConst(name),
|
|
6935
6992
|
_resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
|
|
@@ -6963,20 +7020,8 @@ ${reason}` : "";
|
|
|
6963
7020
|
return "''";
|
|
6964
7021
|
parsed = parseExpression(trimmed);
|
|
6965
7022
|
}
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
const node = matcher(parsed.callee, parsed.args);
|
|
6969
|
-
if (node?.kind === "guard-list" && node.helper === "query") {
|
|
6970
|
-
const qArgs = queryHrefArgs(node, (n) => this.renderParsedExprToJinja(n));
|
|
6971
|
-
return `bf.query(${qArgs.join(", ")})`;
|
|
6972
|
-
}
|
|
6973
|
-
if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
|
|
6974
|
-
const argsX = node.args.map((a) => this.renderParsedExprToJinja(a));
|
|
6975
|
-
return `bf.${node.helper}(${argsX.join(", ")})`;
|
|
6976
|
-
}
|
|
6977
|
-
}
|
|
6978
|
-
}
|
|
6979
|
-
const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
|
|
7023
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers };
|
|
7024
|
+
const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
|
|
6980
7025
|
if (!support.supported) {
|
|
6981
7026
|
this.errors.push({
|
|
6982
7027
|
code: "BF101",
|
|
@@ -7021,7 +7066,9 @@ Options:
|
|
|
7021
7066
|
return null;
|
|
7022
7067
|
return {
|
|
7023
7068
|
condition: exprToString(parsed.test),
|
|
7024
|
-
consequent: exprToString(parsed.consequent)
|
|
7069
|
+
consequent: exprToString(parsed.consequent),
|
|
7070
|
+
testParsed: parsed.test,
|
|
7071
|
+
consequentParsed: parsed.consequent
|
|
7025
7072
|
};
|
|
7026
7073
|
}
|
|
7027
7074
|
isBooleanTypedPropRef(expr) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/jinja",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Jinja2 adapter for BarefootJS — compiles IR to .jinja templates and ships the Python BarefootJS rendering runtime; runs under any Python web framework (Flask, etc.)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"directory": "packages/adapter-jinja"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@barefootjs/shared": "0.
|
|
56
|
+
"@barefootjs/shared": "0.35.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@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
|
"typescript": "^5.0.0",
|
|
77
77
|
"vite": "^6.0.0"
|
|
78
78
|
}
|
|
@@ -659,6 +659,22 @@ class BarefootJS:
|
|
|
659
659
|
def comment(self, text: str) -> str:
|
|
660
660
|
return f"<!--bf-{text}-->"
|
|
661
661
|
|
|
662
|
+
def escape_comment_key(self, value: Any) -> str:
|
|
663
|
+
"""Neutralize a value for splicing into `comment`'s HTML comment
|
|
664
|
+
content (#2795 follow-up). `comment` itself does no escaping --
|
|
665
|
+
fine for every other caller (marker IDs like "cond-start:s0",
|
|
666
|
+
"loop:l0", ...), which are entirely compiler-generated, but the
|
|
667
|
+
whole-item-conditional loop's "loop-i:<key>" anchor carries a
|
|
668
|
+
user-controlled key. Standard HTML escaping doesn't help inside a
|
|
669
|
+
comment -- only the literal sequence "-->" terminates it early, and
|
|
670
|
+
&/</>/"/' are not special there. The key's exact text doesn't need
|
|
671
|
+
to round-trip (the client's mapArrayAnchored matches items
|
|
672
|
+
positionally and by its own JS-computed key, never by re-parsing
|
|
673
|
+
the anchor Comment.nodeValue), so replacing every "-" with the
|
|
674
|
+
visually-similar U+2010 is sufficient and needs no decoding.
|
|
675
|
+
"""
|
|
676
|
+
return self.string(value).replace("-", "‐")
|
|
677
|
+
|
|
662
678
|
# -----------------------------------------------------------------
|
|
663
679
|
# JS-equivalent value stringification
|
|
664
680
|
# -----------------------------------------------------------------
|
|
@@ -549,8 +549,8 @@ function Widget({ values }: { values: number[] }) {
|
|
|
549
549
|
return <ul>{values.map((label) => (label > 0 ? <li key={label}>{label}</li> : null))}</ul>
|
|
550
550
|
}
|
|
551
551
|
`)
|
|
552
|
-
expect(template).toContain('bf.comment("loop-i:" ~ bf.
|
|
553
|
-
expect(template).not.toContain("bf.comment(\"loop-i:\" ~ bf.
|
|
552
|
+
expect(template).toContain('bf.comment("loop-i:" ~ bf.escape_comment_key(label))')
|
|
553
|
+
expect(template).not.toContain("bf.comment(\"loop-i:\" ~ bf.escape_comment_key('x'))")
|
|
554
554
|
})
|
|
555
555
|
|
|
556
556
|
test('a loop param shadowing an outer const resolves to the row value inside a .map() preamble local initializer', () => {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* rather than re-exposing the whole adapter.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { ParsedExpr, CompilerError, IRMetadata } from '@barefootjs/jsx'
|
|
22
|
+
import type { ParsedExpr, CompilerError, IRMetadata, LoweringMatcher } from '@barefootjs/jsx'
|
|
23
23
|
|
|
24
24
|
export interface JinjaEmitContext {
|
|
25
25
|
/**
|
|
@@ -28,6 +28,17 @@ export interface JinjaEmitContext {
|
|
|
28
28
|
*/
|
|
29
29
|
readonly _searchParamsLocals: Set<string>
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Registered lowering-plugin matchers (#2057), bound to this component's
|
|
33
|
+
* metadata at init. Read by `JinjaTopLevelEmitter`'s `lowering` seam
|
|
34
|
+
* (#2843) so a registered call — the built-in `queryHref`, or any
|
|
35
|
+
* userland plugin — is recognised no matter where it sits in an
|
|
36
|
+
* expression tree (a ternary branch, a template-literal interpolation, …),
|
|
37
|
+
* not only when it's the call the adapter's own top-level conversion
|
|
38
|
+
* entry point (`convertExpressionToJinja`) is asked to lower directly.
|
|
39
|
+
*/
|
|
40
|
+
readonly _loweringMatchers: readonly LoweringMatcher[]
|
|
41
|
+
|
|
31
42
|
/**
|
|
32
43
|
* Inline a module-scope pure string-literal const by name as the resolved
|
|
33
44
|
* literal value, or null when the name is not such a const.
|
|
@@ -51,6 +51,8 @@
|
|
|
51
51
|
import { groupBinaryOperand,
|
|
52
52
|
groupObjectLiteralSegments,
|
|
53
53
|
type ParsedExprEmitter,
|
|
54
|
+
type LoweringEmitter,
|
|
55
|
+
type LoweringNode,
|
|
54
56
|
type HigherOrderMethod,
|
|
55
57
|
type ArrayMethod,
|
|
56
58
|
type LiteralType,
|
|
@@ -61,6 +63,8 @@ import { groupBinaryOperand,
|
|
|
61
63
|
identifierPath,
|
|
62
64
|
matchSearchParamsMethodCall,
|
|
63
65
|
sortComparatorFromArrow,
|
|
66
|
+
queryHrefArgs,
|
|
67
|
+
isValidHelperId,
|
|
64
68
|
} from '@barefootjs/jsx'
|
|
65
69
|
|
|
66
70
|
import type { JinjaEmitContext } from '../emit-context.ts'
|
|
@@ -323,6 +327,45 @@ export class JinjaTopLevelEmitter 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 `JinjaAdapter.convertExpressionToJinja` 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. The helper includes a
|
|
344
|
+
// pair iff its guard is truthy AND its value is a non-empty string
|
|
345
|
+
// (the client's `if (value)`): a plain `key: v` passes guard
|
|
346
|
+
// `true`, a conditional `key: cond ? v : undefined` passes the
|
|
347
|
+
// lowered cond. Only the `query` helper renders to `bf.query`;
|
|
348
|
+
// another guard-list helper must not be silently mis-rendered as
|
|
349
|
+
// a query.
|
|
350
|
+
if (node.kind === 'guard-list' && node.helper === 'query') {
|
|
351
|
+
const qArgs = queryHrefArgs(node, emit)
|
|
352
|
+
return `bf.query(${qArgs.join(', ')})`
|
|
353
|
+
}
|
|
354
|
+
// Generic `helper-call` (#2069) — the neutral vocabulary's escape
|
|
355
|
+
// hatch for a userland `LoweringPlugin` that lowers to a single
|
|
356
|
+
// runtime-helper invocation. `bf.<helper>(args…)` mirrors the
|
|
357
|
+
// `query` helper's own naming convention exactly: the framework
|
|
358
|
+
// renders the call, the plugin author registers `<helper>` as a
|
|
359
|
+
// Jinja-callable function/filter in their own runtime — same
|
|
360
|
+
// contract as `bf.query` itself, just not built in.
|
|
361
|
+
if (node.kind === 'helper-call' && isValidHelperId(node.helper)) {
|
|
362
|
+
return `bf.${node.helper}(${node.args.map(emit).join(', ')})`
|
|
363
|
+
}
|
|
364
|
+
return null
|
|
365
|
+
},
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
326
369
|
identifier(name: string): string {
|
|
327
370
|
// `undefined` / `null` nested inside a larger expression tree — Jinja
|
|
328
371
|
// `none` (#1897).
|
|
@@ -138,8 +138,6 @@ import {
|
|
|
138
138
|
lookupStaticRecordLiteral,
|
|
139
139
|
searchParamsLocalNames,
|
|
140
140
|
prepareLoweringMatchers,
|
|
141
|
-
queryHrefArgs,
|
|
142
|
-
isValidHelperId,
|
|
143
141
|
sortComparatorFromArrow,
|
|
144
142
|
isDangerousInnerHtmlAttr,
|
|
145
143
|
resolveDangerousInnerHtml,
|
|
@@ -995,9 +993,12 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
995
993
|
// client's `mapArrayAnchored` can hydrate every SSR-rendered item by its
|
|
996
994
|
// anchor. Still under the row scope (see above) — `loop.key` is a
|
|
997
995
|
// per-row expression.
|
|
996
|
+
// `bf.escape_comment_key` (#2795 follow-up) both stringifies the key and
|
|
997
|
+
// neutralizes `-` so it can't spell `-->` and close the comment early —
|
|
998
|
+
// see its doc in `runtime.py`.
|
|
998
999
|
const bodyChildren =
|
|
999
1000
|
loop.bodyIsItemConditional && loop.key
|
|
1000
|
-
? `{{ bf.comment("loop-i:" ~ bf.
|
|
1001
|
+
? `{{ bf.comment("loop-i:" ~ bf.escape_comment_key(${this.convertExpressionToJinja(loop.key)})) | safe }}\n${childrenUnderLoop}`
|
|
1001
1002
|
: childrenUnderLoop
|
|
1002
1003
|
this.scope = prevScope
|
|
1003
1004
|
|
|
@@ -1430,8 +1431,13 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1430
1431
|
{
|
|
1431
1432
|
const m = this.parseUndefinedAlternateTernary(value.expr)
|
|
1432
1433
|
if (m) {
|
|
1433
|
-
|
|
1434
|
-
|
|
1434
|
+
// Pass the PARSED sub-trees through as `preParsed` (#2843 review)
|
|
1435
|
+
// rather than re-parsing `m.condition`/`m.consequent` — those are
|
|
1436
|
+
// `exprToString` debug text, which renders any nested
|
|
1437
|
+
// `object-literal` (e.g. a registered call's params, `queryHref`'s
|
|
1438
|
+
// `{ tag }`) as a non-reparseable `[UNSUPPORTED: …]` placeholder.
|
|
1439
|
+
const cond = this.convertConditionToJinja(m.condition, m.testParsed)
|
|
1440
|
+
const val = this.convertExpressionToJinja(m.consequent, m.consequentParsed)
|
|
1435
1441
|
return `\n{% if ${cond} %}\n${name}="{{ bf.string(${val}) }}"\n{% endif %}\n`
|
|
1436
1442
|
}
|
|
1437
1443
|
}
|
|
@@ -1693,7 +1699,7 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1693
1699
|
const hasTaggedTemplate = /[A-Za-z_$][\w$]*\s*`/.test(probe)
|
|
1694
1700
|
if (!startsAsObjectLiteral && !hasTaggedTemplate) return false
|
|
1695
1701
|
const parsed = parseExpression(expr.trim())
|
|
1696
|
-
const support = isSupported(parsed)
|
|
1702
|
+
const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers })
|
|
1697
1703
|
if (parsed.kind !== 'unsupported' && support.supported) return false
|
|
1698
1704
|
const reason = support.reason ?? (parsed.kind === 'unsupported' ? parsed.reason : undefined)
|
|
1699
1705
|
const reasonLine = reason ? `\n${reason}` : ''
|
|
@@ -1720,6 +1726,7 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1720
1726
|
private get emitCtx(): JinjaEmitContext {
|
|
1721
1727
|
return {
|
|
1722
1728
|
_searchParamsLocals: this._searchParamsLocals,
|
|
1729
|
+
_loweringMatchers: this._loweringMatchers,
|
|
1723
1730
|
_resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
|
|
1724
1731
|
_resolveLiteralConst: (name) => this._resolveLiteralConst(name),
|
|
1725
1732
|
_resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
|
|
@@ -1774,42 +1781,22 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1774
1781
|
parsed = parseExpression(trimmed)
|
|
1775
1782
|
}
|
|
1776
1783
|
|
|
1777
|
-
//
|
|
1778
|
-
// plugin
|
|
1779
|
-
//
|
|
1780
|
-
//
|
|
1781
|
-
//
|
|
1782
|
-
//
|
|
1783
|
-
//
|
|
1784
|
-
// `
|
|
1785
|
-
//
|
|
1786
|
-
//
|
|
1787
|
-
if (parsed.kind === 'call') {
|
|
1788
|
-
for (const matcher of this._loweringMatchers) {
|
|
1789
|
-
const node = matcher(parsed.callee, parsed.args)
|
|
1790
|
-
if (node?.kind === 'guard-list' && node.helper === 'query') {
|
|
1791
|
-
const qArgs = queryHrefArgs(node, n => this.renderParsedExprToJinja(n))
|
|
1792
|
-
return `bf.query(${qArgs.join(', ')})`
|
|
1793
|
-
}
|
|
1794
|
-
// Generic `helper-call` (#2069) — the neutral vocabulary's escape
|
|
1795
|
-
// hatch for a userland `LoweringPlugin` that lowers to a single
|
|
1796
|
-
// runtime-helper invocation. `bf.<helper>(args…)` mirrors the
|
|
1797
|
-
// `query` helper's own naming convention exactly: the framework
|
|
1798
|
-
// renders the call, the plugin author registers `<helper>` as a
|
|
1799
|
-
// Jinja-callable function/filter in their own runtime — same
|
|
1800
|
-
// contract as `bf.query` itself, just not built in.
|
|
1801
|
-
if (node?.kind === 'helper-call' && isValidHelperId(node.helper)) {
|
|
1802
|
-
const argsX = node.args.map(a => this.renderParsedExprToJinja(a))
|
|
1803
|
-
return `bf.${node.helper}(${argsX.join(', ')})`
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1784
|
+
// #2843: a registered lowering plugin's call (the built-in `queryHref`,
|
|
1785
|
+
// or any userland plugin) is recognised no matter where it sits in the
|
|
1786
|
+
// tree — a ternary branch, a template-literal interpolation, … — not
|
|
1787
|
+
// only when `parsed.kind === 'call'` directly. That recognition now
|
|
1788
|
+
// lives in `JinjaTopLevelEmitter`'s `lowering` seam, consulted by
|
|
1789
|
+
// `emitParsedExpr`'s shared `call` dispatch; the support gate below is
|
|
1790
|
+
// passed `this._loweringMatchers` so a matched call's params (e.g.
|
|
1791
|
+
// `queryHref`'s object literal, otherwise `unsupported` at `rendered`
|
|
1792
|
+
// position) are admitted wherever the call is nested.
|
|
1793
|
+
//
|
|
1808
1794
|
// `pos` distinguishes a derived-seed RHS (an assignment, checked via
|
|
1809
1795
|
// `isSupportedValue`) from every other, genuinely rendered call site —
|
|
1810
1796
|
// the rendered gate would otherwise re-refuse a tree the seed plan
|
|
1811
1797
|
// already classified `derived` at value position (#2696 review).
|
|
1812
|
-
const
|
|
1798
|
+
const supportOpts = { loweringMatchers: this._loweringMatchers }
|
|
1799
|
+
const support = pos === 'value' ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts)
|
|
1813
1800
|
if (!support.supported) {
|
|
1814
1801
|
this.errors.push({
|
|
1815
1802
|
code: 'BF101',
|
|
@@ -1875,10 +1862,21 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1875
1862
|
* Parse `cond ? value : undefined` (or `: null`), returning the
|
|
1876
1863
|
* condition/consequent source spans, else `null`. Used for the
|
|
1877
1864
|
* attribute-omission rule (#1897).
|
|
1865
|
+
*
|
|
1866
|
+
* `testParsed`/`consequentParsed` (#2843 review) are the ACTUAL parsed
|
|
1867
|
+
* sub-trees, for the caller to pass through as `preParsed` — `condition`/
|
|
1868
|
+
* `consequent` are `exprToString` output, a DEBUG formatter that renders
|
|
1869
|
+
* any nested `object-literal` as the non-reparseable `[UNSUPPORTED: …]`
|
|
1870
|
+
* placeholder (unlike `stringifyParsedExpr`, meant for round-tripping).
|
|
1871
|
+
* Re-parsing THAT string for a consequent like `queryHref(base, { tag })`
|
|
1872
|
+
* would corrupt the call's args before the lowering registry — now
|
|
1873
|
+
* consulted at any nesting depth (#2843) — ever sees them. Kept for any
|
|
1874
|
+
* caller that only needs the string form; the parsed trees are the
|
|
1875
|
+
* correct input wherever the caller can accept `preParsed`.
|
|
1878
1876
|
*/
|
|
1879
1877
|
parseUndefinedAlternateTernary(
|
|
1880
1878
|
expr: string,
|
|
1881
|
-
): { condition: string; consequent: string } | null {
|
|
1879
|
+
): { condition: string; consequent: string; testParsed: ParsedExpr; consequentParsed: ParsedExpr } | null {
|
|
1882
1880
|
const parsed = parseExpression(expr.trim())
|
|
1883
1881
|
if (parsed?.kind !== 'conditional') return null
|
|
1884
1882
|
const alt = parsed.alternate
|
|
@@ -1893,6 +1891,8 @@ export class JinjaAdapter extends BaseAdapter implements IRNodeEmitter<JinjaRend
|
|
|
1893
1891
|
return {
|
|
1894
1892
|
condition: exprToString(parsed.test),
|
|
1895
1893
|
consequent: exprToString(parsed.consequent),
|
|
1894
|
+
testParsed: parsed.test,
|
|
1895
|
+
consequentParsed: parsed.consequent,
|
|
1896
1896
|
}
|
|
1897
1897
|
}
|
|
1898
1898
|
|
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
|
+
// `JinjaTopLevelEmitter`'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`) SSRs an empty `<ul>` on real Jinja2 — 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
|
@@ -613,6 +613,26 @@ function buildPythonProps(
|
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
+
// #2813: `extractSsrDefaults` can seed an entry under a name that is
|
|
617
|
+
// none of `propsParams` / `signals` / `memos` above — a bare local-const
|
|
618
|
+
// alias of a signal/memo getter (`const items__alias = items`,
|
|
619
|
+
// `ssr-defaults.ts`) seeds `items__alias` alongside `items`. Production
|
|
620
|
+
// hands the whole manifest-derived stash straight through
|
|
621
|
+
// (`deriveStashFromDefaults` IS the production seeding mechanism here,
|
|
622
|
+
// not a harness stand-in), so any leftover `derivedProps` key must be
|
|
623
|
+
// pushed too, or this harness would silently omit what production
|
|
624
|
+
// actually provides, mismeasuring this conformance case.
|
|
625
|
+
const seededNames = new Set<string>([
|
|
626
|
+
...ir.metadata.propsParams.filter(p => !p.isRest).map(p => p.name),
|
|
627
|
+
...(restPropsName ? [restPropsName] : []),
|
|
628
|
+
...ir.metadata.signals.filter(s => !s.envReader).map(s => s.getter),
|
|
629
|
+
...ir.metadata.memos.map(m => m.name),
|
|
630
|
+
])
|
|
631
|
+
for (const [name, value] of Object.entries(derivedProps)) {
|
|
632
|
+
if (seededNames.has(name)) continue
|
|
633
|
+
fullEntries.push(`${pyStr(name)}: ${toPyLiteral(value)}`)
|
|
634
|
+
}
|
|
635
|
+
|
|
616
636
|
// (#1922) Request-scoped `searchParams()`: bind `searchParams` to an
|
|
617
637
|
// empty-query reader (so the render script needn't build one from a real
|
|
618
638
|
// request). The conformance harness issues no query string (the
|