@barefootjs/go-template 0.6.0 → 0.6.1

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.
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generates Go html/template files from BarefootJS IR.
5
5
  */
6
- import type { ComponentIR, IRNode, IRElement, IRText, IRExpression, IRConditional, IRLoop, IRComponent, IRFragment, IRSlot, ParsedExpr, SortComparator, TemplatePart, IRIfStatement, IRProvider, IRAsync, TemplatePrimitiveRegistry } from '@barefootjs/jsx';
6
+ import type { ComponentIR, IRNode, IRElement, IRText, IRExpression, IRConditional, IRLoop, IRComponent, IRFragment, IRSlot, ParsedExpr, SortComparator, ReduceOp, FlatDepth, FlatMapOp, TemplatePart, IRIfStatement, IRProvider, IRAsync, TemplatePrimitiveRegistry } from '@barefootjs/jsx';
7
7
  import { BaseAdapter, type AdapterOutput, type AdapterGenerateOptions, type ParsedExprEmitter, type HigherOrderMethod, type ArrayMethod, type LiteralType, type IRNodeEmitter, type EmitIRNode } from '@barefootjs/jsx';
8
8
  /**
9
9
  * Go-template adapter's IRNode render context. Only `isRootOfClientComponent`
@@ -469,7 +469,7 @@ export declare class GoTemplateAdapter extends BaseAdapter implements ParsedExpr
469
469
  */
470
470
  private static GO_IDENTIFIER;
471
471
  /** Go common initialisms that should be fully uppercased (https://go.dev/wiki/CodeReviewComments#initialisms) */
472
- private static GO_INITIALISMS;
472
+ static GO_INITIALISMS: Set<string>;
473
473
  /**
474
474
  * (#1423) Go reserved keywords. When we hoist a local var named after
475
475
  * a JSX prop, the prop name could collide with one of these — append
@@ -567,6 +567,9 @@ export declare class GoTemplateAdapter extends BaseAdapter implements ParsedExpr
567
567
  higherOrder(method: HigherOrderMethod, object: ParsedExpr, param: string, predicate: ParsedExpr, emit: (e: ParsedExpr) => string): string;
568
568
  arrayMethod(method: ArrayMethod, object: ParsedExpr, args: ParsedExpr[], emit: (e: ParsedExpr) => string): string;
569
569
  sortMethod(method: 'sort' | 'toSorted', object: ParsedExpr, comparator: SortComparator, emit: (e: ParsedExpr) => string): string;
570
+ reduceMethod(method: 'reduce' | 'reduceRight', object: ParsedExpr, reduceOp: ReduceOp, emit: (e: ParsedExpr) => string): string;
571
+ flatMethod(object: ParsedExpr, depth: FlatDepth, emit: (e: ParsedExpr) => string): string;
572
+ flatMapMethod(object: ParsedExpr, op: FlatMapOp, emit: (e: ParsedExpr) => string): string;
570
573
  unsupported(raw: string, _reason: string): string;
571
574
  /**
572
575
  * Extract field name and negation from a simple predicate.
@@ -1 +1 @@
1
- {"version":3,"file":"go-template-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/go-template-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"go-template-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/go-template-adapter.ts"],"names":[],"mappings":"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"}
@@ -51,8 +51,20 @@ function emitBfSort(recv, c) {
51
51
  });
52
52
  return `bf_sort ${wrapIfMultiToken(recv)} ${groups.join(" ")}`;
53
53
  }
54
+ function emitBfReduce(recv, op, direction) {
55
+ const keyName = op.key.kind === "field" ? capitalize(op.key.field) : "";
56
+ return `bf_reduce ${wrapIfMultiToken(recv)} "${op.op}" "${op.key.kind}" "${keyName}" "${op.type}" "${escapeGoString(op.init)}" "${direction}"`;
57
+ }
58
+ function escapeGoString(s) {
59
+ return s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
60
+ }
54
61
  function capitalize(s) {
55
- return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
62
+ if (s.length === 0)
63
+ return s;
64
+ if (GoTemplateAdapter.GO_INITIALISMS.has(s.toLowerCase())) {
65
+ return s.toUpperCase();
66
+ }
67
+ return s[0].toUpperCase() + s.slice(1);
56
68
  }
57
69
  function slotIdToFieldSuffix(slotId) {
58
70
  const cleanId = slotId.startsWith("^") ? slotId.slice(1) : slotId;
@@ -62,6 +74,18 @@ function slotIdToFieldSuffix(slotId) {
62
74
  }
63
75
  return cleanId.replace("slot_", "Slot");
64
76
  }
77
+ var GO_REMEDIATION_OPTIONS = `Options:
78
+ 1. Use @client directive for client-side evaluation
79
+ 2. Pre-compute the value in Go code`;
80
+ function buildUnsupportedSuggestion(support) {
81
+ if (!support.reason)
82
+ return GO_REMEDIATION_OPTIONS;
83
+ if (support.selfContained)
84
+ return support.reason;
85
+ return `${support.reason}
86
+
87
+ ${GO_REMEDIATION_OPTIONS}`;
88
+ }
65
89
  var GO_TEMPLATE_PRIMITIVES = {
66
90
  "JSON.stringify": { arity: 1, emit: (args) => `bf_json ${args[0]}` },
67
91
  String: { arity: 1, emit: (args) => `bf_string ${args[0]}` },
@@ -1905,9 +1929,7 @@ ${goFields.join(`
1905
1929
  message: `Higher-order method '.${method}' shape cannot be lowered to a Go template action`,
1906
1930
  loc: this.makeLoc(),
1907
1931
  suggestion: {
1908
- message: `Options:
1909
- 1. Use @client directive for client-side evaluation
1910
- 2. Pre-compute the value in Go code`
1932
+ message: GO_REMEDIATION_OPTIONS
1911
1933
  }
1912
1934
  });
1913
1935
  return `""`;
@@ -2027,6 +2049,26 @@ ${goFields.join(`
2027
2049
  sortMethod(method, object, comparator, emit) {
2028
2050
  return emitBfSort(emit(object), comparator);
2029
2051
  }
2052
+ reduceMethod(method, object, reduceOp, emit) {
2053
+ const direction = method === "reduceRight" ? "right" : "left";
2054
+ return emitBfReduce(emit(object), reduceOp, direction);
2055
+ }
2056
+ flatMethod(object, depth, emit) {
2057
+ const d = depth === "infinity" ? -1 : depth;
2058
+ return `bf_flat ${wrapIfMultiToken(emit(object))} ${d}`;
2059
+ }
2060
+ flatMapMethod(object, op, emit) {
2061
+ const recv = wrapIfMultiToken(emit(object));
2062
+ const proj = op.projection;
2063
+ if (proj.kind === "tuple") {
2064
+ const pairs = proj.elements.map((l) => l.kind === "self" ? `"self" ""` : `"field" "${capitalize(l.field)}"`).join(" ");
2065
+ return `bf_flat_map_tuple ${recv} ${pairs}`;
2066
+ }
2067
+ if (proj.kind === "self") {
2068
+ return `bf_flat_map ${recv} "self" ""`;
2069
+ }
2070
+ return `bf_flat_map ${recv} "field" "${capitalize(proj.field)}"`;
2071
+ }
2030
2072
  unsupported(raw, _reason) {
2031
2073
  return `[UNSUPPORTED: ${raw}]`;
2032
2074
  }
@@ -2449,13 +2491,7 @@ ${goFields.join(`
2449
2491
  message: `Expression not supported: ${trimmed}`,
2450
2492
  loc: this.makeLoc(),
2451
2493
  suggestion: {
2452
- message: support.reason ? `${support.reason}
2453
-
2454
- Options:
2455
- 1. Use @client directive for client-side evaluation
2456
- 2. Pre-compute the value in Go code` : `Options:
2457
- 1. Use @client directive for client-side evaluation
2458
- 2. Pre-compute the value in Go code`
2494
+ message: buildUnsupportedSuggestion(support)
2459
2495
  }
2460
2496
  });
2461
2497
  return `""`;
@@ -2484,9 +2520,7 @@ Options:
2484
2520
  message: `Complex predicate in else-if is not supported: ${altIfStmt.condition}`,
2485
2521
  loc: this.makeLoc(),
2486
2522
  suggestion: {
2487
- message: `Options:
2488
- 1. Use @client directive for client-side evaluation
2489
- 2. Pre-compute the value in Go code`
2523
+ message: GO_REMEDIATION_OPTIONS
2490
2524
  }
2491
2525
  });
2492
2526
  }
@@ -2562,11 +2596,7 @@ Options:
2562
2596
  message: `Condition not supported: ${trimmed}`,
2563
2597
  loc: this.makeLoc(),
2564
2598
  suggestion: {
2565
- message: support.reason ? `${support.reason}
2566
-
2567
- Options:
2568
- 1. Use @client directive for client-side evaluation
2569
- 2. Pre-compute the value in Go code` : "Expression contains unsupported syntax"
2599
+ message: buildUnsupportedSuggestion(support)
2570
2600
  }
2571
2601
  });
2572
2602
  return { condition: `false`, preamble: "" };
package/dist/build.js CHANGED
@@ -391,8 +391,20 @@ function emitBfSort(recv, c) {
391
391
  });
392
392
  return `bf_sort ${wrapIfMultiToken(recv)} ${groups.join(" ")}`;
393
393
  }
394
+ function emitBfReduce(recv, op, direction) {
395
+ const keyName = op.key.kind === "field" ? capitalize(op.key.field) : "";
396
+ return `bf_reduce ${wrapIfMultiToken(recv)} "${op.op}" "${op.key.kind}" "${keyName}" "${op.type}" "${escapeGoString(op.init)}" "${direction}"`;
397
+ }
398
+ function escapeGoString(s) {
399
+ return s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
400
+ }
394
401
  function capitalize(s) {
395
- return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
402
+ if (s.length === 0)
403
+ return s;
404
+ if (GoTemplateAdapter.GO_INITIALISMS.has(s.toLowerCase())) {
405
+ return s.toUpperCase();
406
+ }
407
+ return s[0].toUpperCase() + s.slice(1);
396
408
  }
397
409
  function slotIdToFieldSuffix(slotId) {
398
410
  const cleanId = slotId.startsWith("^") ? slotId.slice(1) : slotId;
@@ -402,6 +414,18 @@ function slotIdToFieldSuffix(slotId) {
402
414
  }
403
415
  return cleanId.replace("slot_", "Slot");
404
416
  }
417
+ var GO_REMEDIATION_OPTIONS = `Options:
418
+ 1. Use @client directive for client-side evaluation
419
+ 2. Pre-compute the value in Go code`;
420
+ function buildUnsupportedSuggestion(support) {
421
+ if (!support.reason)
422
+ return GO_REMEDIATION_OPTIONS;
423
+ if (support.selfContained)
424
+ return support.reason;
425
+ return `${support.reason}
426
+
427
+ ${GO_REMEDIATION_OPTIONS}`;
428
+ }
405
429
  var GO_TEMPLATE_PRIMITIVES = {
406
430
  "JSON.stringify": { arity: 1, emit: (args) => `bf_json ${args[0]}` },
407
431
  String: { arity: 1, emit: (args) => `bf_string ${args[0]}` },
@@ -2245,9 +2269,7 @@ ${goFields.join(`
2245
2269
  message: `Higher-order method '.${method}' shape cannot be lowered to a Go template action`,
2246
2270
  loc: this.makeLoc(),
2247
2271
  suggestion: {
2248
- message: `Options:
2249
- 1. Use @client directive for client-side evaluation
2250
- 2. Pre-compute the value in Go code`
2272
+ message: GO_REMEDIATION_OPTIONS
2251
2273
  }
2252
2274
  });
2253
2275
  return `""`;
@@ -2367,6 +2389,26 @@ ${goFields.join(`
2367
2389
  sortMethod(method, object, comparator, emit) {
2368
2390
  return emitBfSort(emit(object), comparator);
2369
2391
  }
2392
+ reduceMethod(method, object, reduceOp, emit) {
2393
+ const direction = method === "reduceRight" ? "right" : "left";
2394
+ return emitBfReduce(emit(object), reduceOp, direction);
2395
+ }
2396
+ flatMethod(object, depth, emit) {
2397
+ const d = depth === "infinity" ? -1 : depth;
2398
+ return `bf_flat ${wrapIfMultiToken(emit(object))} ${d}`;
2399
+ }
2400
+ flatMapMethod(object, op, emit) {
2401
+ const recv = wrapIfMultiToken(emit(object));
2402
+ const proj = op.projection;
2403
+ if (proj.kind === "tuple") {
2404
+ const pairs = proj.elements.map((l) => l.kind === "self" ? `"self" ""` : `"field" "${capitalize(l.field)}"`).join(" ");
2405
+ return `bf_flat_map_tuple ${recv} ${pairs}`;
2406
+ }
2407
+ if (proj.kind === "self") {
2408
+ return `bf_flat_map ${recv} "self" ""`;
2409
+ }
2410
+ return `bf_flat_map ${recv} "field" "${capitalize(proj.field)}"`;
2411
+ }
2370
2412
  unsupported(raw, _reason) {
2371
2413
  return `[UNSUPPORTED: ${raw}]`;
2372
2414
  }
@@ -2789,13 +2831,7 @@ ${goFields.join(`
2789
2831
  message: `Expression not supported: ${trimmed}`,
2790
2832
  loc: this.makeLoc(),
2791
2833
  suggestion: {
2792
- message: support.reason ? `${support.reason}
2793
-
2794
- Options:
2795
- 1. Use @client directive for client-side evaluation
2796
- 2. Pre-compute the value in Go code` : `Options:
2797
- 1. Use @client directive for client-side evaluation
2798
- 2. Pre-compute the value in Go code`
2834
+ message: buildUnsupportedSuggestion(support)
2799
2835
  }
2800
2836
  });
2801
2837
  return `""`;
@@ -2824,9 +2860,7 @@ Options:
2824
2860
  message: `Complex predicate in else-if is not supported: ${altIfStmt.condition}`,
2825
2861
  loc: this.makeLoc(),
2826
2862
  suggestion: {
2827
- message: `Options:
2828
- 1. Use @client directive for client-side evaluation
2829
- 2. Pre-compute the value in Go code`
2863
+ message: GO_REMEDIATION_OPTIONS
2830
2864
  }
2831
2865
  });
2832
2866
  }
@@ -2902,11 +2936,7 @@ Options:
2902
2936
  message: `Condition not supported: ${trimmed}`,
2903
2937
  loc: this.makeLoc(),
2904
2938
  suggestion: {
2905
- message: support.reason ? `${support.reason}
2906
-
2907
- Options:
2908
- 1. Use @client directive for client-side evaluation
2909
- 2. Pre-compute the value in Go code` : "Expression contains unsupported syntax"
2939
+ message: buildUnsupportedSuggestion(support)
2910
2940
  }
2911
2941
  });
2912
2942
  return { condition: `false`, preamble: "" };
package/dist/index.js CHANGED
@@ -51,8 +51,20 @@ function emitBfSort(recv, c) {
51
51
  });
52
52
  return `bf_sort ${wrapIfMultiToken(recv)} ${groups.join(" ")}`;
53
53
  }
54
+ function emitBfReduce(recv, op, direction) {
55
+ const keyName = op.key.kind === "field" ? capitalize(op.key.field) : "";
56
+ return `bf_reduce ${wrapIfMultiToken(recv)} "${op.op}" "${op.key.kind}" "${keyName}" "${op.type}" "${escapeGoString(op.init)}" "${direction}"`;
57
+ }
58
+ function escapeGoString(s) {
59
+ return s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
60
+ }
54
61
  function capitalize(s) {
55
- return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1);
62
+ if (s.length === 0)
63
+ return s;
64
+ if (GoTemplateAdapter.GO_INITIALISMS.has(s.toLowerCase())) {
65
+ return s.toUpperCase();
66
+ }
67
+ return s[0].toUpperCase() + s.slice(1);
56
68
  }
57
69
  function slotIdToFieldSuffix(slotId) {
58
70
  const cleanId = slotId.startsWith("^") ? slotId.slice(1) : slotId;
@@ -62,6 +74,18 @@ function slotIdToFieldSuffix(slotId) {
62
74
  }
63
75
  return cleanId.replace("slot_", "Slot");
64
76
  }
77
+ var GO_REMEDIATION_OPTIONS = `Options:
78
+ 1. Use @client directive for client-side evaluation
79
+ 2. Pre-compute the value in Go code`;
80
+ function buildUnsupportedSuggestion(support) {
81
+ if (!support.reason)
82
+ return GO_REMEDIATION_OPTIONS;
83
+ if (support.selfContained)
84
+ return support.reason;
85
+ return `${support.reason}
86
+
87
+ ${GO_REMEDIATION_OPTIONS}`;
88
+ }
65
89
  var GO_TEMPLATE_PRIMITIVES = {
66
90
  "JSON.stringify": { arity: 1, emit: (args) => `bf_json ${args[0]}` },
67
91
  String: { arity: 1, emit: (args) => `bf_string ${args[0]}` },
@@ -1905,9 +1929,7 @@ ${goFields.join(`
1905
1929
  message: `Higher-order method '.${method}' shape cannot be lowered to a Go template action`,
1906
1930
  loc: this.makeLoc(),
1907
1931
  suggestion: {
1908
- message: `Options:
1909
- 1. Use @client directive for client-side evaluation
1910
- 2. Pre-compute the value in Go code`
1932
+ message: GO_REMEDIATION_OPTIONS
1911
1933
  }
1912
1934
  });
1913
1935
  return `""`;
@@ -2027,6 +2049,26 @@ ${goFields.join(`
2027
2049
  sortMethod(method, object, comparator, emit) {
2028
2050
  return emitBfSort(emit(object), comparator);
2029
2051
  }
2052
+ reduceMethod(method, object, reduceOp, emit) {
2053
+ const direction = method === "reduceRight" ? "right" : "left";
2054
+ return emitBfReduce(emit(object), reduceOp, direction);
2055
+ }
2056
+ flatMethod(object, depth, emit) {
2057
+ const d = depth === "infinity" ? -1 : depth;
2058
+ return `bf_flat ${wrapIfMultiToken(emit(object))} ${d}`;
2059
+ }
2060
+ flatMapMethod(object, op, emit) {
2061
+ const recv = wrapIfMultiToken(emit(object));
2062
+ const proj = op.projection;
2063
+ if (proj.kind === "tuple") {
2064
+ const pairs = proj.elements.map((l) => l.kind === "self" ? `"self" ""` : `"field" "${capitalize(l.field)}"`).join(" ");
2065
+ return `bf_flat_map_tuple ${recv} ${pairs}`;
2066
+ }
2067
+ if (proj.kind === "self") {
2068
+ return `bf_flat_map ${recv} "self" ""`;
2069
+ }
2070
+ return `bf_flat_map ${recv} "field" "${capitalize(proj.field)}"`;
2071
+ }
2030
2072
  unsupported(raw, _reason) {
2031
2073
  return `[UNSUPPORTED: ${raw}]`;
2032
2074
  }
@@ -2449,13 +2491,7 @@ ${goFields.join(`
2449
2491
  message: `Expression not supported: ${trimmed}`,
2450
2492
  loc: this.makeLoc(),
2451
2493
  suggestion: {
2452
- message: support.reason ? `${support.reason}
2453
-
2454
- Options:
2455
- 1. Use @client directive for client-side evaluation
2456
- 2. Pre-compute the value in Go code` : `Options:
2457
- 1. Use @client directive for client-side evaluation
2458
- 2. Pre-compute the value in Go code`
2494
+ message: buildUnsupportedSuggestion(support)
2459
2495
  }
2460
2496
  });
2461
2497
  return `""`;
@@ -2484,9 +2520,7 @@ Options:
2484
2520
  message: `Complex predicate in else-if is not supported: ${altIfStmt.condition}`,
2485
2521
  loc: this.makeLoc(),
2486
2522
  suggestion: {
2487
- message: `Options:
2488
- 1. Use @client directive for client-side evaluation
2489
- 2. Pre-compute the value in Go code`
2523
+ message: GO_REMEDIATION_OPTIONS
2490
2524
  }
2491
2525
  });
2492
2526
  }
@@ -2562,11 +2596,7 @@ Options:
2562
2596
  message: `Condition not supported: ${trimmed}`,
2563
2597
  loc: this.makeLoc(),
2564
2598
  suggestion: {
2565
- message: support.reason ? `${support.reason}
2566
-
2567
- Options:
2568
- 1. Use @client directive for client-side evaluation
2569
- 2. Pre-compute the value in Go code` : "Expression contains unsupported syntax"
2599
+ message: buildUnsupportedSuggestion(support)
2570
2600
  }
2571
2601
  });
2572
2602
  return { condition: `false`, preamble: "" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/go-template",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
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",
@@ -54,6 +54,6 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "@barefootjs/adapter-tests": "0.1.0",
57
- "@barefootjs/jsx": "0.6.0"
57
+ "@barefootjs/jsx": "0.6.1"
58
58
  }
59
59
  }
@@ -2318,6 +2318,81 @@ describe('GoTemplateAdapter - #1448 Tier A/B fixture-driven lowering pins', () =
2318
2318
  // now listed in `UNSUPPORTED_METHODS`, so `isSupported` refuses them
2319
2319
  // and `convertExpressionToGo` records BF101 — the same treatment the
2320
2320
  // unsupported array methods already got. These tests pin that parity.
2321
+ describe('GoTemplateAdapter - #1448 Tier C reduce field capitalisation', () => {
2322
+ // #1728 review: `bf_reduce`'s projected field name must use the same
2323
+ // initialism-aware capitalisation the adapter applies when generating
2324
+ // struct fields (`capitalizeFieldName`), or the runtime reflect lookup
2325
+ // misses the exported field (`id` → struct `ID`, not `Id`) and folds a
2326
+ // zero value. Pin the emitted key so a regression to plain
2327
+ // first-letter capitalisation fails here.
2328
+ test('reduce over an initialism field emits the Go-initialism key (ID, not Id)', () => {
2329
+ const adapter = new GoTemplateAdapter()
2330
+ const ir = compileToIR(`
2331
+ function C({ items }: { items: { id: number }[] }) {
2332
+ return <div>{items.reduce((sum, x) => sum + x.id, 0)}</div>
2333
+ }
2334
+ export { C }
2335
+ `, adapter)
2336
+ const template = adapter.generate(ir).template ?? ''
2337
+ expect(template).toContain('bf_reduce .Items "+" "field" "ID" "numeric" "0"')
2338
+ expect(template).not.toContain('"Id"')
2339
+ })
2340
+ })
2341
+
2342
+ describe('GoTemplateAdapter - #1448 Tier C .flat(depth?)', () => {
2343
+ function emitFlat(expr: string): string {
2344
+ const adapter = new GoTemplateAdapter()
2345
+ const ir = compileToIR(`
2346
+ function C({ rows }: { rows: number[][] }) {
2347
+ return <div>{${expr}}</div>
2348
+ }
2349
+ export { C }
2350
+ `, adapter)
2351
+ return adapter.generate(ir).template ?? ''
2352
+ }
2353
+
2354
+ test('.flat() emits bf_flat with default depth 1', () => {
2355
+ expect(emitFlat('rows.flat()')).toContain('bf_flat .Rows 1')
2356
+ })
2357
+
2358
+ test('.flat(2) emits the explicit depth', () => {
2359
+ expect(emitFlat('rows.flat(2)')).toContain('bf_flat .Rows 2')
2360
+ })
2361
+
2362
+ test('.flat(Infinity) emits the -1 full-depth sentinel', () => {
2363
+ expect(emitFlat('rows.flat(Infinity)')).toContain('bf_flat .Rows -1')
2364
+ })
2365
+ })
2366
+
2367
+ describe('GoTemplateAdapter - #1448 Tier C .flatMap(field projection)', () => {
2368
+ function emitFlatMap(expr: string): string {
2369
+ const adapter = new GoTemplateAdapter()
2370
+ const ir = compileToIR(`
2371
+ function C({ rows }: { rows: { a: string; b: string; tags: string[] }[] }) {
2372
+ return <div>{${expr}}</div>
2373
+ }
2374
+ export { C }
2375
+ `, adapter)
2376
+ return adapter.generate(ir).template ?? ''
2377
+ }
2378
+
2379
+ test('.flatMap(i => i.field) emits bf_flat_map with the Go-capitalised field', () => {
2380
+ expect(emitFlatMap('rows.flatMap(i => i.tags).join(" ")')).toContain('bf_flat_map .Rows "field" "Tags"')
2381
+ })
2382
+
2383
+ test('.flatMap(i => i) emits the self projection', () => {
2384
+ expect(emitFlatMap('rows.flatMap(i => i).join(" ")')).toContain('bf_flat_map .Rows "self" ""')
2385
+ })
2386
+
2387
+ test('.flatMap(i => [i.a, i.b]) emits bf_flat_map_tuple with capitalised leaves', () => {
2388
+ expect(emitFlatMap('rows.flatMap(i => [i.a, i.b]).join(" ")')).toContain('bf_flat_map_tuple .Rows "field" "A" "field" "B"')
2389
+ })
2390
+
2391
+ test('tuple self + field leaves', () => {
2392
+ expect(emitFlatMap('rows.flatMap(i => [i, i.a]).join(" ")')).toContain('bf_flat_map_tuple .Rows "self" "" "field" "A"')
2393
+ })
2394
+ })
2395
+
2321
2396
  describe('GoTemplateAdapter - #1448 @client escape hatch (unsupported methods)', () => {
2322
2397
  // Compile a single expression placed in `<div>` text position, with
2323
2398
  // and without the directive, and return both the build errors and
@@ -2363,10 +2438,14 @@ export function C() {
2363
2438
  // Go fragment that must NOT survive into the template (the pre-fix
2364
2439
  // silent-footgun output for the string rows).
2365
2440
  const unsupported: Array<{ name: string; expr: string; badEmit: string }> = [
2366
- // Tier C array methods.
2367
- { name: 'reduce', expr: `items().reduce((a, b) => a + b.n, 0)`, badEmit: '.Reduce' },
2368
- { name: 'flatMap', expr: `items().flatMap(i => i.tags)`, badEmit: '.FlatMap' },
2369
- { name: 'flat', expr: `items().flat()`, badEmit: '.Flat' },
2441
+ // Tier C array methods. The arithmetic-fold `.reduce(fn, init)`
2442
+ // catalogue now lowers (pinned in the positive reduce-* fixtures);
2443
+ // the no-initial-value form stays refused JS throws on an empty
2444
+ // array there, which a template can't mirror.
2445
+ { name: 'reduce (no init)', expr: `items().reduce((a, b) => a + b.n)`, badEmit: '.Reduce' },
2446
+ // Self / field / field-tuple `.flatMap` now lowers (#1448 Tier C); a
2447
+ // tuple with a non-leaf element (here a string literal) stays refused.
2448
+ { name: 'flatMap (literal element)', expr: `items().flatMap(i => [i.name, "x"])`, badEmit: '.FlatMap' },
2370
2449
  // Lowered methods whose MEANINGFUL extra argument isn't lowered yet
2371
2450
  // (#1448): the `fromIndex` of `.includes`/`.indexOf`/`.lastIndexOf`
2372
2451
  // and the variadic `.concat`. The parser refuses these (silently
@@ -2401,6 +2480,40 @@ export function C() {
2401
2480
  })
2402
2481
  }
2403
2482
 
2483
+ // The diagnostic's `suggestion.message` is shaped by `isSupported`'s
2484
+ // `selfContained` flag: reasons that already spell out the fix are shown
2485
+ // as-is, while low-level parser reasons still get the adapter's generic
2486
+ // "Options" remediation appended so users never lose actionable steps.
2487
+ function suggestionFor(expr: string): string {
2488
+ const { errors } = emit(expr, false)
2489
+ const e = errors.find(e => e.code === 'BF101' || e.code === 'BF102')
2490
+ return e?.suggestion?.message ?? ''
2491
+ }
2492
+
2493
+ test('self-contained reason is shown without the generic Options block', () => {
2494
+ // Generic unsupported-method reason already carries the remedy.
2495
+ const msg = suggestionFor('items().reduce((a, b) => a + b.n)')
2496
+ expect(msg).toContain('no SSR')
2497
+ expect(msg).not.toContain('Options:')
2498
+ })
2499
+
2500
+ test('tailored forEach reason keeps its own guidance, no Options block', () => {
2501
+ const msg = suggestionFor('items().forEach(x => x)')
2502
+ expect(msg).toContain("'.map(")
2503
+ // The forEach message deliberately steers away from @client; the
2504
+ // generic Options block (which re-suggests it) must not be appended.
2505
+ expect(msg).not.toContain('Options:')
2506
+ expect(msg).not.toContain('@client')
2507
+ })
2508
+
2509
+ test('low-level reason still gets the actionable Options block appended', () => {
2510
+ // `typeof` has no structured remedy reason → users must keep the
2511
+ // generic next steps (regression guard for #1730 review).
2512
+ const msg = suggestionFor('typeof items()')
2513
+ expect(msg).toContain('Options:')
2514
+ expect(msg).toContain('@client')
2515
+ })
2516
+
2404
2517
  // Predicate-level use of an unsupported string method also fails the
2405
2518
  // build loudly (intended): a `.filter(t => t.name.charAt(0) === "a")`
2406
2519
  // whose predicate calls one of the gated methods now refuses the whole
@@ -27,6 +27,9 @@ import type {
27
27
  ParsedExpr,
28
28
  ParsedStatement,
29
29
  SortComparator,
30
+ ReduceOp,
31
+ FlatDepth,
32
+ FlatMapOp,
30
33
  TemplatePart,
31
34
  IRIfStatement,
32
35
  IRProvider,
@@ -45,6 +48,7 @@ import {
45
48
  type IRNodeEmitter,
46
49
  type EmitIRNode,
47
50
  type AttrValueEmitter,
51
+ type SupportResult,
48
52
  isBooleanAttr,
49
53
  parseExpression,
50
54
  isSupported,
@@ -208,8 +212,56 @@ function emitBfSort(recv: string, c: SortComparator): string {
208
212
  return `bf_sort ${wrapIfMultiToken(recv)} ${groups.join(' ')}`
209
213
  }
210
214
 
215
+ /**
216
+ * Emit the `bf_reduce` call for a `.reduce(fn, init)` arithmetic fold
217
+ * (#1448 Tier C):
218
+ *
219
+ * bf_reduce <recv> "<op>" "<keyKind>" "<keyName>" "<type>" "<init>" "<direction>"
220
+ *
221
+ * op: "+" | "*"
222
+ * keyKind: "self" | "field"
223
+ * keyName: "" when keyKind=self; capitalised field name otherwise
224
+ * (matches the Go struct-field convention, mirroring
225
+ * `emitBfSort`)
226
+ * type: "numeric" | "string"
227
+ * init: the fold's start value — the numeric literal's text for a
228
+ * numeric fold, or the string literal's contents for a
229
+ * concat fold
230
+ * direction: "left" (reduce) | "right" (reduceRight)
231
+ *
232
+ * The runtime folds `init <op> key(item)` in `direction` order and
233
+ * returns the accumulated value (float64 for numeric, string for
234
+ * concat). The order is only observable for string concat — numeric
235
+ * sum / product commute.
236
+ */
237
+ function emitBfReduce(recv: string, op: ReduceOp, direction: 'left' | 'right'): string {
238
+ const keyName = op.key.kind === 'field' ? capitalize(op.key.field) : ''
239
+ // `op.init` is already the decoded seed value (canonical decimal for
240
+ // numeric folds — `strconv.ParseFloat`-safe; escape-free contents for
241
+ // concat folds). Pass it as a quoted operand the runtime interprets
242
+ // by `type`. `direction` is "left" (reduce) or "right" (reduceRight)
243
+ // — only observable for string concatenation; numeric folds are
244
+ // commutative.
245
+ return `bf_reduce ${wrapIfMultiToken(recv)} "${op.op}" "${op.key.kind}" "${keyName}" "${op.type}" "${escapeGoString(op.init)}" "${direction}"`
246
+ }
247
+
248
+ /** Escape a value for embedding in a Go-template double-quoted string. */
249
+ function escapeGoString(s: string): string {
250
+ return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
251
+ }
252
+
211
253
  function capitalize(s: string): string {
212
- return s.length === 0 ? s : s[0].toUpperCase() + s.slice(1)
254
+ if (s.length === 0) return s
255
+ // Match the adapter's struct-field naming (`capitalizeFieldName`):
256
+ // a whole-word Go initialism uppercases entirely (`id` → `ID`,
257
+ // `url` → `URL`) so the `bf_sort` / `bf_reduce` reflect lookup
258
+ // resolves the generated exported field instead of silently folding
259
+ // a zero value. The class is fully initialised by the time any emit
260
+ // helper runs, so referencing the static set here is safe.
261
+ if (GoTemplateAdapter.GO_INITIALISMS.has(s.toLowerCase())) {
262
+ return s.toUpperCase()
263
+ }
264
+ return s[0].toUpperCase() + s.slice(1)
213
265
  }
214
266
 
215
267
  /**
@@ -239,6 +291,22 @@ interface PrimitiveSpec {
239
291
  emit: (args: string[]) => string
240
292
  }
241
293
 
294
+ // Generic remediation appended to BF101 / BF102 diagnostics whose reason
295
+ // doesn't already carry actionable next steps.
296
+ const GO_REMEDIATION_OPTIONS =
297
+ 'Options:\n1. Use @client directive for client-side evaluation\n2. Pre-compute the value in Go code'
298
+
299
+ // Build the `suggestion.message` for an unsupported expression/condition.
300
+ // A self-contained reason (it already spells out the fix — e.g. the
301
+ // pre-compute / @client hint or the tailored forEach message) is shown
302
+ // as-is; a low-level reason gets the generic options appended; with no
303
+ // reason at all we fall back to the options alone.
304
+ function buildUnsupportedSuggestion(support: SupportResult): string {
305
+ if (!support.reason) return GO_REMEDIATION_OPTIONS
306
+ if (support.selfContained) return support.reason
307
+ return `${support.reason}\n\n${GO_REMEDIATION_OPTIONS}`
308
+ }
309
+
242
310
  const GO_TEMPLATE_PRIMITIVES: Record<string, PrimitiveSpec> = {
243
311
  'JSON.stringify': { arity: 1, emit: (args) => `bf_json ${args[0]}` },
244
312
  'String': { arity: 1, emit: (args) => `bf_string ${args[0]}` },
@@ -2579,7 +2647,9 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
2579
2647
  private static GO_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/
2580
2648
 
2581
2649
  /** Go common initialisms that should be fully uppercased (https://go.dev/wiki/CodeReviewComments#initialisms) */
2582
- private static GO_INITIALISMS = new Set([
2650
+ // Not `private`: the module-level `capitalize` helper reads this so
2651
+ // `bf_sort` / `bf_reduce` field projection matches `capitalizeFieldName`.
2652
+ static GO_INITIALISMS = new Set([
2583
2653
  'id', 'url', 'http', 'https', 'api', 'json', 'xml', 'html', 'css', 'sql',
2584
2654
  'ip', 'tcp', 'udp', 'dns', 'ssh', 'tls', 'ssl', 'uri', 'uid', 'uuid',
2585
2655
  'ascii', 'utf8', 'eof', 'grpc', 'rpc', 'cpu', 'gpu', 'ram', 'os',
@@ -3089,7 +3159,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
3089
3159
  message: `Higher-order method '.${method}' shape cannot be lowered to a Go template action`,
3090
3160
  loc: this.makeLoc(),
3091
3161
  suggestion: {
3092
- message: 'Options:\n1. Use @client directive for client-side evaluation\n2. Pre-compute the value in Go code',
3162
+ message: GO_REMEDIATION_OPTIONS,
3093
3163
  },
3094
3164
  })
3095
3165
  return `""`
@@ -3311,6 +3381,51 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
3311
3381
  return emitBfSort(emit(object), comparator)
3312
3382
  }
3313
3383
 
3384
+ reduceMethod(
3385
+ method: 'reduce' | 'reduceRight',
3386
+ object: ParsedExpr,
3387
+ reduceOp: ReduceOp,
3388
+ emit: (e: ParsedExpr) => string,
3389
+ ): string {
3390
+ // `.reduce(fn, init)` / `.reduceRight(fn, init)` arithmetic-fold
3391
+ // lowering (#1448 Tier C). The structured `ReduceOp` (op / key /
3392
+ // type / init) plus the fold direction feed the `bf_reduce` runtime
3393
+ // helper, which folds the receiver into a scalar.
3394
+ const direction = method === 'reduceRight' ? 'right' : 'left'
3395
+ return emitBfReduce(emit(object), reduceOp, direction)
3396
+ }
3397
+
3398
+ flatMethod(object: ParsedExpr, depth: FlatDepth, emit: (e: ParsedExpr) => string): string {
3399
+ // `.flat(depth?)` → `bf_flat <recv> <depth>`. The `Infinity` form
3400
+ // lowers to the `-1` sentinel (flatten fully); a finite depth flattens
3401
+ // that many levels (`0` = shallow copy). See packages/adapter-go-
3402
+ // template/runtime/bf.go.
3403
+ const d = depth === 'infinity' ? -1 : depth
3404
+ return `bf_flat ${wrapIfMultiToken(emit(object))} ${d}`
3405
+ }
3406
+
3407
+ flatMapMethod(object: ParsedExpr, op: FlatMapOp, emit: (e: ParsedExpr) => string): string {
3408
+ const recv = wrapIfMultiToken(emit(object))
3409
+ const proj = op.projection
3410
+ // Tuple projection `i => [i.a, i.b]` → `bf_flat_map_tuple <recv>
3411
+ // "<kind>" "<name>" ...` (one quoted pair per leaf). flat(1) removes
3412
+ // only the literal's wrapper, so the runtime appends each leaf verbatim.
3413
+ if (proj.kind === 'tuple') {
3414
+ const pairs = proj.elements
3415
+ .map(l => (l.kind === 'self' ? `"self" ""` : `"field" "${capitalize(l.field)}"`))
3416
+ .join(' ')
3417
+ return `bf_flat_map_tuple ${recv} ${pairs}`
3418
+ }
3419
+ // Scalar `.flatMap(i => i)` / `.flatMap(i => i.field)` → `bf_flat_map
3420
+ // <recv> "<kind>" "<name>"`. The runtime projects each item then
3421
+ // flattens one level. The field name uses the Go struct-field
3422
+ // capitalisation, matching `bf_reduce` / `bf_sort`.
3423
+ if (proj.kind === 'self') {
3424
+ return `bf_flat_map ${recv} "self" ""`
3425
+ }
3426
+ return `bf_flat_map ${recv} "field" "${capitalize(proj.field)}"`
3427
+ }
3428
+
3314
3429
  unsupported(raw: string, _reason: string): string {
3315
3430
  // Should not happen if `isSupported` was checked at parse time.
3316
3431
  return `[UNSUPPORTED: ${raw}]`
@@ -4046,9 +4161,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
4046
4161
  message: `Expression not supported: ${trimmed}`,
4047
4162
  loc: this.makeLoc(),
4048
4163
  suggestion: {
4049
- message: support.reason
4050
- ? `${support.reason}\n\nOptions:\n1. Use @client directive for client-side evaluation\n2. Pre-compute the value in Go code`
4051
- : 'Options:\n1. Use @client directive for client-side evaluation\n2. Pre-compute the value in Go code',
4164
+ message: buildUnsupportedSuggestion(support),
4052
4165
  },
4053
4166
  })
4054
4167
  // Return empty string - Go template comments must be separate actions
@@ -4086,7 +4199,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
4086
4199
  message: `Complex predicate in else-if is not supported: ${altIfStmt.condition}`,
4087
4200
  loc: this.makeLoc(),
4088
4201
  suggestion: {
4089
- message: 'Options:\n1. Use @client directive for client-side evaluation\n2. Pre-compute the value in Go code',
4202
+ message: GO_REMEDIATION_OPTIONS,
4090
4203
  },
4091
4204
  })
4092
4205
  }
@@ -4183,9 +4296,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
4183
4296
  message: `Condition not supported: ${trimmed}`,
4184
4297
  loc: this.makeLoc(),
4185
4298
  suggestion: {
4186
- message: support.reason
4187
- ? `${support.reason}\n\nOptions:\n1. Use @client directive for client-side evaluation\n2. Pre-compute the value in Go code`
4188
- : 'Expression contains unsupported syntax',
4299
+ message: buildUnsupportedSuggestion(support),
4189
4300
  },
4190
4301
  })
4191
4302
  // Return false - Go template comments must be separate actions
@@ -355,7 +355,14 @@ function goMapLiteralFromObject(
355
355
  else if (typeof v === 'number') entries.push(`${key}: ${v}`)
356
356
  else if (typeof v === 'boolean') entries.push(`${key}: ${v}`)
357
357
  else if (v === null) entries.push(`${key}: nil`)
358
- else if (v && typeof v === 'object' && !Array.isArray(v)) {
358
+ else if (Array.isArray(v)) {
359
+ // Array-valued field inside an object-in-array (e.g. the `tags`
360
+ // of `items.flatMap(i => i.tags)`). Without this branch the field
361
+ // was silently dropped, leaving an empty map so the template
362
+ // rendered nothing for the projection (#1448 Tier C flatMap).
363
+ entries.push(`${key}: ${goArrayLiteralFromArray(v)}`)
364
+ }
365
+ else if (v && typeof v === 'object') {
359
366
  entries.push(`${key}: ${goMapLiteralFromObject(v as Record<string, unknown>, capitalizeKeys)}`)
360
367
  }
361
368
  }