@barefootjs/go-template 0.32.0 → 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.
package/dist/vite.js CHANGED
@@ -209,7 +209,7 @@ function convertNode(node, raw) {
209
209
  }
210
210
  if (n === undefined || Number.isNaN(n)) {
211
211
  const parsedDepth = convertNode(depthNode, raw);
212
- if (checkSupport(parsedDepth).supported) {
212
+ if (checkSupport(parsedDepth, "rendered").supported) {
213
213
  depthExpr = parsedDepth;
214
214
  flatDepth = 1;
215
215
  } else {
@@ -303,10 +303,12 @@ function convertNode(node, raw) {
303
303
  const k = objectLiteralKeyName(prop.name);
304
304
  if (k === null)
305
305
  return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts.SyntaxKind[node.kind]}` };
306
- properties.push({ key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
306
+ properties.push({ kind: "prop", key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
307
307
  } else if (ts.isShorthandPropertyAssignment(prop)) {
308
308
  const key = prop.name.text;
309
- properties.push({ key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
309
+ properties.push({ kind: "prop", key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
310
+ } else if (ts.isSpreadAssignment(prop)) {
311
+ properties.push({ kind: "spread", expr: convertNode(prop.expression, raw) });
310
312
  } else {
311
313
  return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts.SyntaxKind[node.kind]}` };
312
314
  }
@@ -986,14 +988,26 @@ function getUnaryOperatorString(op) {
986
988
  }
987
989
  }
988
990
  function isSupported(expr) {
989
- return checkSupport(expr);
991
+ return checkSupport(expr, "rendered");
990
992
  }
991
- function checkSupport(expr) {
993
+ function isSupportedValue(expr) {
994
+ return checkSupport(expr, "value");
995
+ }
996
+ function checkSupport(expr, pos) {
992
997
  switch (expr.kind) {
993
998
  case "unsupported":
994
999
  return { supported: false, reason: expr.reason };
995
- case "object-literal":
996
- return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
1000
+ case "object-literal": {
1001
+ if (pos !== "value") {
1002
+ return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
1003
+ }
1004
+ for (const prop of expr.properties) {
1005
+ const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos);
1006
+ if (!propSupport.supported)
1007
+ return propSupport;
1008
+ }
1009
+ return { supported: true, level: "L2" };
1010
+ }
997
1011
  case "identifier":
998
1012
  return { supported: true, level: "L1" };
999
1013
  case "literal":
@@ -1003,7 +1017,7 @@ function checkSupport(expr) {
1003
1017
  return { supported: false, reason: "Standalone arrow functions / regex literals are not supported" };
1004
1018
  case "array-literal": {
1005
1019
  for (const el of expr.elements) {
1006
- const elSupport = checkSupport(el);
1020
+ const elSupport = checkSupport(el, pos);
1007
1021
  if (!elSupport.supported)
1008
1022
  return elSupport;
1009
1023
  }
@@ -1016,16 +1030,16 @@ function checkSupport(expr) {
1016
1030
  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 */`
1017
1031
  };
1018
1032
  }
1019
- const objSupport = checkSupport(expr.object);
1033
+ const objSupport = checkSupport(expr.object, pos);
1020
1034
  if (!objSupport.supported)
1021
1035
  return objSupport;
1022
1036
  for (const arg of expr.args) {
1023
- const argSupport = checkSupport(arg);
1037
+ const argSupport = checkSupport(arg, pos);
1024
1038
  if (!argSupport.supported)
1025
1039
  return argSupport;
1026
1040
  }
1027
1041
  if (expr.method === "flat" && expr.depthExpr) {
1028
- const depthSupport = checkSupport(expr.depthExpr);
1042
+ const depthSupport = checkSupport(expr.depthExpr, pos);
1029
1043
  if (!depthSupport.supported)
1030
1044
  return depthSupport;
1031
1045
  }
@@ -1034,10 +1048,10 @@ function checkSupport(expr) {
1034
1048
  case "call": {
1035
1049
  const cb = asCallbackMethodCall(expr);
1036
1050
  if (cb) {
1037
- const objSupport = checkSupport(cb.object);
1051
+ const objSupport = checkSupport(cb.object, pos);
1038
1052
  if (!objSupport.supported)
1039
1053
  return objSupport;
1040
- const bodySupport = checkSupport(cb.arrow.body);
1054
+ const bodySupport = checkSupport(cb.arrow.body, pos);
1041
1055
  if (!bodySupport.supported) {
1042
1056
  return {
1043
1057
  supported: false,
@@ -1046,13 +1060,13 @@ function checkSupport(expr) {
1046
1060
  };
1047
1061
  }
1048
1062
  for (const rest of cb.args) {
1049
- const restSupport = checkSupport(rest);
1063
+ const restSupport = checkSupport(rest, pos);
1050
1064
  if (!restSupport.supported)
1051
1065
  return restSupport;
1052
1066
  }
1053
1067
  return { supported: true, level: "L5" };
1054
1068
  }
1055
- const calleeSupport = checkSupport(expr.callee);
1069
+ const calleeSupport = checkSupport(expr.callee, pos);
1056
1070
  if (!calleeSupport.supported) {
1057
1071
  return calleeSupport;
1058
1072
  }
@@ -1071,7 +1085,7 @@ function checkSupport(expr) {
1071
1085
  return { supported: true, level: "L1" };
1072
1086
  }
1073
1087
  for (const arg of expr.args) {
1074
- const argSupport = checkSupport(arg);
1088
+ const argSupport = checkSupport(arg, pos);
1075
1089
  if (!argSupport.supported) {
1076
1090
  return argSupport;
1077
1091
  }
@@ -1079,7 +1093,7 @@ function checkSupport(expr) {
1079
1093
  return { supported: true, level: "L2" };
1080
1094
  }
1081
1095
  case "member": {
1082
- const objSupport = checkSupport(expr.object);
1096
+ const objSupport = checkSupport(expr.object, pos);
1083
1097
  if (!objSupport.supported) {
1084
1098
  return objSupport;
1085
1099
  }
@@ -1089,19 +1103,19 @@ function checkSupport(expr) {
1089
1103
  return { supported: true, level: "L2" };
1090
1104
  }
1091
1105
  case "index-access": {
1092
- const objSupport = checkSupport(expr.object);
1106
+ const objSupport = checkSupport(expr.object, pos);
1093
1107
  if (!objSupport.supported)
1094
1108
  return objSupport;
1095
- const indexSupport = checkSupport(expr.index);
1109
+ const indexSupport = checkSupport(expr.index, pos);
1096
1110
  if (!indexSupport.supported)
1097
1111
  return indexSupport;
1098
1112
  return { supported: true, level: "L2" };
1099
1113
  }
1100
1114
  case "binary": {
1101
- const leftSupport = checkSupport(expr.left);
1115
+ const leftSupport = checkSupport(expr.left, pos);
1102
1116
  if (!leftSupport.supported)
1103
1117
  return leftSupport;
1104
- const rightSupport = checkSupport(expr.right);
1118
+ const rightSupport = checkSupport(expr.right, pos);
1105
1119
  if (!rightSupport.supported)
1106
1120
  return rightSupport;
1107
1121
  if (["===", "==", "!==", "!=", ">", "<", ">=", "<="].includes(expr.op)) {
@@ -1113,7 +1127,7 @@ function checkSupport(expr) {
1113
1127
  return { supported: false, reason: `Unknown operator: ${expr.op}` };
1114
1128
  }
1115
1129
  case "unary": {
1116
- const argSupport = checkSupport(expr.argument);
1130
+ const argSupport = checkSupport(expr.argument, pos);
1117
1131
  if (!argSupport.supported)
1118
1132
  return argSupport;
1119
1133
  if (expr.op === "!") {
@@ -1125,25 +1139,25 @@ function checkSupport(expr) {
1125
1139
  return { supported: false, reason: `Unsupported unary operator: ${expr.op}` };
1126
1140
  }
1127
1141
  case "logical": {
1128
- const leftSupport = checkSupport(expr.left);
1142
+ const leftSupport = checkSupport(expr.left, pos);
1129
1143
  if (!leftSupport.supported)
1130
1144
  return leftSupport;
1131
1145
  if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
1132
1146
  return { supported: true, level: "L4" };
1133
1147
  }
1134
- const rightSupport = checkSupport(expr.right);
1148
+ const rightSupport = checkSupport(expr.right, pos);
1135
1149
  if (!rightSupport.supported)
1136
1150
  return rightSupport;
1137
1151
  return { supported: true, level: "L4" };
1138
1152
  }
1139
1153
  case "conditional": {
1140
- const testSupport = checkSupport(expr.test);
1154
+ const testSupport = checkSupport(expr.test, pos);
1141
1155
  if (!testSupport.supported)
1142
1156
  return testSupport;
1143
- const consSupport = checkSupport(expr.consequent);
1157
+ const consSupport = checkSupport(expr.consequent, pos);
1144
1158
  if (!consSupport.supported)
1145
1159
  return consSupport;
1146
- const altSupport = checkSupport(expr.alternate);
1160
+ const altSupport = checkSupport(expr.alternate, pos);
1147
1161
  if (!altSupport.supported)
1148
1162
  return altSupport;
1149
1163
  return { supported: true, level: "L4" };
@@ -1151,7 +1165,7 @@ function checkSupport(expr) {
1151
1165
  case "template-literal": {
1152
1166
  for (const part of expr.parts) {
1153
1167
  if (part.type === "expression") {
1154
- const partSupport = checkSupport(part.expr);
1168
+ const partSupport = checkSupport(part.expr, pos);
1155
1169
  if (!partSupport.supported)
1156
1170
  return partSupport;
1157
1171
  }
@@ -1267,7 +1281,7 @@ function isPureInit(e, pureCallNames) {
1267
1281
  case "array-literal":
1268
1282
  return e.elements.every(pure);
1269
1283
  case "object-literal":
1270
- return e.properties.every((p) => pure(p.value));
1284
+ return e.properties.every((p) => pure(p.kind === "spread" ? p.expr : p.value));
1271
1285
  case "call":
1272
1286
  return e.callee.kind === "identifier" && e.args.length === 0 && pureCallNames !== undefined && pureCallNames.has(e.callee.name);
1273
1287
  case "array-method":
@@ -1321,7 +1335,7 @@ function usesPerPath(name, expr) {
1321
1335
  }
1322
1336
  return add(walk(e.object), sum(e.args));
1323
1337
  case "object-literal":
1324
- return sum(e.properties.map((p) => p.value));
1338
+ return sum(e.properties.map((p) => p.kind === "spread" ? p.expr : p.value));
1325
1339
  case "arrow":
1326
1340
  return walk(e.body).max > 0 ? { min: 0, max: Number.POSITIVE_INFINITY } : { min: 0, max: 0 };
1327
1341
  }
@@ -1387,7 +1401,7 @@ function inlineBinding(expr, name, value) {
1387
1401
  case "object-literal":
1388
1402
  return {
1389
1403
  kind: "object-literal",
1390
- properties: e.properties.map((p) => ({ ...p, value: walk(p.value, enclosing) })),
1404
+ properties: e.properties.map((p) => p.kind === "spread" ? { ...p, expr: walk(p.expr, enclosing) } : { ...p, value: walk(p.value, enclosing) }),
1391
1405
  raw: e.raw
1392
1406
  };
1393
1407
  case "literal":
@@ -1597,7 +1611,7 @@ function materializeGetterCalls(expr, names) {
1597
1611
  return {
1598
1612
  kind: "object-literal",
1599
1613
  raw: expr.raw,
1600
- properties: expr.properties.map((p) => ({ ...p, value: rw(p.value) }))
1614
+ properties: expr.properties.map((p) => p.kind === "spread" ? { ...p, expr: rw(p.expr) } : { ...p, value: rw(p.value) })
1601
1615
  };
1602
1616
  case "arrow":
1603
1617
  return { kind: "arrow", params: expr.params, body: rw(expr.body) };
@@ -1655,7 +1669,7 @@ function freeVarsInBody(body, params) {
1655
1669
  return;
1656
1670
  case "object-literal":
1657
1671
  for (const p of e.properties)
1658
- visit(p.value, bound);
1672
+ visit(p.kind === "spread" ? p.expr : p.value, bound);
1659
1673
  return;
1660
1674
  case "array-method":
1661
1675
  if (e.method === "includes" || e.method === "join") {
@@ -1730,7 +1744,7 @@ function freeIdentifiers(expr) {
1730
1744
  return true;
1731
1745
  case "object-literal":
1732
1746
  for (const p of e.properties)
1733
- if (!visit(p.value, bound))
1747
+ if (!visit(p.kind === "spread" ? p.expr : p.value, bound))
1734
1748
  return false;
1735
1749
  return true;
1736
1750
  case "arrow": {
@@ -1877,10 +1891,17 @@ function toEvalNode(e) {
1877
1891
  case "object-literal": {
1878
1892
  const properties = [];
1879
1893
  for (const p of e.properties) {
1894
+ if (p.kind === "spread") {
1895
+ const spreadExpr = toEvalNode(p.expr);
1896
+ if (!spreadExpr)
1897
+ return null;
1898
+ properties.push({ kind: "spread", expr: spreadExpr });
1899
+ continue;
1900
+ }
1880
1901
  const value = toEvalNode(p.value);
1881
1902
  if (!value)
1882
1903
  return null;
1883
- properties.push({ key: p.key, value });
1904
+ properties.push({ kind: "prop", key: p.key, value });
1884
1905
  }
1885
1906
  return { kind: "object-literal", properties };
1886
1907
  }
@@ -2985,6 +3006,8 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
2985
3006
  let tz = null;
2986
3007
  const probeOptions = {};
2987
3008
  for (const prop of options.properties) {
3009
+ if (prop.kind === "spread")
3010
+ return null;
2988
3011
  if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
2989
3012
  return null;
2990
3013
  const value = String(prop.value.value);
@@ -3918,7 +3941,7 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
3918
3941
 
3919
3942
  // ../jsx/src/ssr-seed-plan.ts
3920
3943
  function classify(name, origin, expr, parsed, available) {
3921
- if (!isSupported(parsed).supported)
3944
+ if (!isSupportedValue(parsed).supported)
3922
3945
  return { kind: "opaque", name, origin };
3923
3946
  const frees = freeIdentifiers(parsed);
3924
3947
  if (frees === null)
@@ -3981,7 +4004,7 @@ function computeSsrSeedPlan(metadata) {
3981
4004
  }
3982
4005
  }
3983
4006
  const expr = signal.initialValue.trim();
3984
- steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
4007
+ steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(signal.parsed ?? parseExpression(`(${expr})`), localConsts), available));
3985
4008
  available.add(signal.getter);
3986
4009
  }
3987
4010
  for (const memo of metadata.memos) {
@@ -4605,6 +4628,26 @@ function isStringTypedOperand(expr, isStringName) {
4605
4628
  function isStringConcatBinary(op, left, right, isStringName) {
4606
4629
  return op === "+" && (isStringTypedOperand(left, isStringName) || isStringTypedOperand(right, isStringName));
4607
4630
  }
4631
+ function groupObjectLiteralSegments(properties, literalOf, emit) {
4632
+ const segments = [];
4633
+ let run = [];
4634
+ const flushRun = () => {
4635
+ if (run.length > 0) {
4636
+ segments.push(literalOf(run));
4637
+ run = [];
4638
+ }
4639
+ };
4640
+ for (const p of properties) {
4641
+ if (p.kind === "spread") {
4642
+ flushRun();
4643
+ segments.push(emit(p.expr));
4644
+ } else {
4645
+ run.push(p);
4646
+ }
4647
+ }
4648
+ flushRun();
4649
+ return segments;
4650
+ }
4608
4651
  function emitParsedExpr(expr, emitter) {
4609
4652
  const emit = (child) => emitParsedExpr(child, emitter);
4610
4653
  switch (expr.kind) {
@@ -4751,6 +4794,17 @@ function evaluateStaticLiteral(expr, bindings) {
4751
4794
  case "object-literal": {
4752
4795
  const out = {};
4753
4796
  for (const prop of expr.properties) {
4797
+ if (prop.kind === "spread") {
4798
+ const resolved2 = evaluateStaticLiteral(prop.expr, bindings);
4799
+ if (!resolved2)
4800
+ return null;
4801
+ if (resolved2.value === null || resolved2.value === undefined)
4802
+ continue;
4803
+ if (typeof resolved2.value !== "object" || Array.isArray(resolved2.value))
4804
+ return null;
4805
+ Object.assign(out, resolved2.value);
4806
+ continue;
4807
+ }
4754
4808
  const resolved = evaluateStaticLiteral(prop.value, bindings);
4755
4809
  if (!resolved)
4756
4810
  return null;
@@ -4817,6 +4871,8 @@ function matchQueryHrefCall(callee, args, localNames) {
4817
4871
  return null;
4818
4872
  const triples = [];
4819
4873
  for (const p of obj.properties) {
4874
+ if (p.kind === "spread")
4875
+ return null;
4820
4876
  const v = p.value;
4821
4877
  if (v.kind === "conditional" && isOmitBranch(v.alternate)) {
4822
4878
  triples.push({ guard: v.test, key: p.key, value: v.consequent });
@@ -4980,6 +5036,8 @@ function htmlPropValue(parsed) {
4980
5036
  if (parsed.properties.length !== 1)
4981
5037
  return null;
4982
5038
  const [prop] = parsed.properties;
5039
+ if (prop.kind === "spread")
5040
+ return null;
4983
5041
  if (prop.key !== "__html")
4984
5042
  return null;
4985
5043
  return prop.value;
@@ -5849,7 +5907,7 @@ function isSubstituteSafeBody(body, paramNames) {
5849
5907
  if (n.kind === "identifier")
5850
5908
  return paramNames.has(n.name);
5851
5909
  if (n.kind === "object-literal") {
5852
- return n.properties.some((p) => p.shorthand && paramNames.has(p.key) || referencesParam(p.value));
5910
+ return n.properties.some((p) => p.kind === "spread" ? referencesParam(p.expr) : p.shorthand && paramNames.has(p.key) || referencesParam(p.value));
5853
5911
  }
5854
5912
  let hit = false;
5855
5913
  forEachValueChild(n, (c) => {
@@ -6204,6 +6262,8 @@ function bakeInlineObjectAsGoMap(ctx, expr) {
6204
6262
  return null;
6205
6263
  const entries = [];
6206
6264
  for (const prop of expr.properties) {
6265
+ if (prop.kind === "spread")
6266
+ return null;
6207
6267
  if (prop.shorthand)
6208
6268
  return null;
6209
6269
  const go = prop.value.kind === "object-literal" ? bakeInlineObjectAsGoMap(ctx, prop.value) : parsedLiteralToGo(ctx, prop.value);
@@ -6259,6 +6319,8 @@ function parsedLiteralToGo(ctx, expr, typeInfo) {
6259
6319
  return null;
6260
6320
  const entries = [];
6261
6321
  for (const prop of expr.properties) {
6322
+ if (prop.kind === "spread")
6323
+ return null;
6262
6324
  const goField = structFields.get(prop.key);
6263
6325
  if (!goField)
6264
6326
  return null;
@@ -6380,6 +6442,8 @@ function objectLiteralToGoMap(ctx, expr) {
6380
6442
  return null;
6381
6443
  const entries = [];
6382
6444
  for (const prop of expr.properties) {
6445
+ if (prop.kind === "spread")
6446
+ return null;
6383
6447
  if (prop.shorthand)
6384
6448
  return null;
6385
6449
  const val = parsedLiteralToGo(ctx, prop.value);
@@ -6458,17 +6522,18 @@ function resolveMapJoinBaseAsGo(ctx, object, signals, propsParams) {
6458
6522
  }
6459
6523
  return null;
6460
6524
  }
6461
- function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
6462
- const itemsGo = resolveMapJoinBaseAsGo(ctx, chain.object, signals, propsParams);
6463
- if (itemsGo === null)
6525
+ var CALLBACK_EVAL_FUNC = { map: "bf.MapEval", filter: "bf.FilterEval" };
6526
+ function callbackStepToGo(ctx, method, itemsGo, arrow, signals, propsParams, propFallbackVars) {
6527
+ const evalFunc = CALLBACK_EVAL_FUNC[method];
6528
+ if (!evalFunc)
6464
6529
  return null;
6465
6530
  const knownGetterNames = new Set(signals.map((s) => s.getter));
6466
- const materialized = materializeGetterCalls(chain.arrow.body, knownGetterNames);
6531
+ const materialized = materializeGetterCalls(arrow.body, knownGetterNames);
6467
6532
  const projJSON = serializeParsedExpr(materialized);
6468
6533
  if (projJSON === null)
6469
6534
  return null;
6470
- const paramName = chain.arrow.params[0] ?? "_";
6471
- const freeVars = freeVarsInBody(materialized, new Set(chain.arrow.params));
6535
+ const paramName = arrow.params[0] ?? "_";
6536
+ const freeVars = freeVarsInBody(materialized, new Set(arrow.params));
6472
6537
  const envEntries = [];
6473
6538
  for (const name of freeVars) {
6474
6539
  const sig = signals.find((s) => s.getter === name);
@@ -6485,6 +6550,25 @@ function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
6485
6550
  envEntries.push(`${JSON.stringify(name)}: ${goExpr}`);
6486
6551
  }
6487
6552
  const envMap = `map[string]any{${envEntries.join(", ")}}`;
6553
+ return `${evalFunc}(${itemsGo}, "${escapeGoString(projJSON)}", ${JSON.stringify(paramName)}, ${envMap})`;
6554
+ }
6555
+ function resolveMapChainAsGo(ctx, expr, signals, propsParams, propFallbackVars) {
6556
+ const cb = asCallbackMethodCall(expr);
6557
+ if (cb && cb.method in CALLBACK_EVAL_FUNC) {
6558
+ const innerGo = resolveMapChainAsGo(ctx, cb.object, signals, propsParams, propFallbackVars);
6559
+ if (innerGo === null)
6560
+ return null;
6561
+ return callbackStepToGo(ctx, cb.method, innerGo, cb.arrow, signals, propsParams, propFallbackVars);
6562
+ }
6563
+ return resolveMapJoinBaseAsGo(ctx, expr, signals, propsParams);
6564
+ }
6565
+ function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
6566
+ const itemsGo = resolveMapChainAsGo(ctx, chain.object, signals, propsParams, propFallbackVars);
6567
+ if (itemsGo === null)
6568
+ return null;
6569
+ const mapGo = callbackStepToGo(ctx, "map", itemsGo, chain.arrow, signals, propsParams, propFallbackVars);
6570
+ if (mapGo === null)
6571
+ return null;
6488
6572
  let sepGo;
6489
6573
  if (!chain.sepArg) {
6490
6574
  sepGo = JSON.stringify(",");
@@ -6493,7 +6577,7 @@ function mapJoinChainToGo(ctx, chain, signals, propsParams, propFallbackVars) {
6493
6577
  } else {
6494
6578
  return null;
6495
6579
  }
6496
- return `bf.Join(bf.MapEval(${itemsGo}, "${escapeGoString(projJSON)}", ${JSON.stringify(paramName)}, ${envMap}), ${sepGo})`;
6580
+ return `bf.Join(${mapGo}, ${sepGo})`;
6497
6581
  }
6498
6582
 
6499
6583
  // src/adapter/memo/memo-type.ts
@@ -6780,6 +6864,8 @@ function computeObjectMemoInitialValue(ctx, memo) {
6780
6864
  const env = { searchParamsVars: new Set, params: new Map };
6781
6865
  const entries = [];
6782
6866
  for (const prop of retObj.properties) {
6867
+ if (prop.kind === "spread")
6868
+ return null;
6783
6869
  if (prop.shorthand)
6784
6870
  return null;
6785
6871
  if (prop.keyKind !== undefined && prop.keyKind !== "identifier" && prop.keyKind !== "string") {
@@ -6903,6 +6989,8 @@ function recordIndexInterpolationToGo(ctx, node, propNames, localKeyBindings) {
6903
6989
  return null;
6904
6990
  const entries = [];
6905
6991
  for (const prop of parsedConst.properties) {
6992
+ if (prop.kind === "spread")
6993
+ return null;
6906
6994
  const v = prop.value;
6907
6995
  if (v.kind === "literal" && v.literalType === "number") {
6908
6996
  entries.push({ key: prop.key, value: { kind: "number", text: v.raw ?? String(v.value) } });
@@ -7229,6 +7317,12 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
7229
7317
  if (concatGo !== null)
7230
7318
  return concatGo;
7231
7319
  }
7320
+ const bareChain = matchMapJoinChain(body);
7321
+ if (bareChain) {
7322
+ const chainGo = mapJoinChainToGo(ctx, bareChain, signals, propsParams, propFallbackVars);
7323
+ if (chainGo !== null)
7324
+ return chainGo;
7325
+ }
7232
7326
  return null;
7233
7327
  }
7234
7328
  function resolveStringConcatChainGo(ctx, expr, signals, propsParams, propFallbackVars, propRef) {
@@ -7400,7 +7494,7 @@ function collectPropsReadByCtorInit(body, propsObjectName, propNames) {
7400
7494
  return;
7401
7495
  case "object-literal":
7402
7496
  for (const p of e.properties)
7403
- visit(p.value, bound);
7497
+ visit(p.kind === "spread" ? p.expr : p.value, bound);
7404
7498
  return;
7405
7499
  case "array-method":
7406
7500
  visit(e.object, bound);
@@ -7511,6 +7605,8 @@ function parsedObjectLiteralToGoMap(parsed) {
7511
7605
  return null;
7512
7606
  const entries = [];
7513
7607
  for (const prop of parsed.properties) {
7608
+ if (prop.kind === "spread")
7609
+ return null;
7514
7610
  if (prop.keyKind === "numeric")
7515
7611
  return null;
7516
7612
  const v = prop.value;
@@ -7635,6 +7731,8 @@ function conditionToGoBool(condition, ir) {
7635
7731
  function objectLiteralToGoSpreadMap(ctx, obj, ir) {
7636
7732
  const entries = [];
7637
7733
  for (const prop of obj.properties) {
7734
+ if (prop.kind === "spread")
7735
+ return null;
7638
7736
  if (prop.shorthand)
7639
7737
  return null;
7640
7738
  if (prop.keyKind === "numeric")
@@ -8449,6 +8547,8 @@ ${goFields.join(`
8449
8547
  return null;
8450
8548
  const seen = new Set;
8451
8549
  for (const prop of el.properties) {
8550
+ if (prop.kind === "spread")
8551
+ return null;
8452
8552
  if (prop.shorthand)
8453
8553
  return null;
8454
8554
  const key = prop.key;
@@ -9620,6 +9720,8 @@ ${goFields.join(`
9620
9720
  return null;
9621
9721
  const entries = [];
9622
9722
  for (const prop of parsed.properties) {
9723
+ if (prop.kind === "spread")
9724
+ return null;
9623
9725
  if (prop.shorthand)
9624
9726
  return null;
9625
9727
  const goVal = this.lowerProviderMapMemberValue(prop.value, propsParams);
@@ -10386,7 +10488,16 @@ ${goFields.join(`
10386
10488
  });
10387
10489
  return `bf_arr ${parts.join(" ")}`;
10388
10490
  }
10389
- objectLiteral(_properties, raw, _emit) {
10491
+ objectLiteral(properties, raw, emit) {
10492
+ if (properties.length > 0) {
10493
+ const wrap = (rendered) => rendered.includes(" ") ? `(${rendered})` : rendered;
10494
+ const literalOf = (run) => `bf_map ${run.map((p) => `"${escapeGoString(p.key)}" ${wrap(emit(p.value))}`).join(" ")}`;
10495
+ if (!properties.some((p) => p.kind === "spread")) {
10496
+ return literalOf(properties);
10497
+ }
10498
+ const segments = groupObjectLiteralSegments(properties, literalOf, (e) => wrap(emit(e)));
10499
+ return `bf_merge ${segments.join(" ")}`;
10500
+ }
10390
10501
  this.state.errors.push({
10391
10502
  code: "BF101",
10392
10503
  severity: "error",
@@ -11109,7 +11220,7 @@ ${goFields.join(`
11109
11220
  return null;
11110
11221
  const carried = constInfo.parsed;
11111
11222
  if (carried?.kind === "object-literal") {
11112
- const hit = carried.properties.find((prop) => prop.key === key);
11223
+ const hit = carried.properties.find((prop) => prop.kind === "prop" && prop.key === key);
11113
11224
  if (hit && hit.value.kind === "literal") {
11114
11225
  if (hit.value.literalType === "string")
11115
11226
  return JSON.stringify(hit.value.value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/go-template",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
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.32.0"
52
+ "@barefootjs/shared": "0.33.0"
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.32.0",
71
- "@barefootjs/jsx": "0.32.0",
72
- "@barefootjs/vite": "0.32.0",
70
+ "@barefootjs/client": "0.33.0",
71
+ "@barefootjs/jsx": "0.33.0",
72
+ "@barefootjs/vite": "0.33.0",
73
73
  "vite": "^6.0.0"
74
74
  }
75
75
  }
@@ -86,8 +86,10 @@ function isSubstituteSafeBody(body: ParsedExpr, paramNames: ReadonlySet<string>)
86
86
  const referencesParam = (n: ParsedExpr): boolean => {
87
87
  if (n.kind === 'identifier') return paramNames.has(n.name)
88
88
  if (n.kind === 'object-literal') {
89
- return n.properties.some(
90
- p => (p.shorthand && paramNames.has(p.key)) || referencesParam(p.value),
89
+ return n.properties.some(p =>
90
+ p.kind === 'spread'
91
+ ? referencesParam(p.expr)
92
+ : (p.shorthand && paramNames.has(p.key)) || referencesParam(p.value),
91
93
  )
92
94
  }
93
95
  let hit = false