@barefootjs/go-template 0.18.3 → 0.18.5
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/adapter/go-template-adapter.d.ts +35 -1
- package/dist/adapter/go-template-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +162 -21
- package/dist/adapter/lib/compile-state.d.ts +7 -0
- package/dist/adapter/lib/compile-state.d.ts.map +1 -1
- package/dist/adapter/lib/constants.d.ts.map +1 -1
- package/dist/adapter/memo/memo-compute.d.ts.map +1 -1
- package/dist/adapter/props/prop-classes.d.ts +21 -0
- package/dist/adapter/props/prop-classes.d.ts.map +1 -0
- package/dist/adapter/props/prop-types.d.ts.map +1 -1
- package/dist/adapter/type/type-codegen.d.ts +5 -1
- package/dist/adapter/type/type-codegen.d.ts.map +1 -1
- package/dist/adapter/value/value-lowering.d.ts.map +1 -1
- package/dist/build.js +162 -21
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +164 -43
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/go-template-adapter.test.ts +1 -1
- package/src/adapter/go-template-adapter.ts +226 -9
- package/src/adapter/lib/compile-state.ts +8 -0
- package/src/adapter/lib/constants.ts +1 -0
- package/src/adapter/memo/memo-compute.ts +37 -9
- package/src/adapter/props/prop-classes.ts +45 -0
- package/src/adapter/props/prop-types.ts +69 -1
- package/src/adapter/type/type-codegen.ts +19 -2
- package/src/adapter/value/value-lowering.ts +27 -2
- package/src/conformance-pins.ts +0 -5
- package/src/render-divergences.ts +0 -36
- package/src/test-render.ts +23 -8
|
@@ -42,8 +42,12 @@ export function convertInitialValue(
|
|
|
42
42
|
return value === 'true' ? 'true' : 'false'
|
|
43
43
|
}
|
|
44
44
|
if (typeInfo.primitive === 'number') {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
// Leading `-` (#2168 math-methods: `createSignal(-7.6)`) — without it,
|
|
46
|
+
// a negative initial value never matches either literal shape below
|
|
47
|
+
// and silently falls to the `0` zero-value fallback, regardless of the
|
|
48
|
+
// field's Go type.
|
|
49
|
+
if (/^-?\d+$/.test(value)) return value
|
|
50
|
+
if (/^-?\d+\.\d+$/.test(value)) return value
|
|
47
51
|
return '0'
|
|
48
52
|
}
|
|
49
53
|
if (typeInfo.primitive === 'string') {
|
|
@@ -70,6 +74,27 @@ export function convertInitialValue(
|
|
|
70
74
|
}
|
|
71
75
|
return '""'
|
|
72
76
|
}
|
|
77
|
+
// A struct-backed `interface` kind (an explicitly-typed object signal,
|
|
78
|
+
// `createSignal<User>({...})`) — #2168 signal-object-field. Mirrors the
|
|
79
|
+
// `array` branch above: `jsLiteralToGo` → `parsedLiteralToGo`'s
|
|
80
|
+
// object-literal case already bakes an object literal against a named
|
|
81
|
+
// local struct correctly (proven by the existing typed-array-of-objects
|
|
82
|
+
// test); it just wasn't reachable from a SCALAR struct signal, which
|
|
83
|
+
// fell straight through to `nil` — a compile error for a non-pointer
|
|
84
|
+
// struct field (`cannot use nil as User value in struct literal`), not
|
|
85
|
+
// merely a silently-dropped initial value.
|
|
86
|
+
if (ctx.state.localStructFields.has(typeInfo.raw)) {
|
|
87
|
+
const baked = jsLiteralToGo(ctx, typeInfo, preParsed)
|
|
88
|
+
if (baked !== null) return baked
|
|
89
|
+
// Baking failed (a non-literal initial value, or no `preParsed` tree)
|
|
90
|
+
// — `nil` is STILL invalid Go for this non-pointer struct field, so
|
|
91
|
+
// the same compile error would resurface for any such case (Copilot
|
|
92
|
+
// review, #2201). The struct's own zero value (`User{}`) is the
|
|
93
|
+
// correct fallback here — mirrors this function's own docstring
|
|
94
|
+
// ("falls back to the type's zero value") for every other typed
|
|
95
|
+
// branch above.
|
|
96
|
+
return `${typeInfo.raw}{}`
|
|
97
|
+
}
|
|
73
98
|
}
|
|
74
99
|
|
|
75
100
|
return 'nil'
|
package/src/conformance-pins.ts
CHANGED
|
@@ -138,9 +138,4 @@ export const conformancePins: ConformancePins = {
|
|
|
138
138
|
// the shape loudly instead of emitting entity-escaped markup that
|
|
139
139
|
// silently renders tags as text.
|
|
140
140
|
'dangerous-inner-html': [{ code: 'BF101', severity: 'error' }],
|
|
141
|
-
// Edge-case sweep (Priority 12): `.replaceAll` has no lowering yet —
|
|
142
|
-
// only first-occurrence `.replace` is wired to the runtime helpers.
|
|
143
|
-
// Refused with BF101 rather than reusing the first-only lowering,
|
|
144
|
-
// which would silently change semantics.
|
|
145
|
-
'string-replaceall': [{ code: 'BF101', severity: 'error' }],
|
|
146
141
|
}
|
|
@@ -17,40 +17,4 @@
|
|
|
17
17
|
import type { RenderDivergences } from '@barefootjs/jsx'
|
|
18
18
|
|
|
19
19
|
export const renderDivergences: RenderDivergences = {
|
|
20
|
-
'html-entity-text':
|
|
21
|
-
'`©` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes',
|
|
22
|
-
'string-concat-plus':
|
|
23
|
-
"`'Hello, ' + name` renders \"0\" — JS string-concat `+` lowered through numeric addition",
|
|
24
|
-
'optional-chaining-prop':
|
|
25
|
-
'`user?.name ?? …` on an object prop: generated Go fails to run (exit 1) — optional chaining into a struct/map prop has no lowering',
|
|
26
|
-
'number-tofixed':
|
|
27
|
-
'`.toFixed(2)` on a number PROP: generated Go fails to run (exit 1)',
|
|
28
|
-
'math-methods':
|
|
29
|
-
'Math.min/max/abs over a signal: generated Go fails to run (exit 1) — only Math.floor is registered',
|
|
30
|
-
'boolean-attr-literals':
|
|
31
|
-
'camelCase boolean alias `readOnly`: Hono SSRs `readOnly="true"`, this adapter emits bare presence',
|
|
32
|
-
'camelcase-attributes':
|
|
33
|
-
'`htmlFor` is not lowered to `for` (Hono maps it)',
|
|
34
|
-
'static-attr-escape':
|
|
35
|
-
'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
|
|
36
|
-
'svg-icon':
|
|
37
|
-
'SVG camelCase presentation attrs (`strokeWidth`, `strokeLinecap`) pass through unmapped; Hono lowers to kebab-case',
|
|
38
|
-
'object-entries-map':
|
|
39
|
-
'`Object.entries(prop).map(([k, v]) => …)`: generated Go fails to run (exit 1) — no object-iteration loop lowering',
|
|
40
|
-
'nested-loop-outer-binding':
|
|
41
|
-
'nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`',
|
|
42
|
-
'jsx-element-prop':
|
|
43
|
-
'a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped',
|
|
44
|
-
'grandchild-composition':
|
|
45
|
-
"three-level composition: the grandchild's threaded prop renders EMPTY — prop forwarding through two template-render layers loses the value",
|
|
46
|
-
'child-primitive-props':
|
|
47
|
-
'numeric/boolean LITERAL props on a child (`count={5}` `active={true}`) render as Go zero values (0 / false)',
|
|
48
|
-
'memo-chain':
|
|
49
|
-
'a memo derived from another memo renders EMPTY for the second layer — the constructor folds only one derivation level',
|
|
50
|
-
'signal-object-field':
|
|
51
|
-
'object-valued signal (`user().name`): generated Go fails to run (exit 1) — no struct synthesis outside loops',
|
|
52
|
-
'string-slice':
|
|
53
|
-
'`.slice()` on a STRING routes through the array `bf_slice` helper and renders "[]" instead of the substring',
|
|
54
|
-
'string-trim-sided':
|
|
55
|
-
'`.trimStart()` / `.trimEnd()`: generated Go fails to run (exit 1) — only both-sides `bf_trim` exists',
|
|
56
20
|
}
|
package/src/test-render.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { compileJSX } from '@barefootjs/jsx'
|
|
|
9
9
|
import type { TemplateAdapter, ComponentIR } from '@barefootjs/jsx'
|
|
10
10
|
import { GoTemplateAdapter } from './adapter/go-template-adapter.ts'
|
|
11
11
|
import { deduplicateGoTypes } from './build.ts'
|
|
12
|
-
import { capitalizeFieldName } from './adapter/lib/go-naming.ts'
|
|
12
|
+
import { capitalizeFieldName, goFieldNameForKey } from './adapter/lib/go-naming.ts'
|
|
13
13
|
import { mkdir, rm } from 'node:fs/promises'
|
|
14
14
|
import { resolve } from 'node:path'
|
|
15
15
|
|
|
@@ -572,9 +572,7 @@ function buildGoPropsInit(
|
|
|
572
572
|
// in struct literal of type InputInput`. (#1467 Phase 2b)
|
|
573
573
|
const declaredParams = new Set((ir?.metadata.propsParams ?? []).map(p => p.name))
|
|
574
574
|
const restPropsName = ir?.metadata.restPropsName ?? null
|
|
575
|
-
const restBagField = restPropsName
|
|
576
|
-
? restPropsName.charAt(0).toUpperCase() + restPropsName.slice(1)
|
|
577
|
-
: null
|
|
575
|
+
const restBagField = restPropsName ? capitalizeFieldName(restPropsName) : null
|
|
578
576
|
|
|
579
577
|
const lines: string[] = []
|
|
580
578
|
const restBagEntries: Array<[string, unknown]> = []
|
|
@@ -594,8 +592,9 @@ function buildGoPropsInit(
|
|
|
594
592
|
restBagEntries.push([key, value])
|
|
595
593
|
continue
|
|
596
594
|
}
|
|
597
|
-
//
|
|
598
|
-
|
|
595
|
+
// Same Go-initialism-aware capitalizer as the real adapter (`id` → `ID`,
|
|
596
|
+
// not the naive `Id`) — see `goMapLiteralFromObject`'s identical fix.
|
|
597
|
+
const goField = capitalizeFieldName(key)
|
|
599
598
|
if (typeof value === 'string') {
|
|
600
599
|
lines.push(`\t\t${goField}: "${value}",`)
|
|
601
600
|
} else if (typeof value === 'number') {
|
|
@@ -729,7 +728,11 @@ function goTypedMapSliceLiteralFromArray(arr: unknown[], elemType: string): stri
|
|
|
729
728
|
function goStructLiteral(obj: Record<string, unknown>, typeName: string): string {
|
|
730
729
|
const fields: string[] = []
|
|
731
730
|
for (const [k, v] of Object.entries(obj)) {
|
|
732
|
-
|
|
731
|
+
// `goFieldNameForKey`, not the bare `capitalizeFieldName` — a data-driven
|
|
732
|
+
// key here can be non-identifier-shaped (`'data-x'`), and the real
|
|
733
|
+
// adapter's own struct-literal baking (`parsed-literal-to-go.ts`)
|
|
734
|
+
// sanitizes those to `DataX`, not `Data-x` (Copilot review, #2202).
|
|
735
|
+
const goField = goFieldNameForKey(k)
|
|
733
736
|
if (typeof v === 'string') fields.push(`${goField}: "${v.replace(/"/g, '\\"')}"`)
|
|
734
737
|
else if (typeof v === 'number' || typeof v === 'boolean') fields.push(`${goField}: ${v}`)
|
|
735
738
|
else if (v === null) fields.push(`${goField}: nil`)
|
|
@@ -766,7 +769,19 @@ function goMapLiteralFromObject(
|
|
|
766
769
|
): string {
|
|
767
770
|
const entries: string[] = []
|
|
768
771
|
for (const [k, v] of Object.entries(obj)) {
|
|
769
|
-
|
|
772
|
+
// `goFieldNameForKey`, not a naive first-letter uppercase and not the
|
|
773
|
+
// bare `capitalizeFieldName` — #2168 nested-loop-triple-depth: a naive
|
|
774
|
+
// capitalize disagrees with the real adapter's Go-initialism-aware
|
|
775
|
+
// field naming for a key like `id` (naive → "Id", adapter's generated
|
|
776
|
+
// struct/template field → "ID"), so the harness baked a literal the
|
|
777
|
+
// template's `{{.ID}}` lookup could never match — the fixture's
|
|
778
|
+
// rendered fields came back empty at EVERY nesting depth for this
|
|
779
|
+
// reason, not because of any depth limit. `capitalizeFieldName` alone
|
|
780
|
+
// fixes the initialism case but still mis-bakes a non-identifier key
|
|
781
|
+
// (`'data-x'` → `"Data-x"`, not the adapter's own `"DataX"` —
|
|
782
|
+
// Copilot review, #2202); `goFieldNameForKey` is what the real adapter
|
|
783
|
+
// uses for exactly this key-to-Go-field sanitization.
|
|
784
|
+
const emittedKey = capitalizeKeys ? goFieldNameForKey(k) : k
|
|
770
785
|
const key = JSON.stringify(emittedKey)
|
|
771
786
|
if (typeof v === 'string') entries.push(`${key}: "${v.replace(/"/g, '\\"')}"`)
|
|
772
787
|
else if (typeof v === 'number') entries.push(`${key}: ${v}`)
|