@barefootjs/go-template 0.15.2 → 0.17.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 (73) hide show
  1. package/dist/adapter/analysis/component-tree.d.ts +23 -0
  2. package/dist/adapter/analysis/component-tree.d.ts.map +1 -0
  3. package/dist/adapter/emit-context.d.ts +53 -0
  4. package/dist/adapter/emit-context.d.ts.map +1 -0
  5. package/dist/adapter/expr/helper-inline.d.ts +31 -0
  6. package/dist/adapter/expr/helper-inline.d.ts.map +1 -0
  7. package/dist/adapter/expr/url-builder.d.ts +23 -0
  8. package/dist/adapter/expr/url-builder.d.ts.map +1 -0
  9. package/dist/adapter/go-template-adapter.d.ts +291 -1070
  10. package/dist/adapter/go-template-adapter.d.ts.map +1 -1
  11. package/dist/adapter/index.js +2859 -2618
  12. package/dist/adapter/lib/compile-state.d.ts +116 -0
  13. package/dist/adapter/lib/compile-state.d.ts.map +1 -0
  14. package/dist/adapter/lib/constants.d.ts +11 -0
  15. package/dist/adapter/lib/constants.d.ts.map +1 -0
  16. package/dist/adapter/lib/go-emit.d.ts +117 -0
  17. package/dist/adapter/lib/go-emit.d.ts.map +1 -0
  18. package/dist/adapter/lib/go-naming.d.ts +39 -0
  19. package/dist/adapter/lib/go-naming.d.ts.map +1 -0
  20. package/dist/adapter/lib/ir-scope.d.ts +13 -0
  21. package/dist/adapter/lib/ir-scope.d.ts.map +1 -0
  22. package/dist/adapter/lib/types.d.ts +165 -0
  23. package/dist/adapter/lib/types.d.ts.map +1 -0
  24. package/dist/adapter/memo/ctor-lowering.d.ts +39 -0
  25. package/dist/adapter/memo/ctor-lowering.d.ts.map +1 -0
  26. package/dist/adapter/memo/memo-compute.d.ts +124 -0
  27. package/dist/adapter/memo/memo-compute.d.ts.map +1 -0
  28. package/dist/adapter/memo/memo-type.d.ts +38 -0
  29. package/dist/adapter/memo/memo-type.d.ts.map +1 -0
  30. package/dist/adapter/memo/memo-value.d.ts +64 -0
  31. package/dist/adapter/memo/memo-value.d.ts.map +1 -0
  32. package/dist/adapter/memo/template-interp.d.ts +43 -0
  33. package/dist/adapter/memo/template-interp.d.ts.map +1 -0
  34. package/dist/adapter/props/prop-types.d.ts +31 -0
  35. package/dist/adapter/props/prop-types.d.ts.map +1 -0
  36. package/dist/adapter/spread/spread-codegen.d.ts +40 -0
  37. package/dist/adapter/spread/spread-codegen.d.ts.map +1 -0
  38. package/dist/adapter/type/type-codegen.d.ts +25 -0
  39. package/dist/adapter/type/type-codegen.d.ts.map +1 -0
  40. package/dist/adapter/value/parsed-literal-to-go.d.ts +17 -0
  41. package/dist/adapter/value/parsed-literal-to-go.d.ts.map +1 -0
  42. package/dist/adapter/value/value-lowering.d.ts +46 -0
  43. package/dist/adapter/value/value-lowering.d.ts.map +1 -0
  44. package/dist/build.js +2857 -2616
  45. package/dist/index.js +2859 -2618
  46. package/dist/test-render.d.ts.map +1 -1
  47. package/package.json +3 -3
  48. package/src/__tests__/derived-state-memo.test.ts +155 -84
  49. package/src/__tests__/go-template-adapter.test.ts +211 -60
  50. package/src/__tests__/lowering-plugin.test.ts +109 -0
  51. package/src/__tests__/query-href.test.ts +179 -0
  52. package/src/adapter/analysis/component-tree.ts +174 -0
  53. package/src/adapter/emit-context.ts +59 -0
  54. package/src/adapter/expr/helper-inline.ts +274 -0
  55. package/src/adapter/expr/url-builder.ts +123 -0
  56. package/src/adapter/go-template-adapter.ts +2100 -5316
  57. package/src/adapter/lib/compile-state.ts +150 -0
  58. package/src/adapter/lib/constants.ts +24 -0
  59. package/src/adapter/lib/go-emit.ts +289 -0
  60. package/src/adapter/lib/go-naming.ts +84 -0
  61. package/src/adapter/lib/ir-scope.ts +31 -0
  62. package/src/adapter/lib/types.ts +182 -0
  63. package/src/adapter/memo/ctor-lowering.ts +267 -0
  64. package/src/adapter/memo/memo-compute.ts +451 -0
  65. package/src/adapter/memo/memo-type.ts +74 -0
  66. package/src/adapter/memo/memo-value.ts +197 -0
  67. package/src/adapter/memo/template-interp.ts +246 -0
  68. package/src/adapter/props/prop-types.ts +84 -0
  69. package/src/adapter/spread/spread-codegen.ts +458 -0
  70. package/src/adapter/type/type-codegen.ts +95 -0
  71. package/src/adapter/value/parsed-literal-to-go.ts +94 -0
  72. package/src/adapter/value/value-lowering.ts +162 -0
  73. package/src/test-render.ts +2 -14
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Go lowering of helper calls to template expressions. Renders backend-neutral
3
+ * `LoweringNode`s produced by registered lowering plugins (#2057) — one uniform
4
+ * path for both userland plugins and built-ins like `queryHref` (a default plugin
5
+ * that lowers to `bf_query`, #2042). Every node funnels through
6
+ * `renderLoweringNode`, which maps a logical helper id to its Go helper; the
7
+ * adapter carries no per-API recognition branch of its own.
8
+ */
9
+
10
+ import {
11
+ type LoweringNode,
12
+ type ParsedExpr,
13
+ parseExpression,
14
+ stringifyParsedExpr,
15
+ } from '@barefootjs/jsx'
16
+
17
+ import type { GoEmitContext } from '../emit-context.ts'
18
+ import { wrapIfMultiToken } from '../lib/go-emit.ts'
19
+
20
+ /** Logical helper id → Go template helper name. */
21
+ const GO_HELPER_NAMES: Record<string, string> = { query: 'bf_query' }
22
+
23
+ const BOOL_COMPARISON_OPS: ReadonlySet<string> = new Set([
24
+ '==', '===', '!=', '!==', '<', '>', '<=', '>=',
25
+ ])
26
+
27
+ /**
28
+ * Lower an expression to a Go *bool* for `bf_query`'s `include` argument. A
29
+ * comparison / negation / bool-literal already yields a bool
30
+ * (`convertConditionToGo`); anything else is JS string-truthiness, lowered to
31
+ * `ne <value> ""`. The arg must be a real bool — `bf_query` type-asserts it, so
32
+ * Go-template truthiness (`{{if x}}`) is not enough.
33
+ *
34
+ * The `ne <value> ""` path models *string* truthiness, which is the query
35
+ * domain: `queryHref` values are strings (`QueryParamValue`). A guard on a
36
+ * non-string value is outside the supported surface; the type-assert on
37
+ * `bf_query`'s include arg surfaces it as a build error rather than silently
38
+ * mis-including. (#2041 review.)
39
+ */
40
+ function lowerUrlGuard(ctx: GoEmitContext, g: ParsedExpr): string {
41
+ // Comparisons, `!x`, and bool literals lower to a Go bool via the condition
42
+ // lowering. `&&` / `||` do NOT qualify: Go's `and`/`or` return one of their
43
+ // operands (a string for a truthiness guard like `tag && other`), not a
44
+ // bool — so they take the truthiness-wrap path below, yielding
45
+ // `ne (and …) ""`, an actual bool.
46
+ const isBoolShape =
47
+ (g.kind === 'binary' && BOOL_COMPARISON_OPS.has(g.op)) ||
48
+ (g.kind === 'unary' && g.op === '!') ||
49
+ (g.kind === 'literal' && g.literalType === 'boolean')
50
+ if (isBoolShape) {
51
+ return ctx.convertConditionToGo(stringifyParsedExpr(g), g).condition
52
+ }
53
+ const valueGo = wrapIfMultiToken(ctx.convertExpressionToGo(stringifyParsedExpr(g), undefined, g))
54
+ return `ne ${valueGo} ""`
55
+ }
56
+
57
+ /**
58
+ * Lower a helper call to a Go template expression, or null when no registered
59
+ * plugin recognises it (→ the generic lowering). Matchers — including the
60
+ * built-in `queryHref` plugin (#2042) — are bound to the component metadata at
61
+ * init (`ctx.state.loweringMatchers`), so this is one uniform loop with no
62
+ * per-API branch.
63
+ *
64
+ * Cheap-out: no active matchers → null; else reuse `preParsed` when it's already
65
+ * a call, otherwise a regex pre-filter gates the parse so non-call expressions
66
+ * never pay for `parseExpression`.
67
+ */
68
+ export function lowerRegisteredCall(
69
+ ctx: GoEmitContext,
70
+ jsExpr: string,
71
+ preParsed?: ParsedExpr,
72
+ ): string | null {
73
+ const matchers = ctx.state.loweringMatchers
74
+ if (matchers.length === 0) return null
75
+
76
+ let call: ParsedExpr | undefined = preParsed?.kind === 'call' ? preParsed : undefined
77
+ if (!call) {
78
+ if (!/^\s*[A-Za-z_$][\w$]*\s*\(/.test(jsExpr)) return null
79
+ const parsed = parseExpression(jsExpr)
80
+ if (parsed.kind !== 'call') return null
81
+ call = parsed
82
+ }
83
+
84
+ for (const matcher of matchers) {
85
+ const node = matcher(call.callee, call.args)
86
+ if (!node) continue
87
+ const rendered = renderLoweringNode(ctx, node)
88
+ if (rendered !== null) return rendered
89
+ }
90
+ return null
91
+ }
92
+
93
+ /**
94
+ * Render a backend-neutral lowering node to a Go template expression, or null
95
+ * when the node's `helper` has no Go mapping — the caller then declines
96
+ * (generic lowering → BF101), rather than emitting the raw helper id, which
97
+ * would be invalid Go. Adapters must switch on `helper`; an unknown one is not
98
+ * rendered.
99
+ */
100
+ function renderLoweringNode(ctx: GoEmitContext, node: LoweringNode): string | null {
101
+ const helper = GO_HELPER_NAMES[node.helper]
102
+ if (!helper) return null
103
+ const lowerExpr = (n: ParsedExpr): string =>
104
+ ctx.convertExpressionToGo(stringifyParsedExpr(n), undefined, n)
105
+ if (node.kind === 'helper-call') {
106
+ const args = node.args.map(a => wrapIfMultiToken(lowerExpr(a)))
107
+ return [helper, ...args].join(' ')
108
+ }
109
+ // guard-list — `queryHref`-shaped. Inclusion mirrors the client exactly, where
110
+ // every param value is a STRING (`QueryParamValue`): bf_query drops an
111
+ // included-but-empty value and appends array members.
112
+ // - plain `key: v` (guard null) → `(true) "key" v`
113
+ // - conditional `key: cond ? a : <omit>` → `(<cond>) "key" a`, where the
114
+ // non-empty check is done by bf_query, not folded into the guard.
115
+ const parts: string[] = [wrapIfMultiToken(lowerExpr(node.base))]
116
+ for (const t of node.triples) {
117
+ const includeGo = t.guard === null ? 'true' : lowerUrlGuard(ctx, t.guard)
118
+ parts.push(`(${includeGo})`)
119
+ parts.push(JSON.stringify(t.key))
120
+ parts.push(wrapIfMultiToken(lowerExpr(t.value)))
121
+ }
122
+ return `${helper} ${parts.join(' ')}`
123
+ }