@barefootjs/go-template 0.17.1 → 0.18.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.
@@ -107,3 +107,59 @@ export function P(props: { base: string; tag: string }) {
107
107
  expect(template).toContain('bf_query .Base (true) "tag" .Tag')
108
108
  })
109
109
  })
110
+
111
+ // A second sample plugin exercising the OTHER neutral-node variant,
112
+ // `helper-call` (#2069) — the general single-invocation escape hatch that
113
+ // was "unused today" before this change. Recognises a bespoke user import
114
+ // (`customSerialize` from `./lib`, matching the shared conformance case)
115
+ // and lowers its one-arg call to a `custom_serialize` helper.
116
+ const customSerializePlugin: LoweringPlugin = {
117
+ name: 'sample-custom-serialize',
118
+ prepare(metadata) {
119
+ const spec = metadata.imports
120
+ .filter(i => i.source === './lib' && !i.isTypeOnly)
121
+ .flatMap(i => i.specifiers)
122
+ .filter(s => !s.isTypeOnly && !s.isNamespace && !s.isDefault)
123
+ .find(s => s.name === 'customSerialize')
124
+ if (!spec) return null
125
+ const local = spec.alias ?? spec.name
126
+ return (callee, args) => {
127
+ if (callee.kind !== 'identifier' || callee.name !== local) return null
128
+ return { kind: 'helper-call', helper: 'custom_serialize', args }
129
+ }
130
+ },
131
+ }
132
+
133
+ afterEach(() => {
134
+ __resetLoweringPluginsForTest(getLoweringPlugins().filter(p => p.name !== 'sample-custom-serialize'))
135
+ })
136
+
137
+ describe('lowering-plugin registry → Go adapter: helper-call (#2069)', () => {
138
+ test('a helper-call node renders as bf_<helper> with the args following, Go-func-call style', () => {
139
+ registerLoweringPlugin(customSerializePlugin)
140
+ const src = `
141
+ 'use client'
142
+ import { customSerialize } from './lib'
143
+ export function P(props: { config: object }) {
144
+ return <div data-config={customSerialize(props.config)}>x</div>
145
+ }
146
+ `
147
+ const { template } = generate(src)
148
+ // `bf_<helper>` mirrors the built-in `query` helper's own `bf_query`
149
+ // naming exactly — the formula generalises, it isn't a lookup table
150
+ // limited to `query`.
151
+ expect(template).toContain('bf_custom_serialize .Config')
152
+ })
153
+
154
+ test('without the plugin registered, the call falls back to the generic (unsupported) lowering', () => {
155
+ const src = `
156
+ 'use client'
157
+ import { customSerialize } from './lib'
158
+ export function P(props: { config: object }) {
159
+ return <div data-config={customSerialize(props.config)}>x</div>
160
+ }
161
+ `
162
+ const { template } = generate(src)
163
+ expect(template).not.toContain('bf_custom_serialize')
164
+ })
165
+ })
@@ -12,13 +12,24 @@ import {
12
12
  type ParsedExpr,
13
13
  parseExpression,
14
14
  stringifyParsedExpr,
15
+ isValidHelperId,
15
16
  } from '@barefootjs/jsx'
16
17
 
17
18
  import type { GoEmitContext } from '../emit-context.ts'
18
19
  import { wrapIfMultiToken } from '../lib/go-emit.ts'
19
20
 
20
- /** Logical helper id → Go template helper name. */
21
- const GO_HELPER_NAMES: Record<string, string> = { query: 'bf_query' }
21
+ /**
22
+ * Logical helper id Go template helper name. `bf_<helper>` is a formula,
23
+ * not a lookup table (#2069) — the built-in `query` helper (`bf_query`)
24
+ * already follows the exact same convention every userland-registered
25
+ * `helper-call` id gets for free. `isValidHelperId` guards against a
26
+ * malformed id (e.g. containing a space or backtick) producing invalid Go
27
+ * template source; a plugin author's helper id is otherwise untrusted
28
+ * input reaching generated code.
29
+ */
30
+ function goHelperName(helper: string): string | null {
31
+ return isValidHelperId(helper) ? `bf_${helper}` : null
32
+ }
22
33
 
23
34
  const BOOL_COMPARISON_OPS: ReadonlySet<string> = new Set([
24
35
  '==', '===', '!=', '!==', '<', '>', '<=', '>=',
@@ -98,7 +109,7 @@ export function lowerRegisteredCall(
98
109
  * rendered.
99
110
  */
100
111
  function renderLoweringNode(ctx: GoEmitContext, node: LoweringNode): string | null {
101
- const helper = GO_HELPER_NAMES[node.helper]
112
+ const helper = goHelperName(node.helper)
102
113
  if (!helper) return null
103
114
  const lowerExpr = (n: ParsedExpr): string =>
104
115
  ctx.convertExpressionToGo(stringifyParsedExpr(n), undefined, n)