@barefootjs/go-template 0.35.1 → 0.35.3

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/index.js CHANGED
@@ -32,7 +32,7 @@ import {
32
32
  buildImportAliasMap,
33
33
  resolveGetterAliases,
34
34
  collectAliasableGetterNames,
35
- resolveBodyDestructuredPropAliases
35
+ resolveBodyDestructuredPropAliases as resolveBodyDestructuredPropAliases2
36
36
  } from "@barefootjs/jsx";
37
37
  import { findInterpolationEnd } from "@barefootjs/jsx/scanner";
38
38
  import { BF_REGION, escapeHtml, resolveJsxChildrenProp } from "@barefootjs/shared";
@@ -1225,12 +1225,9 @@ function convertInitialValue(ctx, value, _typeInfo, propsParams, preParsed) {
1225
1225
  const inlinedStr = ctx.resolveModuleStringConst(value);
1226
1226
  if (inlinedStr !== null)
1227
1227
  return inlinedStr;
1228
- const inlinedNum = ctx.resolveModuleNumericConst(value);
1229
- if (inlinedNum !== null)
1230
- return inlinedNum;
1231
- const inlinedBool = ctx.resolveModuleBooleanConst(value);
1232
- if (inlinedBool !== null)
1233
- return inlinedBool;
1228
+ const inlinedConst = ctx.resolveModuleConstAsGo(value, { kind: "go-source", bakeType: typeInfo });
1229
+ if (inlinedConst !== null)
1230
+ return inlinedConst;
1234
1231
  }
1235
1232
  const propName = ctx.extractPropNameFromInitialValue(value, preParsed);
1236
1233
  const param = propName ? propsParams?.find((p) => p.name === propName) : undefined;
@@ -2880,7 +2877,7 @@ function collectNillablePropNames(ctx, ir) {
2880
2877
  }
2881
2878
 
2882
2879
  // src/adapter/props/prop-classes.ts
2883
- import { collectLoopBoundNames } from "@barefootjs/jsx";
2880
+ import { collectLoopBoundNames, resolveBodyDestructuredPropAliases } from "@barefootjs/jsx";
2884
2881
  function isStringTypeInfo(type) {
2885
2882
  return type.kind === "primitive" && type.primitive === "string";
2886
2883
  }
@@ -2901,6 +2898,10 @@ function collectStringValueNames(ir) {
2901
2898
  if (isStringTypeInfo(p.type))
2902
2899
  names.add(p.name);
2903
2900
  }
2901
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName)) {
2902
+ if (names.has(callerKey))
2903
+ names.add(local);
2904
+ }
2904
2905
  for (const c of ir.metadata.localConstants) {
2905
2906
  if (c.type !== null && isStringTypeInfo(c.type) || isBareStringLiteral(c.value)) {
2906
2907
  names.add(c.name);
@@ -2952,8 +2953,7 @@ class GoTemplateAdapter extends BaseAdapter {
2952
2953
  extractPropFallback: (initialValue, preParsed) => this.extractPropFallback(initialValue, preParsed),
2953
2954
  extractCollisionDerivation: (parsed) => this.extractCollisionDerivation(parsed),
2954
2955
  resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
2955
- resolveModuleNumericConst: (name) => this.resolveModuleNumericConst(name),
2956
- resolveModuleBooleanConst: (name) => this.resolveModuleBooleanConst(name)
2956
+ resolveModuleConstAsGo: (name, target) => this.resolveModuleConstAsGo(name, target)
2957
2957
  };
2958
2958
  get errors() {
2959
2959
  return this.state.errors;
@@ -2993,7 +2993,7 @@ class GoTemplateAdapter extends BaseAdapter {
2993
2993
  const getterNames = collectAliasableGetterNames(ir.metadata.signals ?? [], ir.metadata.memos ?? []);
2994
2994
  this.state.getterAliases = resolveGetterAliases(ir.metadata.localConstants ?? [], (n) => getterNames.has(n));
2995
2995
  }
2996
- this.state.propDestructureAliases = resolveBodyDestructuredPropAliases(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName);
2996
+ this.state.propDestructureAliases = resolveBodyDestructuredPropAliases2(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName);
2997
2997
  this.state.staticLoopSourceBoundNames = collectLoopBoundNames2(ir);
2998
2998
  this.bakedStaticChildLoopCache = new Map;
2999
2999
  this.state.localHelperNames = new Set(this.state.localConstants.filter((c) => !c.isModule && c.containsArrow).map((c) => c.name));
@@ -5151,9 +5151,9 @@ ${goFields.join(`
5151
5151
  const inlined = this.resolveModuleStringConst(name);
5152
5152
  if (inlined !== null)
5153
5153
  return inlined;
5154
- const inlinedNum = this.resolveModuleNumericConst(name);
5155
- if (inlinedNum !== null)
5156
- return inlinedNum;
5154
+ const inlinedScalar = this.resolveModuleConstAsGo(name, { kind: "template-action" });
5155
+ if (inlinedScalar !== null)
5156
+ return inlinedScalar;
5157
5157
  if (this.isCurrentLoopItem(name))
5158
5158
  return ".";
5159
5159
  if (this.isOuterLoopParam(name))
@@ -5230,11 +5230,18 @@ ${goFields.join(`
5230
5230
  return hit !== null && hit.depth > 0 && hit.binding.source === "item";
5231
5231
  }
5232
5232
  rootFieldRef(name) {
5233
- const resolved = this.state.getterAliases.get(name) ?? this.state.propDestructureAliases.get(name) ?? name;
5233
+ const resolved = this.resolveRootFieldAlias(name);
5234
5234
  this.state.templateReadRootFields.add(resolved);
5235
5235
  const prefix = this.inLoop ? "$." : ".";
5236
5236
  return `${prefix}${capitalizeFieldName(resolved)}`;
5237
5237
  }
5238
+ resolveRootFieldAlias(name) {
5239
+ return this.state.getterAliases.get(name) ?? this.state.propDestructureAliases.get(name) ?? name;
5240
+ }
5241
+ filterRootFieldRef(name) {
5242
+ this.rootFieldRef(name);
5243
+ return `$.${capitalizeFieldName(this.resolveRootFieldAlias(name))}`;
5244
+ }
5238
5245
  searchParamsFieldRef(name) {
5239
5246
  return this.state.searchParamsLocals.has(name) ? this.rootFieldRef("searchParams") : null;
5240
5247
  }
@@ -5256,20 +5263,7 @@ ${goFields.join(`
5256
5263
  findModuleConst(name) {
5257
5264
  return this.state.localConstants.find((k) => k.name === name && k.isModule && !k.containsArrow);
5258
5265
  }
5259
- resolveModuleNumericConst(name) {
5260
- if (this.isCurrentLoopItem(name))
5261
- return null;
5262
- if (this.loopVarRefCount.has(name))
5263
- return null;
5264
- if (this.isOuterLoopParam(name))
5265
- return null;
5266
- const c = this.findModuleConst(name);
5267
- if (!c || c.value === undefined)
5268
- return null;
5269
- const v = c.value.trim().replace(/(?<=\d)_(?=\d)/g, "");
5270
- return /^-?\d+(\.\d+)?$/.test(v) ? v : null;
5271
- }
5272
- resolveModuleBooleanConst(name) {
5266
+ resolveModuleConstAsGo(name, target) {
5273
5267
  if (this.isCurrentLoopItem(name))
5274
5268
  return null;
5275
5269
  if (this.loopVarRefCount.has(name))
@@ -5277,10 +5271,13 @@ ${goFields.join(`
5277
5271
  if (this.isOuterLoopParam(name))
5278
5272
  return null;
5279
5273
  const c = this.findModuleConst(name);
5280
- if (!c || c.value === undefined)
5274
+ if (!c?.parsed)
5281
5275
  return null;
5282
- const v = c.value.trim();
5283
- return v === "true" || v === "false" ? v : null;
5276
+ if (target.kind === "template-action") {
5277
+ return c.parsed.kind === "literal" || c.parsed.kind === "unary" ? parsedLiteralToGo(this.emitCtx, c.parsed) : null;
5278
+ }
5279
+ const bakeType = target.bakeType.kind !== "unknown" ? target.bakeType : c.type ?? undefined;
5280
+ return parsedLiteralToGo(this.emitCtx, c.parsed, bakeType);
5284
5281
  }
5285
5282
  literal(value, literalType) {
5286
5283
  if (literalType === "string")
@@ -5929,11 +5926,9 @@ ${goFields.join(`
5929
5926
  }
5930
5927
  const signal = localVarMap.get(expr.name);
5931
5928
  if (signal) {
5932
- this.rootFieldRef(signal);
5933
- return `$.${capitalizeFieldName(signal)}`;
5929
+ return this.filterRootFieldRef(signal);
5934
5930
  }
5935
- this.rootFieldRef(expr.name);
5936
- return `.${capitalizeFieldName(expr.name)}`;
5931
+ return this.filterRootFieldRef(expr.name);
5937
5932
  }
5938
5933
  case "literal":
5939
5934
  if (expr.literalType === "string") {
@@ -5947,6 +5942,9 @@ ${goFields.join(`
5947
5942
  if (expr.object.kind === "identifier" && expr.object.name === param) {
5948
5943
  return `${paramPrefix}.${capitalizeFieldName(expr.property)}`;
5949
5944
  }
5945
+ if (expr.object.kind === "identifier" && this.state.propsObjectName && expr.object.name === this.state.propsObjectName) {
5946
+ return this.filterRootFieldRef(expr.property);
5947
+ }
5950
5948
  if (expr.property === "length") {
5951
5949
  const innerHO = this.higherOrderShapeOf(expr.object);
5952
5950
  if (innerHO && innerHO.method === "filter") {
@@ -5965,8 +5963,7 @@ ${goFields.join(`
5965
5963
  return `${paramPrefix}.${capitalizeFieldName(expr.callee.property)}`;
5966
5964
  }
5967
5965
  if (expr.callee.kind === "identifier" && expr.args.length === 0) {
5968
- this.rootFieldRef(expr.callee.name);
5969
- return `$.${capitalizeFieldName(expr.callee.name)}`;
5966
+ return this.filterRootFieldRef(expr.callee.name);
5970
5967
  }
5971
5968
  if (asCallbackMethodCall4(expr) !== null) {
5972
5969
  return this.refuseFilterExprNode(expr);
@@ -5996,29 +5993,33 @@ ${goFields.join(`
5996
5993
  const right = this.renderFilterExpr(expr.right, param, localVarMap, datumField);
5997
5994
  if (this.filterExprUnsupported)
5998
5995
  return "false";
5996
+ const wl = wrapIfMultiToken(left);
5997
+ const wr = wrapIfMultiToken(right);
5999
5998
  switch (expr.op) {
6000
5999
  case "===":
6001
6000
  case "==":
6002
- return `eq ${left} ${right}`;
6001
+ return `eq ${wl} ${wr}`;
6003
6002
  case "!==":
6004
6003
  case "!=":
6005
- return `ne ${left} ${right}`;
6004
+ return `ne ${wl} ${wr}`;
6006
6005
  case ">":
6007
- return `gt ${left} ${right}`;
6006
+ return `gt ${wl} ${wr}`;
6008
6007
  case "<":
6009
- return `lt ${left} ${right}`;
6008
+ return `lt ${wl} ${wr}`;
6010
6009
  case ">=":
6011
- return `ge ${left} ${right}`;
6010
+ return `ge ${wl} ${wr}`;
6012
6011
  case "<=":
6013
- return `le ${left} ${right}`;
6012
+ return `le ${wl} ${wr}`;
6014
6013
  case "+":
6015
- return this._emitPlus(expr.left, expr.right, left, right);
6014
+ return this._emitPlus(expr.left, expr.right, wl, wr);
6016
6015
  case "-":
6017
- return `bf_sub ${left} ${right}`;
6016
+ return `bf_sub ${wl} ${wr}`;
6018
6017
  case "*":
6019
- return `bf_mul ${left} ${right}`;
6018
+ return `bf_mul ${wl} ${wr}`;
6020
6019
  case "/":
6021
- return `bf_div ${left} ${right}`;
6020
+ return `bf_div ${wl} ${wr}`;
6021
+ case "%":
6022
+ return `bf_mod ${wl} ${wr}`;
6022
6023
  default:
6023
6024
  return `${left} ${expr.op} ${right}`;
6024
6025
  }
@@ -6469,6 +6470,9 @@ ${goFields.join(`
6469
6470
  case "/":
6470
6471
  result = `bf_div ${left} ${right}`;
6471
6472
  break;
6473
+ case "%":
6474
+ result = `bf_mod ${left} ${right}`;
6475
+ break;
6472
6476
  default:
6473
6477
  result = `${left} ${expr.op} ${right}`;
6474
6478
  }
@@ -7109,7 +7113,12 @@ var conformancePins = {
7109
7113
  severity: "error",
7110
7114
  issue: "https://github.com/piconic-ai/barefootjs/issues/2700"
7111
7115
  }],
7112
- "namespace-import-primitive": [{ code: "BF013", severity: "error" }]
7116
+ "namespace-import-primitive": [{ code: "BF013", severity: "error" }],
7117
+ "static-nested-loop-ref": [{
7118
+ code: "BF101",
7119
+ severity: "error",
7120
+ issue: "https://github.com/piconic-ai/barefootjs/issues/2893"
7121
+ }]
7113
7122
  };
7114
7123
  // src/render-divergences.ts
7115
7124
  var renderDivergences = {};
package/dist/vite.js CHANGED
@@ -3525,8 +3525,11 @@ function formatDateLocalNames(metadata) {
3525
3525
  // ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
3526
3526
  import ts19 from "typescript";
3527
3527
 
3528
- // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3528
+ // ../jsx/src/ir-to-client-js/emit-reactive.ts
3529
3529
  import ts20 from "typescript";
3530
+
3531
+ // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3532
+ import ts21 from "typescript";
3530
3533
  var NO_PREAMBLE = {
3531
3534
  lazySafe: true,
3532
3535
  facts: { declaredNames: new Set, freeNames: new Set }
@@ -3575,9 +3578,6 @@ var INERT_BINDING_GLOBALS = new Set([
3575
3578
  "decodeURI"
3576
3579
  ]);
3577
3580
 
3578
- // ../jsx/src/ir-to-client-js/emit-reactive.ts
3579
- import ts21 from "typescript";
3580
-
3581
3581
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
3582
3582
  var NON_BUBBLING_EVENTS = new Set([
3583
3583
  "blur",
@@ -6524,12 +6524,9 @@ function convertInitialValue(ctx, value, _typeInfo, propsParams, preParsed) {
6524
6524
  const inlinedStr = ctx.resolveModuleStringConst(value);
6525
6525
  if (inlinedStr !== null)
6526
6526
  return inlinedStr;
6527
- const inlinedNum = ctx.resolveModuleNumericConst(value);
6528
- if (inlinedNum !== null)
6529
- return inlinedNum;
6530
- const inlinedBool = ctx.resolveModuleBooleanConst(value);
6531
- if (inlinedBool !== null)
6532
- return inlinedBool;
6527
+ const inlinedConst = ctx.resolveModuleConstAsGo(value, { kind: "go-source", bakeType: typeInfo });
6528
+ if (inlinedConst !== null)
6529
+ return inlinedConst;
6533
6530
  }
6534
6531
  const propName = ctx.extractPropNameFromInitialValue(value, preParsed);
6535
6532
  const param = propName ? propsParams?.find((p) => p.name === propName) : undefined;
@@ -8187,6 +8184,10 @@ function collectStringValueNames(ir) {
8187
8184
  if (isStringTypeInfo(p.type))
8188
8185
  names.add(p.name);
8189
8186
  }
8187
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName)) {
8188
+ if (names.has(callerKey))
8189
+ names.add(local);
8190
+ }
8190
8191
  for (const c of ir.metadata.localConstants) {
8191
8192
  if (c.type !== null && isStringTypeInfo(c.type) || isBareStringLiteral(c.value)) {
8192
8193
  names.add(c.name);
@@ -8238,8 +8239,7 @@ class GoTemplateAdapter extends BaseAdapter {
8238
8239
  extractPropFallback: (initialValue, preParsed) => this.extractPropFallback(initialValue, preParsed),
8239
8240
  extractCollisionDerivation: (parsed) => this.extractCollisionDerivation(parsed),
8240
8241
  resolveModuleStringConst: (name) => this.resolveModuleStringConst(name),
8241
- resolveModuleNumericConst: (name) => this.resolveModuleNumericConst(name),
8242
- resolveModuleBooleanConst: (name) => this.resolveModuleBooleanConst(name)
8242
+ resolveModuleConstAsGo: (name, target) => this.resolveModuleConstAsGo(name, target)
8243
8243
  };
8244
8244
  get errors() {
8245
8245
  return this.state.errors;
@@ -10437,9 +10437,9 @@ ${goFields.join(`
10437
10437
  const inlined = this.resolveModuleStringConst(name);
10438
10438
  if (inlined !== null)
10439
10439
  return inlined;
10440
- const inlinedNum = this.resolveModuleNumericConst(name);
10441
- if (inlinedNum !== null)
10442
- return inlinedNum;
10440
+ const inlinedScalar = this.resolveModuleConstAsGo(name, { kind: "template-action" });
10441
+ if (inlinedScalar !== null)
10442
+ return inlinedScalar;
10443
10443
  if (this.isCurrentLoopItem(name))
10444
10444
  return ".";
10445
10445
  if (this.isOuterLoopParam(name))
@@ -10516,11 +10516,18 @@ ${goFields.join(`
10516
10516
  return hit !== null && hit.depth > 0 && hit.binding.source === "item";
10517
10517
  }
10518
10518
  rootFieldRef(name) {
10519
- const resolved = this.state.getterAliases.get(name) ?? this.state.propDestructureAliases.get(name) ?? name;
10519
+ const resolved = this.resolveRootFieldAlias(name);
10520
10520
  this.state.templateReadRootFields.add(resolved);
10521
10521
  const prefix = this.inLoop ? "$." : ".";
10522
10522
  return `${prefix}${capitalizeFieldName(resolved)}`;
10523
10523
  }
10524
+ resolveRootFieldAlias(name) {
10525
+ return this.state.getterAliases.get(name) ?? this.state.propDestructureAliases.get(name) ?? name;
10526
+ }
10527
+ filterRootFieldRef(name) {
10528
+ this.rootFieldRef(name);
10529
+ return `$.${capitalizeFieldName(this.resolveRootFieldAlias(name))}`;
10530
+ }
10524
10531
  searchParamsFieldRef(name) {
10525
10532
  return this.state.searchParamsLocals.has(name) ? this.rootFieldRef("searchParams") : null;
10526
10533
  }
@@ -10542,20 +10549,7 @@ ${goFields.join(`
10542
10549
  findModuleConst(name) {
10543
10550
  return this.state.localConstants.find((k) => k.name === name && k.isModule && !k.containsArrow);
10544
10551
  }
10545
- resolveModuleNumericConst(name) {
10546
- if (this.isCurrentLoopItem(name))
10547
- return null;
10548
- if (this.loopVarRefCount.has(name))
10549
- return null;
10550
- if (this.isOuterLoopParam(name))
10551
- return null;
10552
- const c = this.findModuleConst(name);
10553
- if (!c || c.value === undefined)
10554
- return null;
10555
- const v = c.value.trim().replace(/(?<=\d)_(?=\d)/g, "");
10556
- return /^-?\d+(\.\d+)?$/.test(v) ? v : null;
10557
- }
10558
- resolveModuleBooleanConst(name) {
10552
+ resolveModuleConstAsGo(name, target) {
10559
10553
  if (this.isCurrentLoopItem(name))
10560
10554
  return null;
10561
10555
  if (this.loopVarRefCount.has(name))
@@ -10563,10 +10557,13 @@ ${goFields.join(`
10563
10557
  if (this.isOuterLoopParam(name))
10564
10558
  return null;
10565
10559
  const c = this.findModuleConst(name);
10566
- if (!c || c.value === undefined)
10560
+ if (!c?.parsed)
10567
10561
  return null;
10568
- const v = c.value.trim();
10569
- return v === "true" || v === "false" ? v : null;
10562
+ if (target.kind === "template-action") {
10563
+ return c.parsed.kind === "literal" || c.parsed.kind === "unary" ? parsedLiteralToGo(this.emitCtx, c.parsed) : null;
10564
+ }
10565
+ const bakeType = target.bakeType.kind !== "unknown" ? target.bakeType : c.type ?? undefined;
10566
+ return parsedLiteralToGo(this.emitCtx, c.parsed, bakeType);
10570
10567
  }
10571
10568
  literal(value, literalType) {
10572
10569
  if (literalType === "string")
@@ -11215,11 +11212,9 @@ ${goFields.join(`
11215
11212
  }
11216
11213
  const signal = localVarMap.get(expr.name);
11217
11214
  if (signal) {
11218
- this.rootFieldRef(signal);
11219
- return `$.${capitalizeFieldName(signal)}`;
11215
+ return this.filterRootFieldRef(signal);
11220
11216
  }
11221
- this.rootFieldRef(expr.name);
11222
- return `.${capitalizeFieldName(expr.name)}`;
11217
+ return this.filterRootFieldRef(expr.name);
11223
11218
  }
11224
11219
  case "literal":
11225
11220
  if (expr.literalType === "string") {
@@ -11233,6 +11228,9 @@ ${goFields.join(`
11233
11228
  if (expr.object.kind === "identifier" && expr.object.name === param) {
11234
11229
  return `${paramPrefix}.${capitalizeFieldName(expr.property)}`;
11235
11230
  }
11231
+ if (expr.object.kind === "identifier" && this.state.propsObjectName && expr.object.name === this.state.propsObjectName) {
11232
+ return this.filterRootFieldRef(expr.property);
11233
+ }
11236
11234
  if (expr.property === "length") {
11237
11235
  const innerHO = this.higherOrderShapeOf(expr.object);
11238
11236
  if (innerHO && innerHO.method === "filter") {
@@ -11251,8 +11249,7 @@ ${goFields.join(`
11251
11249
  return `${paramPrefix}.${capitalizeFieldName(expr.callee.property)}`;
11252
11250
  }
11253
11251
  if (expr.callee.kind === "identifier" && expr.args.length === 0) {
11254
- this.rootFieldRef(expr.callee.name);
11255
- return `$.${capitalizeFieldName(expr.callee.name)}`;
11252
+ return this.filterRootFieldRef(expr.callee.name);
11256
11253
  }
11257
11254
  if (asCallbackMethodCall(expr) !== null) {
11258
11255
  return this.refuseFilterExprNode(expr);
@@ -11282,29 +11279,33 @@ ${goFields.join(`
11282
11279
  const right = this.renderFilterExpr(expr.right, param, localVarMap, datumField);
11283
11280
  if (this.filterExprUnsupported)
11284
11281
  return "false";
11282
+ const wl = wrapIfMultiToken(left);
11283
+ const wr = wrapIfMultiToken(right);
11285
11284
  switch (expr.op) {
11286
11285
  case "===":
11287
11286
  case "==":
11288
- return `eq ${left} ${right}`;
11287
+ return `eq ${wl} ${wr}`;
11289
11288
  case "!==":
11290
11289
  case "!=":
11291
- return `ne ${left} ${right}`;
11290
+ return `ne ${wl} ${wr}`;
11292
11291
  case ">":
11293
- return `gt ${left} ${right}`;
11292
+ return `gt ${wl} ${wr}`;
11294
11293
  case "<":
11295
- return `lt ${left} ${right}`;
11294
+ return `lt ${wl} ${wr}`;
11296
11295
  case ">=":
11297
- return `ge ${left} ${right}`;
11296
+ return `ge ${wl} ${wr}`;
11298
11297
  case "<=":
11299
- return `le ${left} ${right}`;
11298
+ return `le ${wl} ${wr}`;
11300
11299
  case "+":
11301
- return this._emitPlus(expr.left, expr.right, left, right);
11300
+ return this._emitPlus(expr.left, expr.right, wl, wr);
11302
11301
  case "-":
11303
- return `bf_sub ${left} ${right}`;
11302
+ return `bf_sub ${wl} ${wr}`;
11304
11303
  case "*":
11305
- return `bf_mul ${left} ${right}`;
11304
+ return `bf_mul ${wl} ${wr}`;
11306
11305
  case "/":
11307
- return `bf_div ${left} ${right}`;
11306
+ return `bf_div ${wl} ${wr}`;
11307
+ case "%":
11308
+ return `bf_mod ${wl} ${wr}`;
11308
11309
  default:
11309
11310
  return `${left} ${expr.op} ${right}`;
11310
11311
  }
@@ -11755,6 +11756,9 @@ ${goFields.join(`
11755
11756
  case "/":
11756
11757
  result = `bf_div ${left} ${right}`;
11757
11758
  break;
11759
+ case "%":
11760
+ result = `bf_mod ${left} ${right}`;
11761
+ break;
11758
11762
  default:
11759
11763
  result = `${left} ${expr.op} ${right}`;
11760
11764
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/go-template",
3
- "version": "0.35.1",
3
+ "version": "0.35.3",
4
4
  "description": "Go html/template adapter for BarefootJS - generates Go template files from IR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,7 +49,7 @@
49
49
  "directory": "packages/adapter-go-template"
50
50
  },
51
51
  "dependencies": {
52
- "@barefootjs/shared": "0.35.1"
52
+ "@barefootjs/shared": "0.35.3"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@barefootjs/jsx": ">=0.2.0",
@@ -67,9 +67,9 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "@barefootjs/adapter-tests": "0.1.0",
70
- "@barefootjs/client": "0.35.1",
71
- "@barefootjs/jsx": "0.35.1",
72
- "@barefootjs/vite": "0.35.1",
70
+ "@barefootjs/client": "0.35.3",
71
+ "@barefootjs/jsx": "0.35.3",
72
+ "@barefootjs/vite": "0.35.3",
73
73
  "vite": "^6.0.0"
74
74
  }
75
75
  }
@@ -1641,7 +1641,7 @@ export function Widget(props: P) {
1641
1641
  // to `nil` — the analyzer types it `unknown` since it never chases an
1642
1642
  // identifier to its declaration, so none of convertInitialValue's typed
1643
1643
  // branches saw it (#2794). Now resolved via the same
1644
- // resolveModuleStringConst/resolveModuleNumericConst the adapter
1644
+ // resolveModuleStringConst/resolveModuleConstAsGo the adapter
1645
1645
  // already used for live template expressions (template-interp.ts).
1646
1646
  test('signal seeded from a module-level const bakes its literal value, not nil', () => {
1647
1647
  const adapter = new GoTemplateAdapter()
@@ -6208,7 +6208,7 @@ export function Nested({ groups }: { groups: { label: string }[][] }) {
6208
6208
  // goes through `identifier()` (the `ParsedExprEmitter` method), which
6209
6209
  // already carries the loop-shadow guards (`loopParamStack` /
6210
6210
  // `isOuterLoopParam`, mirrored from `resolveModuleStringConst` /
6211
- // `resolveModuleNumericConst`). So a `.map((count) => ...)` callback param
6211
+ // `resolveModuleConstAsGo`). So a `.map((count) => ...)` callback param
6212
6212
  // that shadows an outer `const count = 7` got the OUTER literal inlined at
6213
6213
  // the `data-key` position even though the text position (which DOES go
6214
6214
  // through `identifier()`) correctly resolved to the per-item value.
@@ -6909,3 +6909,34 @@ export { C }
6909
6909
  expect(decode(htmlExplicitZero)).toEqual({ name: 'Ada', label: '', x: 0 })
6910
6910
  })
6911
6911
  })
6912
+
6913
+ describe('GoTemplateAdapter - collectStringValueNames resolves renamed body-destructured prop aliases (#2894)', () => {
6914
+ // Sibling gap to #2883 (Mojolicious): a `+` concat against a bare-props-form
6915
+ // BODY-destructured, RENAMED prop (`const { fallbackLabel: skipLabel } =
6916
+ // props`, the #2788 alias family) previously had no witness in
6917
+ // `collectStringValueNames`, so `isStringConcatBinary` fell through to
6918
+ // numeric `bf_add` instead of `bf_concat_str` — Go's `bf_add` coerces both
6919
+ // operands through `toFloat64`, so a string operand silently becomes `0`.
6920
+ test('a `+` concat against a renamed body-destructured prop lowers to bf_concat_str, not bf_add', () => {
6921
+ const result = compileAndGenerate(`
6922
+ 'use client'
6923
+ import { createSignal } from '@barefootjs/client'
6924
+
6925
+ type Todo = { id: number; label: string }
6926
+
6927
+ export function ConcatRenamedProp(props: { fallbackLabel: string }) {
6928
+ const { fallbackLabel: skipLabel } = props
6929
+ const [todos] = createSignal<Todo[]>([{ id: 1, label: 'Alpha' }])
6930
+ return (
6931
+ <ul>
6932
+ {todos().map(t => (
6933
+ <li key={t.id}>{t.label + skipLabel}</li>
6934
+ ))}
6935
+ </ul>
6936
+ )
6937
+ }
6938
+ `)
6939
+ expect(result.template).toContain('bf_concat_str .Label $.FallbackLabel')
6940
+ expect(result.template).not.toContain('bf_add .Label $.FallbackLabel')
6941
+ })
6942
+ })
@@ -14,7 +14,7 @@
14
14
  * genuinely needs it, so the seam documents the real cross-module coupling.
15
15
  */
16
16
 
17
- import type { ParsedExpr } from '@barefootjs/jsx'
17
+ import type { ParsedExpr, TypeInfo } from '@barefootjs/jsx'
18
18
 
19
19
  import type { CompileState } from './lib/compile-state.ts'
20
20
 
@@ -81,16 +81,18 @@ export interface GoEmitContext {
81
81
  resolveModuleStringConst(name: string): string | null
82
82
 
83
83
  /**
84
- * Inline a module numeric const by name as its Go literal text (e.g.
85
- * `8`, `-3.5`), or null when the name is not such a const (loop vars and
86
- * outer-loop params are excluded, same as `resolveModuleStringConst`).
84
+ * Resolve a bare identifier naming a plain module-level const (`const
85
+ * TRACK = 8`, `const OPEN = true`, `const INITIAL: Row[] = [...]`) to its
86
+ * Go literal, dispatched structurally off the const's `ConstantInfo.parsed`
87
+ * — or null when the name is not such a const (loop vars and outer-loop
88
+ * params are excluded, same as `resolveModuleStringConst`). `target.kind
89
+ * === 'go-source'` may bake a composite (array/object) literal against
90
+ * `target.bakeType`; `target.kind === 'template-action'` only resolves a
91
+ * scalar, since a `{{...}}` splice has no valid Go template spelling for a
92
+ * composite literal.
87
93
  */
88
- resolveModuleNumericConst(name: string): string | null
89
-
90
- /**
91
- * Inline a module boolean const by name as its Go literal text
92
- * (`true`/`false`), or null when the name is not such a const (same
93
- * exclusions as `resolveModuleNumericConst`).
94
- */
95
- resolveModuleBooleanConst(name: string): string | null
94
+ resolveModuleConstAsGo(
95
+ name: string,
96
+ target: { kind: 'template-action' } | { kind: 'go-source'; bakeType: TypeInfo },
97
+ ): string | null
96
98
  }