@barefootjs/xslate 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.
@@ -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 XslateEmitContext {
22
22
  /**
23
23
  * (#1922) Local binding names the request-scoped `searchParams()` env signal
24
24
  * is imported under. Non-empty enables the env-signal method-call lowering.
25
25
  */
26
26
  readonly _searchParamsLocals: Set<string>;
27
+ /**
28
+ * Registered lowering-plugin matchers (#2057), bound to this component's
29
+ * metadata at init. Read by `XslateTopLevelEmitter`'s `lowering` seam
30
+ * (#2843) so a registered call — the built-in `queryHref`, or any
31
+ * userland plugin — is recognised no matter where it sits in an
32
+ * expression tree (a ternary branch, a template-literal interpolation, …),
33
+ * not only when it's the call the adapter's own top-level conversion
34
+ * entry point (`convertExpressionToKolon`) 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;AAE5E,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAEzC;;;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,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,yEAAyE;IACzE,4BAA4B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACtE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,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,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACvE;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;OAYG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;CACnG"}
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,iBAAiB;IAChC;;;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,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,yEAAyE;IACzE,4BAA4B,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACtE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,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,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,GAAG,MAAM,CAAA;CACvE;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;OAYG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAA;CACnG"}
@@ -10,7 +10,7 @@
10
10
  * - `XslateTopLevelEmitter` — top-level / per-render-var context; depends on
11
11
  * the adapter only through the narrow `XslateEmitContext` seam.
12
12
  */
13
- import { type ParsedExprEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
13
+ import { type ParsedExprEmitter, type LoweringEmitter, type ArrayMethod, type LiteralType, type ParsedExpr, type ObjectLiteralProperty, type FlatDepth, type TemplatePart } from '@barefootjs/jsx';
14
14
  import type { XslateEmitContext } from '../emit-context.ts';
15
15
  /**
16
16
  * Lowering for the predicate body of a filter / every / some / find, plus the
@@ -63,6 +63,16 @@ export declare class XslateFilterEmitter implements ParsedExprEmitter {
63
63
  export declare class XslateTopLevelEmitter implements ParsedExprEmitter {
64
64
  private readonly ctx;
65
65
  constructor(ctx: XslateEmitContext);
66
+ /**
67
+ * Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
68
+ * tries every matcher here BEFORE `call()` itself, so a registered call
69
+ * (the built-in `queryHref`, or any userland plugin) is recognised no
70
+ * matter where it sits in the tree. `render` is what used to live inline
71
+ * in `XslateAdapter.convertExpressionToKolon` before the object-literal
72
+ * support-gate refusal (`checkSupport`'s `call` arm, now itself
73
+ * registry-aware) made the pre-gate special case unnecessary.
74
+ */
75
+ get lowering(): LoweringEmitter;
66
76
  identifier(name: string): string;
67
77
  literal(value: string | number | boolean | null, literalType: LiteralType): string;
68
78
  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":"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"}
1
+ {"version":3,"file":"emitters.d.ts","sourceRoot":"","sources":["../../../src/adapter/expr/emitters.ts"],"names":[],"mappings":"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"}
@@ -187306,8 +187306,6 @@ import {
187306
187306
  lookupStaticRecordLiteral,
187307
187307
  searchParamsLocalNames,
187308
187308
  prepareLoweringMatchers,
187309
- queryHrefArgs,
187310
- isValidHelperId,
187311
187309
  sortComparatorFromArrow as sortComparatorFromArrow2,
187312
187310
  isLowerableLoopDestructure,
187313
187311
  isDangerousInnerHtmlAttr,
@@ -187640,7 +187638,9 @@ import {
187640
187638
  isStringConcatBinary,
187641
187639
  identifierPath,
187642
187640
  matchSearchParamsMethodCall,
187643
- sortComparatorFromArrow
187641
+ sortComparatorFromArrow,
187642
+ queryHrefArgs,
187643
+ isValidHelperId
187644
187644
  } from "@barefootjs/jsx";
187645
187645
  var PREDICATE_METHODS = new Set([
187646
187646
  "filter",
@@ -187772,6 +187772,21 @@ class XslateTopLevelEmitter {
187772
187772
  constructor(ctx) {
187773
187773
  this.ctx = ctx;
187774
187774
  }
187775
+ get lowering() {
187776
+ return {
187777
+ matchers: this.ctx._loweringMatchers,
187778
+ render: (node, emit) => {
187779
+ if (node.kind === "guard-list" && node.helper === "query") {
187780
+ const qArgs = queryHrefArgs(node, emit);
187781
+ return `$bf.query(${qArgs.join(", ")})`;
187782
+ }
187783
+ if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
187784
+ return `$bf.${node.helper}(${node.args.map(emit).join(", ")})`;
187785
+ }
187786
+ return null;
187787
+ }
187788
+ };
187789
+ }
187775
187790
  identifier(name) {
187776
187791
  if (name === "undefined" || name === "null")
187777
187792
  return "nil";
@@ -188628,7 +188643,7 @@ ${whenTrue}
188628
188643
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`);
188629
188644
  const childrenUnderLoop = this.renderChildren(loop.children);
188630
188645
  this.inLoop = prevInLoop;
188631
- const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
188646
+ const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ $bf.escape_comment_key(${this.convertExpressionToKolon(loop.key)})) | mark_raw :>
188632
188647
  ${childrenUnderLoop}` : childrenUnderLoop;
188633
188648
  this.scope = prevScope;
188634
188649
  const lines = [];
@@ -188831,8 +188846,8 @@ ${body}
188831
188846
  {
188832
188847
  const m = this.parseUndefinedAlternateTernary(value.expr);
188833
188848
  if (m) {
188834
- const cond = this.convertExpressionToKolon(m.condition);
188835
- const val = this.convertExpressionToKolon(m.consequent);
188849
+ const cond = this.convertExpressionToKolon("", m.testParsed);
188850
+ const val = this.convertExpressionToKolon("", m.consequentParsed);
188836
188851
  return `
188837
188852
  : if (${cond}) {
188838
188853
  ${name}="<: ${val} :>"
@@ -188965,7 +188980,7 @@ ${name}="<: ${val} :>"
188965
188980
  if (!startsAsObjectLiteral && !hasTaggedTemplate)
188966
188981
  return false;
188967
188982
  const parsed = parseExpression2(expr.trim());
188968
- const support = isSupported(parsed);
188983
+ const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
188969
188984
  if (parsed.kind !== "unsupported" && support.supported)
188970
188985
  return false;
188971
188986
  const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
@@ -188985,6 +189000,7 @@ ${reason}` : "";
188985
189000
  get emitCtx() {
188986
189001
  return {
188987
189002
  _searchParamsLocals: this._searchParamsLocals,
189003
+ _loweringMatchers: this._loweringMatchers,
188988
189004
  _resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
188989
189005
  _resolveLiteralConst: (name) => this._resolveLiteralConst(name),
188990
189006
  _resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
@@ -189015,20 +189031,8 @@ ${reason}` : "";
189015
189031
  return "''";
189016
189032
  parsed = parseExpression2(trimmed);
189017
189033
  }
189018
- if (parsed.kind === "call") {
189019
- for (const matcher of this._loweringMatchers) {
189020
- const node = matcher(parsed.callee, parsed.args);
189021
- if (node?.kind === "guard-list" && node.helper === "query") {
189022
- const qArgs = queryHrefArgs(node, (n) => this.renderParsedExprToKolon(n));
189023
- return `$bf.query(${qArgs.join(", ")})`;
189024
- }
189025
- if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
189026
- const argsX = node.args.map((a) => this.renderParsedExprToKolon(a));
189027
- return `$bf.${node.helper}(${argsX.join(", ")})`;
189028
- }
189029
- }
189030
- }
189031
- const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
189034
+ const supportOpts = { loweringMatchers: this._loweringMatchers };
189035
+ const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
189032
189036
  if (!support.supported) {
189033
189037
  this.errors.push({
189034
189038
  code: "BF101",
@@ -189065,7 +189069,9 @@ Options:
189065
189069
  return null;
189066
189070
  return {
189067
189071
  condition: exprToString(parsed.test),
189068
- consequent: exprToString(parsed.consequent)
189072
+ consequent: exprToString(parsed.consequent),
189073
+ testParsed: parsed.test,
189074
+ consequentParsed: parsed.consequent
189069
189075
  };
189070
189076
  }
189071
189077
  isBooleanTypedPropRef(expr) {
@@ -21,6 +21,7 @@
21
21
  */
22
22
  import type { ComponentIR, IRNode, IRElement, IRText, IRExpression, IRConditional, IRLoop, IRComponent, IRFragment, IRSlot, IRIfStatement, IRProvider, IRAsync, TemplatePrimitiveRegistry } from '@barefootjs/jsx';
23
23
  import { BaseAdapter, type AdapterOutput, type AdapterGenerateOptions, type IRNodeEmitter, type EmitIRNode } from '@barefootjs/jsx';
24
+ import type { ParsedExpr } from '@barefootjs/jsx';
24
25
  import type { XslateRenderCtx } from './lib/types.ts';
25
26
  export type { XslateAdapterOptions } from './lib/types.ts';
26
27
  import type { XslateAdapterOptions } from './lib/types.ts';
@@ -332,6 +333,8 @@ export declare class XslateAdapter extends BaseAdapter implements IRNodeEmitter<
332
333
  parseUndefinedAlternateTernary(expr: string): {
333
334
  condition: string;
334
335
  consequent: string;
336
+ testParsed: ParsedExpr;
337
+ consequentParsed: ParsedExpr;
335
338
  } | null;
336
339
  isBooleanTypedPropRef(expr: string): boolean;
337
340
  /** Position-accurate loop-bound-name check — see `this.scope`'s docstring. */
@@ -1 +1 @@
1
- {"version":3,"file":"xslate-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/xslate-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"xslate-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/xslate-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,eA6D7B,CAAA"}
1
+ {"version":3,"file":"conformance-pins.d.ts","sourceRoot":"","sources":["../src/conformance-pins.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,eAAO,MAAM,eAAe,EAAE,eAiE7B,CAAA"}
package/dist/index.js CHANGED
@@ -187306,8 +187306,6 @@ import {
187306
187306
  lookupStaticRecordLiteral,
187307
187307
  searchParamsLocalNames,
187308
187308
  prepareLoweringMatchers,
187309
- queryHrefArgs,
187310
- isValidHelperId,
187311
187309
  sortComparatorFromArrow as sortComparatorFromArrow2,
187312
187310
  isLowerableLoopDestructure,
187313
187311
  isDangerousInnerHtmlAttr,
@@ -187640,7 +187638,9 @@ import {
187640
187638
  isStringConcatBinary,
187641
187639
  identifierPath,
187642
187640
  matchSearchParamsMethodCall,
187643
- sortComparatorFromArrow
187641
+ sortComparatorFromArrow,
187642
+ queryHrefArgs,
187643
+ isValidHelperId
187644
187644
  } from "@barefootjs/jsx";
187645
187645
  var PREDICATE_METHODS = new Set([
187646
187646
  "filter",
@@ -187772,6 +187772,21 @@ class XslateTopLevelEmitter {
187772
187772
  constructor(ctx) {
187773
187773
  this.ctx = ctx;
187774
187774
  }
187775
+ get lowering() {
187776
+ return {
187777
+ matchers: this.ctx._loweringMatchers,
187778
+ render: (node, emit) => {
187779
+ if (node.kind === "guard-list" && node.helper === "query") {
187780
+ const qArgs = queryHrefArgs(node, emit);
187781
+ return `$bf.query(${qArgs.join(", ")})`;
187782
+ }
187783
+ if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
187784
+ return `$bf.${node.helper}(${node.args.map(emit).join(", ")})`;
187785
+ }
187786
+ return null;
187787
+ }
187788
+ };
187789
+ }
187775
187790
  identifier(name) {
187776
187791
  if (name === "undefined" || name === "null")
187777
187792
  return "nil";
@@ -188628,7 +188643,7 @@ ${whenTrue}
188628
188643
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`);
188629
188644
  const childrenUnderLoop = this.renderChildren(loop.children);
188630
188645
  this.inLoop = prevInLoop;
188631
- const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
188646
+ const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ $bf.escape_comment_key(${this.convertExpressionToKolon(loop.key)})) | mark_raw :>
188632
188647
  ${childrenUnderLoop}` : childrenUnderLoop;
188633
188648
  this.scope = prevScope;
188634
188649
  const lines = [];
@@ -188831,8 +188846,8 @@ ${body}
188831
188846
  {
188832
188847
  const m = this.parseUndefinedAlternateTernary(value.expr);
188833
188848
  if (m) {
188834
- const cond = this.convertExpressionToKolon(m.condition);
188835
- const val = this.convertExpressionToKolon(m.consequent);
188849
+ const cond = this.convertExpressionToKolon("", m.testParsed);
188850
+ const val = this.convertExpressionToKolon("", m.consequentParsed);
188836
188851
  return `
188837
188852
  : if (${cond}) {
188838
188853
  ${name}="<: ${val} :>"
@@ -188965,7 +188980,7 @@ ${name}="<: ${val} :>"
188965
188980
  if (!startsAsObjectLiteral && !hasTaggedTemplate)
188966
188981
  return false;
188967
188982
  const parsed = parseExpression2(expr.trim());
188968
- const support = isSupported(parsed);
188983
+ const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
188969
188984
  if (parsed.kind !== "unsupported" && support.supported)
188970
188985
  return false;
188971
188986
  const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
@@ -188985,6 +189000,7 @@ ${reason}` : "";
188985
189000
  get emitCtx() {
188986
189001
  return {
188987
189002
  _searchParamsLocals: this._searchParamsLocals,
189003
+ _loweringMatchers: this._loweringMatchers,
188988
189004
  _resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
188989
189005
  _resolveLiteralConst: (name) => this._resolveLiteralConst(name),
188990
189006
  _resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
@@ -189015,20 +189031,8 @@ ${reason}` : "";
189015
189031
  return "''";
189016
189032
  parsed = parseExpression2(trimmed);
189017
189033
  }
189018
- if (parsed.kind === "call") {
189019
- for (const matcher of this._loweringMatchers) {
189020
- const node = matcher(parsed.callee, parsed.args);
189021
- if (node?.kind === "guard-list" && node.helper === "query") {
189022
- const qArgs = queryHrefArgs(node, (n) => this.renderParsedExprToKolon(n));
189023
- return `$bf.query(${qArgs.join(", ")})`;
189024
- }
189025
- if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
189026
- const argsX = node.args.map((a) => this.renderParsedExprToKolon(a));
189027
- return `$bf.${node.helper}(${argsX.join(", ")})`;
189028
- }
189029
- }
189030
- }
189031
- const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
189034
+ const supportOpts = { loweringMatchers: this._loweringMatchers };
189035
+ const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
189032
189036
  if (!support.supported) {
189033
189037
  this.errors.push({
189034
189038
  code: "BF101",
@@ -189065,7 +189069,9 @@ Options:
189065
189069
  return null;
189066
189070
  return {
189067
189071
  condition: exprToString(parsed.test),
189068
- consequent: exprToString(parsed.consequent)
189072
+ consequent: exprToString(parsed.consequent),
189073
+ testParsed: parsed.test,
189074
+ consequentParsed: parsed.consequent
189069
189075
  };
189070
189076
  }
189071
189077
  isBooleanTypedPropRef(expr) {
@@ -189171,9 +189177,7 @@ var conformancePins = {
189171
189177
  "namespace-import-primitive": [{ code: "BF013", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2771" }]
189172
189178
  };
189173
189179
  // src/render-divergences.ts
189174
- var renderDivergences = {
189175
- "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 Text::Xslate — 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."
189176
- };
189180
+ var renderDivergences = {};
189177
189181
  export {
189178
189182
  xslateAdapter,
189179
189183
  renderDivergences,
@@ -1 +1 @@
1
- {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAexD,eAAO,MAAM,iBAAiB,EAAE,iBAG/B,CAAA"}
1
+ {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAexD,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",
@@ -4684,6 +4714,17 @@ function emitParsedExpr(expr, emitter) {
4684
4714
  case "literal":
4685
4715
  return emitter.literal(expr.value, expr.literalType);
4686
4716
  case "call": {
4717
+ if (emitter.lowering) {
4718
+ for (const matcher of emitter.lowering.matchers) {
4719
+ const node = matcher(expr.callee, expr.args);
4720
+ if (!node)
4721
+ continue;
4722
+ const rendered = emitter.lowering.render(node, emit);
4723
+ if (rendered !== null)
4724
+ return rendered;
4725
+ break;
4726
+ }
4727
+ }
4687
4728
  const cb = asCallbackMethodCall(expr);
4688
4729
  if (cb)
4689
4730
  return emitter.callbackMethod(cb.method, cb.object, cb.arrow, cb.args, emit);
@@ -5709,6 +5750,21 @@ class XslateTopLevelEmitter {
5709
5750
  constructor(ctx) {
5710
5751
  this.ctx = ctx;
5711
5752
  }
5753
+ get lowering() {
5754
+ return {
5755
+ matchers: this.ctx._loweringMatchers,
5756
+ render: (node, emit) => {
5757
+ if (node.kind === "guard-list" && node.helper === "query") {
5758
+ const qArgs = queryHrefArgs(node, emit);
5759
+ return `$bf.query(${qArgs.join(", ")})`;
5760
+ }
5761
+ if (node.kind === "helper-call" && isValidHelperId(node.helper)) {
5762
+ return `$bf.${node.helper}(${node.args.map(emit).join(", ")})`;
5763
+ }
5764
+ return null;
5765
+ }
5766
+ };
5767
+ }
5712
5768
  identifier(name) {
5713
5769
  if (name === "undefined" || name === "null")
5714
5770
  return "nil";
@@ -6556,7 +6612,7 @@ ${whenTrue}
6556
6612
  const preambleLines = (loop.preamble?.declarations ?? []).map((d) => `: my $${d.name} = ${this.convertExpressionToKolon(d.raw, d.valueParsed)};`);
6557
6613
  const childrenUnderLoop = this.renderChildren(loop.children);
6558
6614
  this.inLoop = prevInLoop;
6559
- const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>
6615
+ const bodyChildren = loop.bodyIsItemConditional && loop.key ? `<: $bf.comment("loop-i:" ~ $bf.escape_comment_key(${this.convertExpressionToKolon(loop.key)})) | mark_raw :>
6560
6616
  ${childrenUnderLoop}` : childrenUnderLoop;
6561
6617
  this.scope = prevScope;
6562
6618
  const lines = [];
@@ -6759,8 +6815,8 @@ ${body}
6759
6815
  {
6760
6816
  const m = this.parseUndefinedAlternateTernary(value.expr);
6761
6817
  if (m) {
6762
- const cond = this.convertExpressionToKolon(m.condition);
6763
- const val = this.convertExpressionToKolon(m.consequent);
6818
+ const cond = this.convertExpressionToKolon("", m.testParsed);
6819
+ const val = this.convertExpressionToKolon("", m.consequentParsed);
6764
6820
  return `
6765
6821
  : if (${cond}) {
6766
6822
  ${name}="<: ${val} :>"
@@ -6893,7 +6949,7 @@ ${name}="<: ${val} :>"
6893
6949
  if (!startsAsObjectLiteral && !hasTaggedTemplate)
6894
6950
  return false;
6895
6951
  const parsed = parseExpression(expr.trim());
6896
- const support = isSupported(parsed);
6952
+ const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers });
6897
6953
  if (parsed.kind !== "unsupported" && support.supported)
6898
6954
  return false;
6899
6955
  const reason = support.reason ?? (parsed.kind === "unsupported" ? parsed.reason : undefined);
@@ -6913,6 +6969,7 @@ ${reason}` : "";
6913
6969
  get emitCtx() {
6914
6970
  return {
6915
6971
  _searchParamsLocals: this._searchParamsLocals,
6972
+ _loweringMatchers: this._loweringMatchers,
6916
6973
  _resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
6917
6974
  _resolveLiteralConst: (name) => this._resolveLiteralConst(name),
6918
6975
  _resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
@@ -6943,20 +7000,8 @@ ${reason}` : "";
6943
7000
  return "''";
6944
7001
  parsed = parseExpression(trimmed);
6945
7002
  }
6946
- if (parsed.kind === "call") {
6947
- for (const matcher of this._loweringMatchers) {
6948
- const node = matcher(parsed.callee, parsed.args);
6949
- if (node?.kind === "guard-list" && node.helper === "query") {
6950
- const qArgs = queryHrefArgs(node, (n) => this.renderParsedExprToKolon(n));
6951
- return `$bf.query(${qArgs.join(", ")})`;
6952
- }
6953
- if (node?.kind === "helper-call" && isValidHelperId(node.helper)) {
6954
- const argsX = node.args.map((a) => this.renderParsedExprToKolon(a));
6955
- return `$bf.${node.helper}(${argsX.join(", ")})`;
6956
- }
6957
- }
6958
- }
6959
- const support = pos === "value" ? isSupportedValue(parsed) : isSupported(parsed);
7003
+ const supportOpts = { loweringMatchers: this._loweringMatchers };
7004
+ const support = pos === "value" ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts);
6960
7005
  if (!support.supported) {
6961
7006
  this.errors.push({
6962
7007
  code: "BF101",
@@ -6993,7 +7038,9 @@ Options:
6993
7038
  return null;
6994
7039
  return {
6995
7040
  condition: exprToString(parsed.test),
6996
- consequent: exprToString(parsed.consequent)
7041
+ consequent: exprToString(parsed.consequent),
7042
+ testParsed: parsed.test,
7043
+ consequentParsed: parsed.consequent
6997
7044
  };
6998
7045
  }
6999
7046
  isBooleanTypedPropRef(expr) {
@@ -1,5 +1,5 @@
1
1
  package BarefootJS::Backend::Xslate;
2
- our $VERSION = "0.33.4";
2
+ our $VERSION = "0.34.0";
3
3
  use strict;
4
4
  use warnings;
5
5
  use utf8;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/xslate",
3
- "version": "0.33.6",
3
+ "version": "0.35.0",
4
4
  "description": "Text::Xslate (Kolon) adapter for BarefootJS — compiles IR to .tx templates and ships the Xslate rendering backend; runs under any PSGI/Plack app",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,7 +55,7 @@
55
55
  "directory": "packages/adapter-xslate"
56
56
  },
57
57
  "dependencies": {
58
- "@barefootjs/shared": "0.33.6"
58
+ "@barefootjs/shared": "0.35.0"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@barefootjs/jsx": ">=0.2.0",
@@ -72,9 +72,9 @@
72
72
  },
73
73
  "devDependencies": {
74
74
  "@barefootjs/adapter-tests": "0.1.0",
75
- "@barefootjs/jsx": "0.33.6",
76
- "@barefootjs/vite": "0.33.6",
77
- "@barefootjs/client": "0.33.6",
75
+ "@barefootjs/jsx": "0.35.0",
76
+ "@barefootjs/vite": "0.35.0",
77
+ "@barefootjs/client": "0.35.0",
78
78
  "typescript": "^5.0.0",
79
79
  "vite": "^6.0.0"
80
80
  }
@@ -595,8 +595,8 @@ function Widget({ values }: { values: number[] }) {
595
595
  return <ul>{values.map((label) => (label > 0 ? <li key={label}>{label}</li> : null))}</ul>
596
596
  }
597
597
  `)
598
- expect(template).toContain('$bf.comment("loop-i:" ~ $label)')
599
- expect(template).not.toContain('$bf.comment("loop-i:" ~ \'x\')')
598
+ expect(template).toContain('$bf.comment("loop-i:" ~ $bf.escape_comment_key($label))')
599
+ expect(template).not.toContain('$bf.comment("loop-i:" ~ $bf.escape_comment_key(\'x\'))')
600
600
  })
601
601
 
602
602
  test('a loop param shadowing an outer const resolves to the row value inside a .map() preamble local initializer', () => {
@@ -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 XslateEmitContext {
24
24
  /**
@@ -27,6 +27,17 @@ export interface XslateEmitContext {
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 `XslateTopLevelEmitter`'s `lowering` seam
33
+ * (#2843) so a registered call — the built-in `queryHref`, or any
34
+ * userland plugin — is recognised no matter where it sits in an
35
+ * expression tree (a ternary branch, a template-literal interpolation, …),
36
+ * not only when it's the call the adapter's own top-level conversion
37
+ * entry point (`convertExpressionToKolon`) 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.
@@ -15,6 +15,8 @@ import { groupBinaryOperand,
15
15
  groupObjectLiteralSegments,
16
16
  isStringConcatBinary,
17
17
  type ParsedExprEmitter,
18
+ type LoweringEmitter,
19
+ type LoweringNode,
18
20
  type HigherOrderMethod,
19
21
  type ArrayMethod,
20
22
  type LiteralType,
@@ -25,6 +27,8 @@ import { groupBinaryOperand,
25
27
  identifierPath,
26
28
  matchSearchParamsMethodCall,
27
29
  sortComparatorFromArrow,
30
+ queryHrefArgs,
31
+ isValidHelperId,
28
32
  } from '@barefootjs/jsx'
29
33
 
30
34
  import type { XslateEmitContext } from '../emit-context.ts'
@@ -267,6 +271,35 @@ export class XslateTopLevelEmitter implements ParsedExprEmitter {
267
271
  this.ctx = ctx
268
272
  }
269
273
 
274
+ /**
275
+ * Registered-lowering seam (#2843): `emitParsedExpr`'s shared `call` case
276
+ * tries every matcher here BEFORE `call()` itself, so a registered call
277
+ * (the built-in `queryHref`, or any userland plugin) is recognised no
278
+ * matter where it sits in the tree. `render` is what used to live inline
279
+ * in `XslateAdapter.convertExpressionToKolon` before the object-literal
280
+ * support-gate refusal (`checkSupport`'s `call` arm, now itself
281
+ * registry-aware) made the pre-gate special case unnecessary.
282
+ */
283
+ get lowering(): LoweringEmitter {
284
+ return {
285
+ matchers: this.ctx._loweringMatchers,
286
+ render: (node: LoweringNode, emit: (e: ParsedExpr) => string): string | null => {
287
+ // `query` guard-list — `queryHref`-shaped.
288
+ if (node.kind === 'guard-list' && node.helper === 'query') {
289
+ const qArgs = queryHrefArgs(node, emit)
290
+ return `$bf.query(${qArgs.join(', ')})`
291
+ }
292
+ // Generic `helper-call` (#2069) — a userland `LoweringPlugin`'s
293
+ // single runtime-helper invocation; `$bf.<helper>(args…)` mirrors
294
+ // the `query` helper's own naming convention.
295
+ if (node.kind === 'helper-call' && isValidHelperId(node.helper)) {
296
+ return `$bf.${node.helper}(${node.args.map(emit).join(', ')})`
297
+ }
298
+ return null
299
+ },
300
+ }
301
+ }
302
+
270
303
  identifier(name: string): string {
271
304
  // `undefined` / `null` nested inside a larger expression tree —
272
305
  // Kolon `nil` (#1897).
@@ -70,8 +70,6 @@ import {
70
70
  lookupStaticRecordLiteral,
71
71
  searchParamsLocalNames,
72
72
  prepareLoweringMatchers,
73
- queryHrefArgs,
74
- isValidHelperId,
75
73
  sortComparatorFromArrow,
76
74
  isLowerableLoopDestructure,
77
75
  isDangerousInnerHtmlAttr,
@@ -981,9 +979,13 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
981
979
  // client's `mapArrayAnchored` can hydrate every SSR-rendered item by its
982
980
  // anchor. Still under the row scope (see above) — `loop.key` is a
983
981
  // per-row expression.
982
+ // `$bf.escape_comment_key` (#2795 follow-up) both stringifies the key
983
+ // (JS `String()` semantics, matching the other adapters) and neutralizes
984
+ // `-` so it can't spell `-->` and close the comment early — see its doc
985
+ // in `BarefootJS.pm`.
984
986
  const bodyChildren =
985
987
  loop.bodyIsItemConditional && loop.key
986
- ? `<: $bf.comment("loop-i:" ~ ${this.convertExpressionToKolon(loop.key)}) | mark_raw :>\n${childrenUnderLoop}`
988
+ ? `<: $bf.comment("loop-i:" ~ $bf.escape_comment_key(${this.convertExpressionToKolon(loop.key)})) | mark_raw :>\n${childrenUnderLoop}`
987
989
  : childrenUnderLoop
988
990
  this.scope = prevScope
989
991
 
@@ -1403,8 +1405,13 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1403
1405
  {
1404
1406
  const m = this.parseUndefinedAlternateTernary(value.expr)
1405
1407
  if (m) {
1406
- const cond = this.convertExpressionToKolon(m.condition)
1407
- const val = this.convertExpressionToKolon(m.consequent)
1408
+ // Pass the PARSED sub-trees through as `preParsed` (#2843 review)
1409
+ // rather than re-parsing `m.condition`/`m.consequent` — those are
1410
+ // `exprToString` debug text, which renders any nested
1411
+ // `object-literal` (e.g. a registered call's params, `queryHref`'s
1412
+ // `{ tag }`) as a non-reparseable `[UNSUPPORTED: …]` placeholder.
1413
+ const cond = this.convertExpressionToKolon('', m.testParsed)
1414
+ const val = this.convertExpressionToKolon('', m.consequentParsed)
1408
1415
  return `\n: if (${cond}) {\n${name}="<: ${val} :>"\n: }\n`
1409
1416
  }
1410
1417
  }
@@ -1659,7 +1666,7 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1659
1666
  const hasTaggedTemplate = /[A-Za-z_$][\w$]*\s*`/.test(probe)
1660
1667
  if (!startsAsObjectLiteral && !hasTaggedTemplate) return false
1661
1668
  const parsed = parseExpression(expr.trim())
1662
- const support = isSupported(parsed)
1669
+ const support = isSupported(parsed, { loweringMatchers: this._loweringMatchers })
1663
1670
  if (parsed.kind !== 'unsupported' && support.supported) return false
1664
1671
  const reason = support.reason ?? (parsed.kind === 'unsupported' ? parsed.reason : undefined)
1665
1672
  const reasonLine = reason ? `\n${reason}` : ''
@@ -1686,6 +1693,7 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1686
1693
  private get emitCtx(): XslateEmitContext {
1687
1694
  return {
1688
1695
  _searchParamsLocals: this._searchParamsLocals,
1696
+ _loweringMatchers: this._loweringMatchers,
1689
1697
  _resolveModuleStringConst: (name) => this._resolveModuleStringConst(name),
1690
1698
  _resolveLiteralConst: (name) => this._resolveLiteralConst(name),
1691
1699
  _resolveStaticRecordLiteral: (o, k) => this._resolveStaticRecordLiteral(o, k),
@@ -1737,42 +1745,22 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1737
1745
  parsed = parseExpression(trimmed)
1738
1746
  }
1739
1747
 
1740
- // Registered call lowerings (#2057) including the built-in `queryHref`
1741
- // plugin (#2042), which lowers `queryHref(base, { })` to a neutral
1742
- // `guard-list` on the `query` helper `$bf.query(base, <triples>)`.
1743
- // Recognised before the support gate because the object-literal arg is
1744
- // otherwise `unsupported` (BF101). The `query` helper includes a pair iff its
1745
- // guard is truthy AND its value is a non-empty string (the client's
1746
- // `if (value)`): a plain `key: v` passes guard `1`, a conditional
1747
- // `key: cond ? v : undefined` passes the lowered cond. Only the `query`
1748
- // helper renders to `$bf.query`; another guard-list helper must not be
1749
- // silently mis-rendered as a query.
1750
- if (parsed.kind === 'call') {
1751
- for (const matcher of this._loweringMatchers) {
1752
- const node = matcher(parsed.callee, parsed.args)
1753
- if (node?.kind === 'guard-list' && node.helper === 'query') {
1754
- const qArgs = queryHrefArgs(node, n => this.renderParsedExprToKolon(n))
1755
- return `$bf.query(${qArgs.join(', ')})`
1756
- }
1757
- // Generic `helper-call` (#2069) — the neutral vocabulary's escape
1758
- // hatch for a userland `LoweringPlugin` that lowers to a single
1759
- // runtime-helper invocation. `$bf.<helper>(args…)` mirrors the
1760
- // `query` helper's own naming convention exactly: the framework
1761
- // renders the call, the plugin author registers `<helper>` as a
1762
- // Kolon-callable method on the `$bf` vars entry in their own
1763
- // runtime — same contract as `$bf.query` itself, just not built in.
1764
- if (node?.kind === 'helper-call' && isValidHelperId(node.helper)) {
1765
- const argsX = node.args.map(a => this.renderParsedExprToKolon(a))
1766
- return `$bf.${node.helper}(${argsX.join(', ')})`
1767
- }
1768
- }
1769
- }
1770
-
1748
+ // #2843: a registered lowering plugin's call (the built-in `queryHref`,
1749
+ // or any userland plugin) is recognised no matter where it sits in the
1750
+ // tree a ternary branch, a template-literal interpolation, … — not
1751
+ // only when `parsed.kind === 'call'` directly. That recognition now
1752
+ // lives in `XslateTopLevelEmitter`'s `lowering` seam, consulted by
1753
+ // `emitParsedExpr`'s shared `call` dispatch; the support gate below is
1754
+ // passed `this._loweringMatchers` so a matched call's params (e.g.
1755
+ // `queryHref`'s object literal, otherwise `unsupported` at `rendered`
1756
+ // position) are admitted wherever the call is nested.
1757
+ //
1771
1758
  // `pos` distinguishes a derived-seed RHS (an assignment, checked via
1772
1759
  // `isSupportedValue`) from every other, genuinely rendered call site —
1773
1760
  // the rendered gate would otherwise re-refuse a tree the seed plan
1774
1761
  // already classified `derived` at value position (#2696 review).
1775
- const support = pos === 'value' ? isSupportedValue(parsed) : isSupported(parsed)
1762
+ const supportOpts = { loweringMatchers: this._loweringMatchers }
1763
+ const support = pos === 'value' ? isSupportedValue(parsed, supportOpts) : isSupported(parsed, supportOpts)
1776
1764
  if (!support.supported) {
1777
1765
  this.errors.push({
1778
1766
  code: 'BF101',
@@ -1832,7 +1820,7 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1832
1820
  */
1833
1821
  parseUndefinedAlternateTernary(
1834
1822
  expr: string,
1835
- ): { condition: string; consequent: string } | null {
1823
+ ): { condition: string; consequent: string; testParsed: ParsedExpr; consequentParsed: ParsedExpr } | null {
1836
1824
  const parsed = parseExpression(expr.trim())
1837
1825
  if (parsed?.kind !== 'conditional') return null
1838
1826
  const alt = parsed.alternate
@@ -1840,13 +1828,16 @@ export class XslateAdapter extends BaseAdapter implements IRNodeEmitter<XslateRe
1840
1828
  (alt.kind === 'identifier' && (alt.name === 'undefined' || alt.name === 'null')) ||
1841
1829
  (alt.kind === 'literal' && (alt.value === null || alt.value === undefined))
1842
1830
  if (!isUndef) return null
1843
- // Serialise the parsed sub-expressions back to JS source rather than
1844
- // slicing `expr` text `indexOf('?')` / `lastIndexOf(':')` would
1845
- // mis-split when the consequent itself contains `?` / `:` inside a
1846
- // string or nested ternary (`cond ? 'a:b' : undefined`).
1831
+ // `condition`/`consequent` are DEBUG text only (`exprToString` renders an
1832
+ // unsupported nested shape like an object literal as non-reparseable
1833
+ // `[UNSUPPORTED: …]` text) callers that need to re-lower the
1834
+ // sub-expression must use `testParsed`/`consequentParsed` (the actual
1835
+ // parsed trees) as `preParsed`, not re-parse these strings.
1847
1836
  return {
1848
1837
  condition: exprToString(parsed.test),
1849
1838
  consequent: exprToString(parsed.consequent),
1839
+ testParsed: parsed.test,
1840
+ consequentParsed: parsed.consequent,
1850
1841
  }
1851
1842
  }
1852
1843
 
@@ -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
+ // `XslateTopLevelEmitter`'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' }],
@@ -22,7 +22,4 @@ import type { RenderDivergences } from '@barefootjs/jsx'
22
22
  // the real name off that capture — the same in-template recompute the other
23
23
  // six template-stash backends already had. Keep the file even when the set
24
24
  // is empty — the next divergence lands here, not in a re-created file.
25
- export const renderDivergences: RenderDivergences = {
26
- 'aliased-loop-source':
27
- 'A `.map()` loop whose source is a local const alias of a signal getter (`const items__alias = items`) SSRs an empty `<ul>` on real Text::Xslate — 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.',
28
- }
25
+ export const renderDivergences: RenderDivergences = {}
@@ -581,6 +581,26 @@ function buildPerlProps(
581
581
  }
582
582
  }
583
583
 
584
+ // #2813: `extractSsrDefaults` can seed an entry under a name that is
585
+ // none of `propsParams` / `signals` / `memos` above — a bare local-const
586
+ // alias of a signal/memo getter (`const items__alias = items`,
587
+ // `ssr-defaults.ts`) seeds `items__alias` alongside `items`. Production
588
+ // hands the whole manifest-derived stash straight through
589
+ // (`deriveStashFromDefaults` IS the production seeding mechanism here,
590
+ // not a harness stand-in), so any leftover `derivedProps` key must be
591
+ // pushed too, or this harness would silently omit what production
592
+ // actually provides, mismeasuring this conformance case.
593
+ const seededNames = new Set<string>([
594
+ ...ir.metadata.propsParams.filter(p => !p.isRest).map(p => p.name),
595
+ ...(restPropsName ? [restPropsName] : []),
596
+ ...ir.metadata.signals.filter(s => !s.envReader).map(s => s.getter),
597
+ ...ir.metadata.memos.map(m => m.name),
598
+ ])
599
+ for (const [name, value] of Object.entries(derivedProps)) {
600
+ if (seededNames.has(name)) continue
601
+ entries.push(`${name} => ${toPerlLiteral(value)}`)
602
+ }
603
+
584
604
  // (#1922) Request-scoped `searchParams()`: bind `$searchParams` to an
585
605
  // empty-query reader via the lazy-loading factory (so the render script
586
606
  // needn't `use BarefootJS::SearchParams`). The conformance harness issues no