@barefootjs/go-template 0.31.10 → 0.33.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.
Files changed (33) hide show
  1. package/dist/adapter/emit-context.d.ts +16 -0
  2. package/dist/adapter/emit-context.d.ts.map +1 -1
  3. package/dist/adapter/expr/helper-inline.d.ts.map +1 -1
  4. package/dist/adapter/go-template-adapter.d.ts +75 -1
  5. package/dist/adapter/go-template-adapter.d.ts.map +1 -1
  6. package/dist/adapter/index.js +165 -15
  7. package/dist/adapter/lib/types.d.ts +13 -0
  8. package/dist/adapter/lib/types.d.ts.map +1 -1
  9. package/dist/adapter/memo/memo-compute.d.ts.map +1 -1
  10. package/dist/adapter/memo/memo-value.d.ts.map +1 -1
  11. package/dist/adapter/memo/template-interp.d.ts.map +1 -1
  12. package/dist/adapter/props/prop-types.d.ts.map +1 -1
  13. package/dist/adapter/spread/spread-codegen.d.ts.map +1 -1
  14. package/dist/adapter/value/parsed-literal-to-go.d.ts.map +1 -1
  15. package/dist/adapter/value/value-lowering.d.ts +15 -12
  16. package/dist/adapter/value/value-lowering.d.ts.map +1 -1
  17. package/dist/index.js +166 -17
  18. package/dist/render-divergences.d.ts.map +1 -1
  19. package/dist/vite.js +259 -52
  20. package/package.json +5 -5
  21. package/src/__tests__/go-template-adapter.test.ts +246 -6
  22. package/src/adapter/emit-context.ts +14 -0
  23. package/src/adapter/expr/helper-inline.ts +4 -2
  24. package/src/adapter/go-template-adapter.ts +296 -9
  25. package/src/adapter/lib/types.ts +10 -0
  26. package/src/adapter/memo/memo-compute.ts +12 -1
  27. package/src/adapter/memo/memo-value.ts +3 -0
  28. package/src/adapter/memo/template-interp.ts +5 -0
  29. package/src/adapter/props/prop-types.ts +26 -1
  30. package/src/adapter/spread/spread-codegen.ts +8 -0
  31. package/src/adapter/value/parsed-literal-to-go.ts +7 -0
  32. package/src/adapter/value/value-lowering.ts +96 -22
  33. package/src/render-divergences.ts +2 -23
@@ -1 +1 @@
1
- {"version":3,"file":"spread-codegen.d.ts","sourceRoot":"","sources":["../../../src/adapter/spread/spread-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EAQN,UAAU,EACX,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGrD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAIrF;AAuID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,aAAa,EAClB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,WAAW,EACf,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,GAAG,IAAI,CA6Ef"}
1
+ {"version":3,"file":"spread-codegen.d.ts","sourceRoot":"","sources":["../../../src/adapter/spread/spread-codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EAQN,UAAU,EACX,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGrD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,EAAE,CAIrF;AA2ID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,aAAa,EAClB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,WAAW,EACf,MAAM,CAAC,EAAE,UAAU,GAClB,MAAM,GAAG,IAAI,CA6Ef"}
@@ -1 +1 @@
1
- {"version":3,"file":"parsed-literal-to-go.d.ts","sourceRoot":"","sources":["../../../src/adapter/value/parsed-literal-to-go.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAkB,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAmDvD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAalE;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,QAAQ,GAClB,MAAM,GAAG,IAAI,CA8Ef"}
1
+ {"version":3,"file":"parsed-literal-to-go.d.ts","sourceRoot":"","sources":["../../../src/adapter/value/parsed-literal-to-go.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAkB,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAsDvD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAalE;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,UAAU,EAChB,QAAQ,CAAC,EAAE,QAAQ,GAClB,MAAM,GAAG,IAAI,CAkFf"}
@@ -74,20 +74,23 @@ export declare function matchMapJoinChain(expr: ParsedExpr): {
74
74
  } | null;
75
75
  /**
76
76
  * Lower a `.map(cb).join(sep)` chain (matched by {@link matchMapJoinChain})
77
- * to a `bf.Join(bf.MapEval(<items>, "<projJSON>", "<param>", <envMap>),
78
- * <sep>)` Go expression the constructor-source analogue of
79
- * `matchFilterArmMemo`'s `bf.FilterEval` emit (`memo-compute.ts`), reusing
80
- * the SAME two runtime evaluator functions (`MapEval`, `eval.go`; `Join`,
81
- * `bf.go`) the template-position `bf_map_eval`/`bf_join` lowering already
82
- * calls. Shared by a memo's derived value (`memoInitialFromParsedBody`'s
83
- * concatenation-chain arm) and a SIGNAL's own initializer
84
- * (`convertInitialValue`'s `string` branch, #2492).
77
+ * to a `bf.Join(<chain>, <sep>)` Go expression, where `<chain>` is the
78
+ * chain's OWN `.map()` step composed by {@link callbackStepToGo} over
79
+ * whatever {@link resolveMapChainAsGo} resolves its receiver to (a base
80
+ * shape, or one or more nested `.map()`/`.filter()` layers) — the
81
+ * constructor-source analogue of `matchFilterArmMemo`'s `bf.FilterEval`
82
+ * emit (`memo-compute.ts`), reusing the SAME runtime evaluator functions
83
+ * (`MapEval`/`FilterEval`, `eval.go`; `Join`, `bf.go`) the template-position
84
+ * `bf_map_eval`/`bf_join` lowering already calls. Shared by a memo's
85
+ * derived value (`memoInitialFromParsedBody`'s concatenation-chain arm and
86
+ * bare-chain arm) and a SIGNAL's own initializer (`convertInitialValue`'s
87
+ * `string` branch, #2492).
85
88
  *
86
89
  * @returns the Go expression, or null when the receiver doesn't resolve
87
- * ({@link resolveMapJoinBaseAsGo}), the projection body isn't
88
- * representable to the runtime evaluator (`serializeParsedExpr` refusal),
89
- * a captured free variable doesn't resolve, or the separator isn't a
90
- * string literal (a dynamic separator — out of scope for this arm).
90
+ * ({@link resolveMapChainAsGo}), the projection body isn't representable
91
+ * to the runtime evaluator (`serializeParsedExpr` refusal), a captured
92
+ * free variable doesn't resolve, or the separator isn't a string literal
93
+ * (a dynamic separator — out of scope for this arm).
91
94
  */
92
95
  export declare function mapJoinChainToGo(ctx: GoEmitContext, chain: {
93
96
  object: ParsedExpr;
@@ -1 +1 @@
1
- {"version":3,"file":"value-lowering.d.ts","sourceRoot":"","sources":["../../../src/adapter/value/value-lowering.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAQ3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAyDtD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,QAAQ,EACnB,WAAW,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACrD,SAAS,CAAC,EAAE,UAAU,GACrB,MAAM,CAkHR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,QAAQ,EAClB,SAAS,CAAC,EAAE,UAAU,GACrB,MAAM,GAAG,IAAI,CAMf;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAWxF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,aAAa,EAClB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACpD,gBAAgB,GAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAA4B,EACjF,UAAU,CAAC,EAAE,QAAQ,GACpB,MAAM,CAqCR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG;IACnD,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAC7C,MAAM,CAAC,EAAE,UAAU,CAAA;CACpB,GAAG,IAAI,CAKP;AAsED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EACjG,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EAAE,EACzF,WAAW,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACpD,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GACrD,MAAM,GAAG,IAAI,CAqCf"}
1
+ {"version":3,"file":"value-lowering.d.ts","sourceRoot":"","sources":["../../../src/adapter/value/value-lowering.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAQ3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAyDtD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,QAAQ,EACnB,WAAW,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACrD,SAAS,CAAC,EAAE,UAAU,GACrB,MAAM,CAkHR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,QAAQ,EAClB,SAAS,CAAC,EAAE,UAAU,GACrB,MAAM,GAAG,IAAI,CAMf;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAcxF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,aAAa,EAClB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACpD,gBAAgB,GAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAA4B,EACjF,UAAU,CAAC,EAAE,QAAQ,GACpB,MAAM,CAqCR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG;IACnD,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAC7C,MAAM,CAAC,EAAE,UAAU,CAAA;CACpB,GAAG,IAAI,CAKP;AA8JD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EACjG,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EAAE,EACzF,WAAW,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EACpD,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GACrD,MAAM,GAAG,IAAI,CAiBf"}
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  asCallbackMethodCall as asCallbackMethodCall4,
12
12
  sortComparatorFromArrow,
13
13
  emitParsedExpr,
14
+ groupObjectLiteralSegments,
14
15
  emitIRNode,
15
16
  emitAttrValue,
16
17
  augmentInheritedPropAccesses,
@@ -724,7 +725,7 @@ function isSubstituteSafeBody(body, paramNames) {
724
725
  if (n.kind === "identifier")
725
726
  return paramNames.has(n.name);
726
727
  if (n.kind === "object-literal") {
727
- return n.properties.some((p) => p.shorthand && paramNames.has(p.key) || referencesParam(p.value));
728
+ return n.properties.some((p) => p.kind === "spread" ? referencesParam(p.expr) : p.shorthand && paramNames.has(p.key) || referencesParam(p.value));
728
729
  }
729
730
  let hit = false;
730
731
  forEachValueChild(n, (c) => {
@@ -1092,6 +1093,8 @@ function bakeInlineObjectAsGoMap(ctx, expr) {
1092
1093
  return null;
1093
1094
  const entries = [];
1094
1095
  for (const prop of expr.properties) {
1096
+ if (prop.kind === "spread")
1097
+ return null;
1095
1098
  if (prop.shorthand)
1096
1099
  return null;
1097
1100
  const go = prop.value.kind === "object-literal" ? bakeInlineObjectAsGoMap(ctx, prop.value) : parsedLiteralToGo(ctx, prop.value);
@@ -1147,6 +1150,8 @@ function parsedLiteralToGo(ctx, expr, typeInfo) {
1147
1150
  return null;
1148
1151
  const entries = [];
1149
1152
  for (const prop of expr.properties) {
1153
+ if (prop.kind === "spread")
1154
+ return null;
1150
1155
  const goField = structFields.get(prop.key);
1151
1156
  if (!goField)
1152
1157
  return null;
@@ -1268,6 +1273,8 @@ function objectLiteralToGoMap(ctx, expr) {
1268
1273
  return null;
1269
1274
  const entries = [];
1270
1275
  for (const prop of expr.properties) {
1276
+ if (prop.kind === "spread")
1277
+ return null;
1271
1278
  if (prop.shorthand)
1272
1279
  return null;
1273
1280
  const val = parsedLiteralToGo(ctx, prop.value);
@@ -1346,17 +1353,18 @@ function resolveMapJoinBaseAsGo(ctx, object, signals, propsParams) {
1346
1353
  }
1347
1354
  return null;
1348
1355
  }
1349
- function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
1350
- const itemsGo = resolveMapJoinBaseAsGo(ctx, chain.object, signals, propsParams);
1351
- if (itemsGo === null)
1356
+ var CALLBACK_EVAL_FUNC = { map: "bf.MapEval", filter: "bf.FilterEval" };
1357
+ function callbackStepToGo(ctx, method, itemsGo, arrow, signals, propsParams, propFallbackVars) {
1358
+ const evalFunc = CALLBACK_EVAL_FUNC[method];
1359
+ if (!evalFunc)
1352
1360
  return null;
1353
1361
  const knownGetterNames = new Set(signals.map((s) => s.getter));
1354
- const materialized = materializeGetterCalls(chain.arrow.body, knownGetterNames);
1362
+ const materialized = materializeGetterCalls(arrow.body, knownGetterNames);
1355
1363
  const projJSON = serializeParsedExpr2(materialized);
1356
1364
  if (projJSON === null)
1357
1365
  return null;
1358
- const paramName = chain.arrow.params[0] ?? "_";
1359
- const freeVars = freeVarsInBody2(materialized, new Set(chain.arrow.params));
1366
+ const paramName = arrow.params[0] ?? "_";
1367
+ const freeVars = freeVarsInBody2(materialized, new Set(arrow.params));
1360
1368
  const envEntries = [];
1361
1369
  for (const name of freeVars) {
1362
1370
  const sig = signals.find((s) => s.getter === name);
@@ -1373,6 +1381,25 @@ function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
1373
1381
  envEntries.push(`${JSON.stringify(name)}: ${goExpr}`);
1374
1382
  }
1375
1383
  const envMap = `map[string]any{${envEntries.join(", ")}}`;
1384
+ return `${evalFunc}(${itemsGo}, "${escapeGoString(projJSON)}", ${JSON.stringify(paramName)}, ${envMap})`;
1385
+ }
1386
+ function resolveMapChainAsGo(ctx, expr, signals, propsParams, propFallbackVars) {
1387
+ const cb = asCallbackMethodCall(expr);
1388
+ if (cb && cb.method in CALLBACK_EVAL_FUNC) {
1389
+ const innerGo = resolveMapChainAsGo(ctx, cb.object, signals, propsParams, propFallbackVars);
1390
+ if (innerGo === null)
1391
+ return null;
1392
+ return callbackStepToGo(ctx, cb.method, innerGo, cb.arrow, signals, propsParams, propFallbackVars);
1393
+ }
1394
+ return resolveMapJoinBaseAsGo(ctx, expr, signals, propsParams);
1395
+ }
1396
+ function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
1397
+ const itemsGo = resolveMapChainAsGo(ctx, chain.object, signals, propsParams, propFallbackVars);
1398
+ if (itemsGo === null)
1399
+ return null;
1400
+ const mapGo = callbackStepToGo(ctx, "map", itemsGo, chain.arrow, signals, propsParams, propFallbackVars);
1401
+ if (mapGo === null)
1402
+ return null;
1376
1403
  let sepGo;
1377
1404
  if (!chain.sepArg) {
1378
1405
  sepGo = JSON.stringify(",");
@@ -1381,7 +1408,7 @@ function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
1381
1408
  } else {
1382
1409
  return null;
1383
1410
  }
1384
- return `bf.Join(bf.MapEval(${itemsGo}, "${escapeGoString(projJSON)}", ${JSON.stringify(paramName)}, ${envMap}), ${sepGo})`;
1411
+ return `bf.Join(${mapGo}, ${sepGo})`;
1385
1412
  }
1386
1413
 
1387
1414
  // src/adapter/memo/memo-type.ts
@@ -1670,6 +1697,8 @@ function computeObjectMemoInitialValue(ctx, memo) {
1670
1697
  const env = { searchParamsVars: new Set, params: new Map };
1671
1698
  const entries = [];
1672
1699
  for (const prop of retObj.properties) {
1700
+ if (prop.kind === "spread")
1701
+ return null;
1673
1702
  if (prop.shorthand)
1674
1703
  return null;
1675
1704
  if (prop.keyKind !== undefined && prop.keyKind !== "identifier" && prop.keyKind !== "string") {
@@ -1801,6 +1830,8 @@ function recordIndexInterpolationToGo(ctx, node, propNames, localKeyBindings) {
1801
1830
  return null;
1802
1831
  const entries = [];
1803
1832
  for (const prop of parsedConst.properties) {
1833
+ if (prop.kind === "spread")
1834
+ return null;
1804
1835
  const v = prop.value;
1805
1836
  if (v.kind === "literal" && v.literalType === "number") {
1806
1837
  entries.push({ key: prop.key, value: { kind: "number", text: v.raw ?? String(v.value) } });
@@ -2127,6 +2158,12 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
2127
2158
  if (concatGo !== null)
2128
2159
  return concatGo;
2129
2160
  }
2161
+ const bareChain = matchMapJoinChain(body);
2162
+ if (bareChain) {
2163
+ const chainGo = mapJoinChainToGo(ctx, bareChain, signals, propsParams, propFallbackVars);
2164
+ if (chainGo !== null)
2165
+ return chainGo;
2166
+ }
2130
2167
  return null;
2131
2168
  }
2132
2169
  function resolveStringConcatChainGo(ctx, expr, signals, propsParams, propFallbackVars, propRef) {
@@ -2298,7 +2335,7 @@ function collectPropsReadByCtorInit(body, propsObjectName, propNames) {
2298
2335
  return;
2299
2336
  case "object-literal":
2300
2337
  for (const p of e.properties)
2301
- visit(p.value, bound);
2338
+ visit(p.kind === "spread" ? p.expr : p.value, bound);
2302
2339
  return;
2303
2340
  case "array-method":
2304
2341
  visit(e.object, bound);
@@ -2410,6 +2447,8 @@ function parsedObjectLiteralToGoMap(parsed) {
2410
2447
  return null;
2411
2448
  const entries = [];
2412
2449
  for (const prop of parsed.properties) {
2450
+ if (prop.kind === "spread")
2451
+ return null;
2413
2452
  if (prop.keyKind === "numeric")
2414
2453
  return null;
2415
2454
  const v = prop.value;
@@ -2534,6 +2573,8 @@ function conditionToGoBool(condition, ir) {
2534
2573
  function objectLiteralToGoSpreadMap(ctx, obj, ir) {
2535
2574
  const entries = [];
2536
2575
  for (const prop of obj.properties) {
2576
+ if (prop.kind === "spread")
2577
+ return null;
2537
2578
  if (prop.shorthand)
2538
2579
  return null;
2539
2580
  if (prop.keyKind === "numeric")
@@ -2677,7 +2718,18 @@ function collectNullishConsumedPropNames(ctx, ir) {
2677
2718
  };
2678
2719
  walk(ir.root);
2679
2720
  for (const signal of ir.metadata.signals) {
2680
- const match = ctx.extractPropFallback(signal.initialValue, resolveSignalParsedThroughSeedPlan(ctx.state, signal));
2721
+ const resolvedParsed = resolveSignalParsedThroughSeedPlan(ctx.state, signal);
2722
+ let match = ctx.extractPropFallback(signal.initialValue, resolvedParsed);
2723
+ if (!match) {
2724
+ const collision = ctx.extractCollisionDerivation(resolvedParsed);
2725
+ if (collision) {
2726
+ const collisionParam = ir.metadata.propsParams.find((p) => p.name === collision.propName);
2727
+ const collisionField = collisionParam ? capitalizeFieldName(collisionParam.sourceName ?? collision.propName) : null;
2728
+ if (collisionField && capitalizeFieldName(signal.getter) === collisionField) {
2729
+ match = { propName: collision.propName, goFallback: collision.goFallback };
2730
+ }
2731
+ }
2732
+ }
2681
2733
  if (!match || !optionalParams.has(match.propName))
2682
2734
  continue;
2683
2735
  const f = match.goFallback;
@@ -2863,6 +2915,7 @@ class GoTemplateAdapter extends BaseAdapter {
2863
2915
  convertConditionToGo: (jsCondition, preParsed) => this.convertConditionToGo(jsCondition, preParsed),
2864
2916
  extractPropNameFromInitialValue: (initialValue, preParsed) => this.extractPropNameFromInitialValue(initialValue, preParsed),
2865
2917
  extractPropFallback: (initialValue, preParsed) => this.extractPropFallback(initialValue, preParsed),
2918
+ extractCollisionDerivation: (parsed) => this.extractCollisionDerivation(parsed),
2866
2919
  resolveModuleStringConst: (name) => this.resolveModuleStringConst(name)
2867
2920
  };
2868
2921
  get errors() {
@@ -3338,6 +3391,8 @@ ${goFields.join(`
3338
3391
  return null;
3339
3392
  const seen = new Set;
3340
3393
  for (const prop of el.properties) {
3394
+ if (prop.kind === "spread")
3395
+ return null;
3341
3396
  if (prop.shorthand)
3342
3397
  return null;
3343
3398
  const key = prop.key;
@@ -3641,6 +3696,7 @@ ${goFields.join(`
3641
3696
  }
3642
3697
  lines.push("");
3643
3698
  }
3699
+ this.emitCallerPropsInit(lines, ir, nestedComponents, staticWithoutBody, staticWithBody, dynamicWithBody, emittedWrapperVars, propTypeOverrides);
3644
3700
  lines.push(` return ${propsTypeName}{`);
3645
3701
  lines.push("\t\tScopeID: scopeID,");
3646
3702
  lines.push("\t\tBfParent: in.BfParent,");
@@ -3648,6 +3704,7 @@ ${goFields.join(`
3648
3704
  if (this.usesSearchParams(ir)) {
3649
3705
  lines.push("\t\tSearchParams: in.SearchParams,");
3650
3706
  }
3707
+ lines.push("\t\tBfCallerProps: bfCallerProps,");
3651
3708
  const nestedArrayFields = this.propDerivedNestedArrayFields(nestedComponents);
3652
3709
  const memoFallbacks = new Map;
3653
3710
  for (const memo of ir.metadata.memos) {
@@ -3673,7 +3730,8 @@ ${goFields.join(`
3673
3730
  continue;
3674
3731
  const hoisted = propFallbackVars.get(param.name);
3675
3732
  if (hoisted) {
3676
- lines.push(` ${fieldName}: ${hoisted.varName},`);
3733
+ const value = hoisted.collisionWrap ? `${hoisted.varName} ${hoisted.collisionWrap.operator} ${hoisted.collisionWrap.operand}` : hoisted.varName;
3734
+ lines.push(` ${fieldName}: ${value},`);
3677
3735
  } else {
3678
3736
  const paramDefault = goPropDefault(param.defaultValue);
3679
3737
  const memoFold = memoFallbacks.get(fieldName);
@@ -3752,6 +3810,53 @@ ${goFields.join(`
3752
3810
  lines.push("\t}");
3753
3811
  lines.push("}");
3754
3812
  }
3813
+ emitCallerPropsInit(lines, ir, nestedComponents, staticWithoutBody, staticWithBody, dynamicWithBody, emittedWrapperVars, propTypeOverrides) {
3814
+ lines.push("\tbfCallerProps := map[string]interface{}{}");
3815
+ const bfCallerPropsTakenTags = new Set;
3816
+ const nestedArrayFields = this.propDerivedNestedArrayFields(nestedComponents);
3817
+ for (const param of ir.metadata.propsParams) {
3818
+ if (param.name === "children")
3819
+ continue;
3820
+ if (this.isNestedArrayShadowed(param, nestedArrayFields))
3821
+ continue;
3822
+ const callerKey = this.claimJsonTag(this.toJsonTag(param.sourceName ?? param.name), bfCallerPropsTakenTags);
3823
+ if (callerKey === "-")
3824
+ continue;
3825
+ const inputField = `in.${capitalizeFieldName(param.sourceName ?? param.name)}`;
3826
+ const goType = resolvePropGoType(this.emitCtx, param, propTypeOverrides);
3827
+ const isNillable = goType === "interface{}" || goType === "map[string]interface{}" || goType.startsWith("[]");
3828
+ if (param.optional && isNillable) {
3829
+ lines.push(` if ${inputField} != nil {`);
3830
+ lines.push(` bfCallerProps["${callerKey}"] = ${inputField}`);
3831
+ lines.push(` }`);
3832
+ } else {
3833
+ lines.push(` bfCallerProps["${callerKey}"] = ${inputField}`);
3834
+ }
3835
+ }
3836
+ for (const nested of [...staticWithoutBody, ...staticWithBody, ...dynamicWithBody]) {
3837
+ if (!nested.isPropDerived)
3838
+ continue;
3839
+ const varName = `${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`;
3840
+ const isBuilt = staticWithoutBody.includes(nested) || emittedWrapperVars.has(varName);
3841
+ if (!isBuilt)
3842
+ continue;
3843
+ const arrayFieldName = capitalizeFieldName(`${nested.name}s`);
3844
+ const param = ir.metadata.propsParams.find((p) => capitalizeFieldName(p.name) === arrayFieldName || capitalizeFieldName(p.sourceName ?? p.name) === arrayFieldName);
3845
+ if (!param || !this.isNestedArrayShadowed(param, nestedArrayFields))
3846
+ continue;
3847
+ const callerKey = this.claimJsonTag(this.toJsonTag(param.sourceName ?? param.name), bfCallerPropsTakenTags);
3848
+ if (callerKey === "-")
3849
+ continue;
3850
+ if (param.optional) {
3851
+ lines.push(` if in.${nested.name}s != nil {`);
3852
+ lines.push(` bfCallerProps["${callerKey}"] = ${varName}`);
3853
+ lines.push(` }`);
3854
+ } else {
3855
+ lines.push(` bfCallerProps["${callerKey}"] = ${varName}`);
3856
+ }
3857
+ }
3858
+ lines.push("");
3859
+ }
3755
3860
  emitStaticChildInstances(lines, ir) {
3756
3861
  const staticChildren = this.collectStaticChildInstances(ir.root, ir.metadata.propsParams);
3757
3862
  for (const child of staticChildren) {
@@ -4203,6 +4308,7 @@ ${goFields.join(`
4203
4308
  if (this.usesSearchParams(ir)) {
4204
4309
  lines.push('\tSearchParams bf.SearchParams `json:"-"`');
4205
4310
  }
4311
+ lines.push('\tBfCallerProps map[string]interface{} `json:"-"`');
4206
4312
  }
4207
4313
  emitPropsDataFields(lines, ir, nestedComponents, propTypeOverrides, takenJsonTags) {
4208
4314
  const nestedArrayFields = this.propDerivedNestedArrayFields(nestedComponents);
@@ -4458,6 +4564,8 @@ ${goFields.join(`
4458
4564
  return null;
4459
4565
  const entries = [];
4460
4566
  for (const prop of parsed.properties) {
4567
+ if (prop.kind === "spread")
4568
+ return null;
4461
4569
  if (prop.shorthand)
4462
4570
  return null;
4463
4571
  const goVal = this.lowerProviderMapMemberValue(prop.value, propsParams);
@@ -4614,7 +4722,19 @@ ${goFields.join(`
4614
4722
  }
4615
4723
  const propTypeOverrides = buildPropTypeOverrides(this.emitCtx, ir);
4616
4724
  for (const signal of ir.metadata.signals) {
4617
- const match = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
4725
+ let match = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
4726
+ let collisionWrap;
4727
+ if (!match) {
4728
+ const collision = this.extractCollisionDerivation(this.resolvedSignalParsed(signal));
4729
+ if (collision) {
4730
+ const collisionParam = ir.metadata.propsParams.find((p) => p.name === collision.propName);
4731
+ const collisionField = collisionParam ? capitalizeFieldName(collisionParam.sourceName ?? collision.propName) : null;
4732
+ if (collisionField && capitalizeFieldName(signal.getter) === collisionField) {
4733
+ match = { propName: collision.propName, goFallback: collision.goFallback };
4734
+ collisionWrap = { operator: collision.operator, operand: collision.operand };
4735
+ }
4736
+ }
4737
+ }
4618
4738
  if (!match)
4619
4739
  continue;
4620
4740
  if (result.has(match.propName))
@@ -4653,7 +4773,8 @@ ${goFields.join(`
4653
4773
  fieldName,
4654
4774
  goFallback: match.goFallback,
4655
4775
  zeroLiteral,
4656
- ...nullishLowered ? { assertType: concreteType } : {}
4776
+ ...nullishLowered ? { assertType: concreteType } : {},
4777
+ ...collisionWrap ? { collisionWrap } : {}
4657
4778
  });
4658
4779
  }
4659
4780
  return result;
@@ -4703,6 +4824,26 @@ ${goFields.join(`
4703
4824
  return null;
4704
4825
  return { propName, goFallback };
4705
4826
  }
4827
+ extractCollisionDerivation(parsed) {
4828
+ if (!parsed || parsed.kind !== "binary")
4829
+ return null;
4830
+ if (!["*", "+", "-", "/"].includes(parsed.op))
4831
+ return null;
4832
+ const { right } = parsed;
4833
+ if (right.kind !== "literal" || right.literalType !== "number" || typeof right.value !== "number" || !Number.isInteger(right.value) || right.value < 0) {
4834
+ return null;
4835
+ }
4836
+ if (parsed.op === "/" && right.value === 0)
4837
+ return null;
4838
+ const coalesce = parsed.left;
4839
+ if (coalesce.kind !== "logical" || coalesce.op !== "??" || coalesce.right.kind !== "literal" || coalesce.right.literalType !== "number") {
4840
+ return null;
4841
+ }
4842
+ const inner = this.extractPropFallbackFromParsed(parsed.left);
4843
+ if (!inner)
4844
+ return null;
4845
+ return { ...inner, operator: parsed.op, operand: String(right.value) };
4846
+ }
4706
4847
  extractPropNameFromInitialValue(initialValue, preParsed) {
4707
4848
  if (!this.state.propsObjectName) {
4708
4849
  if (preParsed?.kind === "logical" && (preParsed.op === "??" || preParsed.op === "||") && preParsed.left.kind === "identifier") {
@@ -5191,7 +5332,16 @@ ${goFields.join(`
5191
5332
  });
5192
5333
  return `bf_arr ${parts.join(" ")}`;
5193
5334
  }
5194
- objectLiteral(_properties, raw, _emit) {
5335
+ objectLiteral(properties, raw, emit) {
5336
+ if (properties.length > 0) {
5337
+ const wrap = (rendered) => rendered.includes(" ") ? `(${rendered})` : rendered;
5338
+ const literalOf = (run) => `bf_map ${run.map((p) => `"${escapeGoString(p.key)}" ${wrap(emit(p.value))}`).join(" ")}`;
5339
+ if (!properties.some((p) => p.kind === "spread")) {
5340
+ return literalOf(properties);
5341
+ }
5342
+ const segments = groupObjectLiteralSegments(properties, literalOf, (e) => wrap(emit(e)));
5343
+ return `bf_merge ${segments.join(" ")}`;
5344
+ }
5195
5345
  this.state.errors.push({
5196
5346
  code: "BF101",
5197
5347
  severity: "error",
@@ -5914,7 +6064,7 @@ ${goFields.join(`
5914
6064
  return null;
5915
6065
  const carried = constInfo.parsed;
5916
6066
  if (carried?.kind === "object-literal") {
5917
- const hit = carried.properties.find((prop) => prop.key === key);
6067
+ const hit = carried.properties.find((prop) => prop.kind === "prop" && prop.key === key);
5918
6068
  if (hit && hit.value.kind === "literal") {
5919
6069
  if (hit.value.literalType === "string")
5920
6070
  return JSON.stringify(hit.value.value);
@@ -6758,8 +6908,7 @@ var conformancePins = {
6758
6908
  };
6759
6909
  // src/render-divergences.ts
6760
6910
  var renderDivergences = {
6761
- "signal-prop-same-name-derived": "self-derived signal collides with its prop field name in the generated Go props struct — the non-idempotent `* 2` derivation is dropped and the signal renders the raw prop value instead (https://github.com/piconic-ai/barefootjs/issues/2683)",
6762
- "signal-prop-same-name-via-const-derived": "self-derived signal (reached through a component-scope const) collides with its prop field name in the generated Go props struct — the non-idempotent `* 2` derivation is dropped and the signal renders the raw prop value instead (https://github.com/piconic-ai/barefootjs/issues/2683)"
6911
+ "signal-object-spread-init": "PRE-EXISTING, unrelated to the #2696 Step 2 spread work this fixture pins: a `derived`-classified signal/memo whose value is an OBJECT literal has no live-template-expression lowering on Gounlike the other six template-stash backends (e.g. minijinja emits `{% set merged = dict(base, done=true) %}`), Go always bakes an object-typed signal/memo field into Go SOURCE at `NewXxxProps` constructor time (`convertInitialValue`/`parsedLiteralToGo`), and that baker is STATIC-only (identifier/call/member operands defer, `parsed-literal-to-go.ts`'s own docstring) — it cannot reference a live prop at all. Reproduced identically with the spread REMOVED (`createSignal({ id: base.id, done: true })`), confirming the gap predates and is independent of spread: the signal seeds `nil` and every field read (`.Merged.ID`/`.Merged.Done`) reads the Go zero value regardless of `initialTodos`. Graduate by teaching the baker to emit prop-referencing Go expressions (https://github.com/piconic-ai/barefootjs/issues/2700)."
6763
6912
  };
6764
6913
  export {
6765
6914
  renderDivergences,
@@ -1 +1 @@
1
- {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAwB/B,CAAA"}
1
+ {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAG/B,CAAA"}