@barefootjs/cli 0.1.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 (45) hide show
  1. package/dist/docs/core/README.md +84 -0
  2. package/dist/docs/core/adapters/adapter-architecture.md +262 -0
  3. package/dist/docs/core/adapters/csr.md +78 -0
  4. package/dist/docs/core/adapters/custom-adapter.md +357 -0
  5. package/dist/docs/core/adapters/go-template-adapter.md +269 -0
  6. package/dist/docs/core/adapters/hono-adapter.md +199 -0
  7. package/dist/docs/core/adapters.md +37 -0
  8. package/dist/docs/core/advanced/code-splitting.md +142 -0
  9. package/dist/docs/core/advanced/compiler-internals.md +331 -0
  10. package/dist/docs/core/advanced/error-codes.md +261 -0
  11. package/dist/docs/core/advanced/ir-schema.md +65 -0
  12. package/dist/docs/core/advanced/performance.md +115 -0
  13. package/dist/docs/core/advanced/xyflow-browser-bundle.md +69 -0
  14. package/dist/docs/core/advanced.md +11 -0
  15. package/dist/docs/core/components/children-slots.md +150 -0
  16. package/dist/docs/core/components/component-authoring.md +207 -0
  17. package/dist/docs/core/components/context-api.md +236 -0
  18. package/dist/docs/core/components/portals.md +192 -0
  19. package/dist/docs/core/components/props-type-safety.md +97 -0
  20. package/dist/docs/core/components/styling.md +37 -0
  21. package/dist/docs/core/components.md +19 -0
  22. package/dist/docs/core/core-concepts/ai-native.md +83 -0
  23. package/dist/docs/core/core-concepts/backend-freedom.md +31 -0
  24. package/dist/docs/core/core-concepts/how-it-works.md +147 -0
  25. package/dist/docs/core/core-concepts/mpa-style.md +36 -0
  26. package/dist/docs/core/core-concepts/reactivity.md +35 -0
  27. package/dist/docs/core/core-concepts.md +28 -0
  28. package/dist/docs/core/introduction.md +87 -0
  29. package/dist/docs/core/llms.txt +53 -0
  30. package/dist/docs/core/quick-start.mdx +160 -0
  31. package/dist/docs/core/reactivity/create-effect.md +125 -0
  32. package/dist/docs/core/reactivity/create-memo.md +91 -0
  33. package/dist/docs/core/reactivity/create-signal.md +128 -0
  34. package/dist/docs/core/reactivity/on-cleanup.md +67 -0
  35. package/dist/docs/core/reactivity/on-mount.md +70 -0
  36. package/dist/docs/core/reactivity/props-reactivity.md +91 -0
  37. package/dist/docs/core/reactivity/untrack.md +69 -0
  38. package/dist/docs/core/reactivity.md +28 -0
  39. package/dist/docs/core/rendering/client-directive.md +82 -0
  40. package/dist/docs/core/rendering/fragment.md +43 -0
  41. package/dist/docs/core/rendering/jsx-compatibility.md +163 -0
  42. package/dist/docs/core/rendering.md +14 -0
  43. package/dist/index.js +25490 -0
  44. package/dist/tokens.json +74 -0
  45. package/package.json +37 -0
@@ -0,0 +1,331 @@
1
+ ---
2
+ title: Compiler Internals
3
+ description: How the BarefootJS compiler transforms JSX into marked templates and client JavaScript.
4
+ ---
5
+
6
+ # Compiler Internals
7
+
8
+ ## Pipeline Overview
9
+
10
+ ```
11
+ ┌─────────────────────────────────────────────────────┐
12
+ │ JSX Source (.tsx with "use client") │
13
+ └──────────────────────┬──────────────────────────────┘
14
+
15
+ ┌──────────────────────┴──────────────────────────────┐
16
+ │ 1. Analyzer (analyzer.ts) │
17
+ │ Single-pass AST visitor │
18
+ │ Extracts: signals, memos, effects, props, types │
19
+ └──────────────────────┬──────────────────────────────┘
20
+
21
+ ┌──────────────────────┴──────────────────────────────┐
22
+ │ 2. JSX → IR (jsx-to-ir.ts) │
23
+ │ Transforms JSX AST to IR node tree │
24
+ │ Assigns slotIds, detects reactivity │
25
+ └──────────────────────┬──────────────────────────────┘
26
+
27
+ ┌────────────┴────────────┐
28
+ ↓ ↓
29
+ ┌─────────┴─────────┐ ┌───────────┴──────────┐
30
+ │ 3a. Adapter │ │ 3b. IR → Client JS │
31
+ │ IR → Template │ │ ir-to-client-js/ │
32
+ │ (e.g., Hono JSX) │ │ Hydration code │
33
+ └────────────────────┘ └──────────────────────┘
34
+ ```
35
+
36
+ ## Entry Points
37
+
38
+ ```typescript
39
+ // Async — reads files from disk
40
+ compileJSX(entryPath: string, readFile: ReadFileFn, options: CompileOptions): Promise<CompileResult>
41
+
42
+ // Sync — source string input
43
+ compileJSX(source: string, filePath: string, options: CompileOptions): CompileResult
44
+ ```
45
+
46
+ Both support multi-component files.
47
+
48
+ ---
49
+
50
+ ## Phase 1: Analysis
51
+
52
+ The analyzer (`analyzer.ts`) performs a **single-pass** AST walk using TypeScript's compiler API.
53
+
54
+ ### Extracted Data
55
+
56
+ | Category | Data | Example |
57
+ |----------|------|---------|
58
+ | Signals | getter/setter names, initial value, type | `[count, setCount] = createSignal(0)` |
59
+ | Memos | name, computation expression, type | `doubled = createMemo(() => count() * 2)` |
60
+ | Effects | effect body | `createEffect(() => { ... })` |
61
+ | onMounts | callback body | `onMount(() => { ... })` |
62
+ | Props | parameter style, type info, defaults | `(props: ButtonProps)` or `({ label }: Props)` |
63
+ | Imports | source, specifiers | `import { createSignal } from '@barefootjs/client'` |
64
+ | Constants | name, value, dependencies | `const baseClass = 'btn'` |
65
+ | Functions | name, body, parameters | `function handleClick() { ... }` |
66
+ | Types | interfaces, type aliases | `interface ButtonProps { ... }` |
67
+ | JSX Return | the return statement's JSX | `return <button>...</button>` |
68
+ | Conditional Returns | early returns inside `if` blocks | `if (loading) return <Spinner />` |
69
+
70
+ ### `"use client"` Validation
71
+
72
+ Files with reactive APIs but no `"use client"` emit **BF001**:
73
+
74
+ ```
75
+ error[BF001]: 'use client' directive required for components with createSignal
76
+ ```
77
+
78
+ ### Props Destructuring Detection
79
+
80
+ ```tsx
81
+ // ⚠️ BF043: Destructuring captures values once — may lose reactivity
82
+ function Child({ count }: Props) { ... }
83
+
84
+ // ✅ No warning — direct access maintains reactivity
85
+ function Child(props: Props) { ... }
86
+ ```
87
+
88
+ Suppress with `// @bf-ignore props-destructuring`.
89
+
90
+ ---
91
+
92
+ ## Phase 2: JSX → IR
93
+
94
+ `jsxToIR` (`jsx-to-ir.ts`) transforms the analyzed JSX AST into the IR node tree.
95
+
96
+ ### Reactivity Detection
97
+
98
+ Two-tier strategy to determine if an expression is reactive:
99
+
100
+ 1. **TypeChecker path** — Walks the AST and checks each node's type for the `Reactive<T>` brand via `checker.getTypeAtLocation()`. This detects all reactive getters: signals, memos, and library-provided reactive accessors (e.g., `FieldReturn.error`, `FormReturn.isSubmitting`).
101
+
102
+ 2. **Regex fallback** — Pattern-matches known signal/memo names and props references. Used when the TypeChecker cannot resolve imported types.
103
+
104
+ Reactive if any match:
105
+ - A `Reactive<T>`-branded type (via TypeChecker)
106
+ - A signal getter: `count()` — regex pattern `\bcount\s*\(`
107
+ - A memo: `doubled()` — same pattern
108
+ - A props reference: `props.value` — per-prop name matching (excludes `children`)
109
+ - A local constant derived from any of the above (taint analysis)
110
+
111
+ ### Slot ID Assignment
112
+
113
+ Elements receive a `slotId` when they have:
114
+
115
+ 1. Event handlers (`onClick`, `onInput`, etc.)
116
+ 2. Dynamic children (reactive expressions, loops, conditionals)
117
+ 3. Reactive attributes (`class={expr()}`, `value={signal()}`)
118
+ 4. Refs (`ref={callback}`)
119
+ 5. Component references (always need initialization)
120
+
121
+ ### Filter/Sort Chain Parsing
122
+
123
+ `.filter()` and `.sort()` chains before `.map()` are parsed for template-level evaluation:
124
+
125
+ ```tsx
126
+ {todos().filter(t => !t.done).sort((a, b) => a.date - b.date).map(t => (
127
+ <li key={t.id}>{t.name}</li>
128
+ ))}
129
+ ```
130
+
131
+ Simple patterns compile for template-level evaluation. Complex patterns trigger **BF021**. See [Error Codes](./error-codes.md#bf021--unsupported-jsx-pattern).
132
+
133
+ ### Auto Scope Wrapping
134
+
135
+ If the IR root is a Provider with no wrapper element, the compiler wraps it in `<div style="display:contents">` for scope identification during hydration.
136
+
137
+ ---
138
+
139
+ ## Phase 3a: Template Generation (Adapter)
140
+
141
+ See [Adapter Architecture](../adapters/adapter-architecture.md). Each adapter handles:
142
+ - `renderElement()` — HTML elements with hydration markers
143
+ - `renderExpression()` — Dynamic values in the target template language
144
+ - `renderConditional()` — Template-level conditionals
145
+ - `renderLoop()` — Template-level iteration (with filter/sort if supported)
146
+ - `renderComponent()` — Child component includes
147
+
148
+ ---
149
+
150
+ ## Phase 3b: Client JS Generation
151
+
152
+ ### 1. Element Collection
153
+
154
+ | Category | Description | Example |
155
+ |----------|-------------|---------|
156
+ | `interactiveElements` | Elements with event handlers | `<button onClick={...}>` |
157
+ | `dynamicElements` | Elements with reactive text | `<span>{count()}</span>` |
158
+ | `conditionalElements` | Ternary/logical conditionals | `{open() ? <A/> : <B/>}` |
159
+ | `loopElements` | Array `.map()` loops | `{items().map(...)}` |
160
+ | `refElements` | Elements with ref callbacks | `<input ref={inputRef}>` |
161
+ | `reactiveAttrs` | Elements with reactive attributes | `<div class={cls()}>` |
162
+ | `clientOnlyElements` | `/* @client */` expressions | Skipped during SSR |
163
+
164
+ ### 2. Dependency Resolution
165
+
166
+ ```typescript
167
+ // "Early" constants — no reactive deps, emitted first
168
+ const baseClass = 'btn'
169
+ const THRESHOLD = 10
170
+
171
+ // "Late" constants — reference signals/memos, emitted after signal creation
172
+ const displayValue = `Count: ${count()}`
173
+ ```
174
+
175
+ ### 3. Controlled Signal Detection
176
+
177
+ When a signal name matches a prop name:
178
+
179
+ ```tsx
180
+ function Switch(props: Props) {
181
+ const [checked, setChecked] = createSignal(props.checked ?? false)
182
+ // ^^^^^^^ matches props.checked
183
+ }
184
+ ```
185
+
186
+ A sync effect is generated:
187
+
188
+ ```javascript
189
+ createEffect(() => {
190
+ const __val = _p.checked
191
+ if (__val !== undefined) setChecked(__val)
192
+ })
193
+ ```
194
+
195
+ ### 4. Code Generation Order
196
+
197
+ ```javascript
198
+ import { $, $t, createEffect, createMemo, createSignal, hydrate, onMount } from '@barefootjs/client'
199
+
200
+ export function initCounter(__scope, _p = {}) {
201
+ if (!__scope) return
202
+
203
+ // 1. Early constants (no reactive deps)
204
+ const baseClass = 'counter'
205
+
206
+ // 2. Local functions / handlers (before signals so signal initializers
207
+ // can reference them, e.g., createSignal(toArray(_p.x)))
208
+ const handleClick = () => { setCount(n => n + 1) }
209
+
210
+ // 3. Signals, memos, controlled signal sync, and late constants
211
+ const [count, setCount] = createSignal(_p.initial ?? 0)
212
+ createEffect(() => { // controlled signal sync
213
+ const __val = _p.initial
214
+ if (__val !== undefined) setCount(__val)
215
+ })
216
+ const doubled = createMemo(() => count() * 2)
217
+
218
+ // 4. Element references (always destructured, always returns array)
219
+ // $() — regular elements: querySelector('[bf="id"]') within scope
220
+ // $t() — text nodes: find comment marker <!--bf:id-->
221
+ const [_s3] = $(__scope, 's3')
222
+ const [_s0, _s2] = $t(__scope, 's0', 's2')
223
+
224
+ // 5. Dynamic text updates
225
+ createEffect(() => {
226
+ const __val = count()
227
+ if (_s0 && !__val?.__isSlot) _s0.nodeValue = String(__val ?? '')
228
+ })
229
+
230
+ // 6. Reactive attribute updates
231
+ createEffect(() => {
232
+ if (_s3) { _s3.disabled = !!(count() > 10) }
233
+ })
234
+
235
+ // 7. Conditional updates (insert with comment markers)
236
+ // insert(__scope, 's4', () => isOpen(), trueBranch, falseBranch)
237
+
238
+ // 8. Loop updates (mapArray with reconciliation)
239
+ // mapArray(() => items(), _s5, null, (item, idx, existing) => { ... })
240
+
241
+ // 9. Event handlers
242
+ if (_s3) _s3.addEventListener('click', handleClick)
243
+
244
+ // 10. Reactive prop bindings / child component props
245
+ // 11. Ref callbacks
246
+ // 12. User-defined effects and onMounts
247
+ createEffect(() => { console.log('Count changed:', count()) })
248
+ onMount(() => { console.log('Mounted') })
249
+
250
+ // 13. Provider setup and child component initialization
251
+ }
252
+
253
+ // Registration: hydrate() registers the component and initializes all
254
+ // instances on the page. Template inclusion depends on two factors:
255
+ // 1. Static template (no signal deps) → always included
256
+ // 2. CSR fallback template → only when used as a child component
257
+ // Top-level-only components with signals skip template to save bytes.
258
+ hydrate('Counter', {
259
+ init: initCounter,
260
+ template: (_p) => `<div><p bf="s1">Count: <!--bf:s0-->${(0)}<!--/--></p>...</div>`
261
+ })
262
+ ```
263
+
264
+ ### 5. Import Detection
265
+
266
+ Only used imports are included:
267
+
268
+ ```javascript
269
+ import { $, $t, createEffect, createMemo, createSignal, hydrate, onMount } from '@barefootjs/client'
270
+ ```
271
+
272
+ ### 6. Template Registration
273
+
274
+ **Static template** — No signal-dependent expressions:
275
+
276
+ ```javascript
277
+ hydrate('Button', {
278
+ init: initButton,
279
+ template: (_p) => `<button ${(_p.className ?? '') != null ? 'class="' + (_p.className ?? '') + '"' : ''} bf="s0">${_p.children}</button>`
280
+ })
281
+ ```
282
+
283
+ **CSR fallback template** — Component has signals but is used as a child in the same file:
284
+
285
+ ```javascript
286
+ // StatusBadge is used by Dashboard in the same file → gets CSR fallback
287
+ hydrate('StatusBadge', {
288
+ init: initStatusBadge,
289
+ template: (_p) => `<span bf="s0">${_p.active ? 'on' : 'off'}</span>`
290
+ })
291
+
292
+ // Dashboard is top-level only → no template (saves bytes)
293
+ hydrate('Dashboard', { init: initDashboard })
294
+ ```
295
+
296
+ **No template** — Top-level-only components with signals. Hydrated from server HTML only.
297
+
298
+ ---
299
+
300
+ ## Multi-Component Files
301
+
302
+ Two-pass approach for multi-component files:
303
+
304
+ 1. **Pass 1** — Detect exports, analyze, and generate IR for each
305
+ 2. **Between passes** — Build `usedAsChild` set via `collectComponentNamesFromIR()`
306
+ 3. **Pass 2** — Generate templates and client JS; only child components get CSR fallback templates
307
+ 4. Merge templates (deduplicate imports/types) and client JS (combine imports)
308
+
309
+ ```tsx
310
+ // Both compiled from the same file
311
+ export function Button(props: ButtonProps) { ... }
312
+ export function IconButton(props: IconButtonProps) { ... }
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Debugging Tips
318
+
319
+ ### View the IR
320
+
321
+ ```typescript
322
+ const result = compileJSX(source, 'file.tsx', { adapter })
323
+ console.log(JSON.stringify(result.ir, null, 2))
324
+ ```
325
+
326
+ ### View generated client JS
327
+
328
+ ```typescript
329
+ console.log(result.clientJs)
330
+ ```
331
+
@@ -0,0 +1,261 @@
1
+ ---
2
+ title: Error Codes Reference
3
+ description: BF-prefixed compiler error codes with explanations and fixes.
4
+ ---
5
+
6
+ # Error Codes Reference
7
+
8
+ Errors follow the format `BF` + 3-digit code with source location and fix suggestions.
9
+
10
+ ## Format
11
+
12
+ ```
13
+ error[BF001]: 'use client' directive required for components with createSignal
14
+
15
+ --> src/components/Counter.tsx:3:1
16
+ |
17
+ 3 | import { createSignal } from '@barefootjs/client'
18
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19
+ |
20
+ = help: Add 'use client' at the top of the file
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Directive Errors (BF001–BF003)
26
+
27
+ ### BF001 — Missing `"use client"` Directive
28
+
29
+ **Trigger:** Reactive APIs used without `"use client"`.
30
+
31
+ ```tsx
32
+ // ❌ BF001
33
+ import { createSignal } from '@barefootjs/client'
34
+ export function Counter() {
35
+ const [count, setCount] = createSignal(0)
36
+ return <button onClick={() => setCount(n => n + 1)}>{count()}</button>
37
+ }
38
+ ```
39
+
40
+ **Fix:**
41
+
42
+ ```tsx
43
+ // ✅ Fixed
44
+ "use client"
45
+ import { createSignal } from '@barefootjs/client'
46
+ export function Counter() { ... }
47
+ ```
48
+
49
+ ### BF003 — Client Component Importing Server Component
50
+
51
+ **Trigger:** Client component imports from a file without `"use client"`.
52
+
53
+ **Fix:** Add `"use client"` to the imported file, or import only types/constants.
54
+
55
+ ---
56
+
57
+ ## Signal Errors (BF011)
58
+
59
+ ### BF011 — Module-Level Reactive Declaration
60
+
61
+ **Trigger:** A `createSignal` or `createMemo` call at module scope without a leading `/* @client */` directive.
62
+
63
+ ```tsx
64
+ 'use client'
65
+ import { createSignal } from '@barefootjs/client'
66
+ // ❌ BF011 — module-level signal without opt-in
67
+ const [count, setCount] = createSignal(0)
68
+ export function Counter() {
69
+ return <button onClick={() => setCount(count() + 1)}>{count()}</button>
70
+ }
71
+ ```
72
+
73
+ **Fix (option A):** Move the declaration inside the component function so each mount gets its own state.
74
+
75
+ ```tsx
76
+ 'use client'
77
+ import { createSignal } from '@barefootjs/client'
78
+
79
+ export function Counter() {
80
+ const [count, setCount] = createSignal(0)
81
+ return <button onClick={() => setCount(count() + 1)}>{count()}</button>
82
+ }
83
+ ```
84
+
85
+ **Fix (option B):** Prefix the declaration with `/* @client */` to opt into client-only module-scope state. The signal is emitted at module scope in the client bundle and SSR renders a placeholder for any reference. Intended for "global signal" / "store" patterns shared across components.
86
+
87
+ ```tsx
88
+ 'use client'
89
+ import { createSignal } from '@barefootjs/client'
90
+
91
+ /* @client */
92
+ const [count, setCount] = createSignal(0)
93
+
94
+ export function Counter() {
95
+ return <button onClick={() => setCount(count() + 1)}>{count()}</button>
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## JSX Errors (BF021–BF023)
102
+
103
+ ### BF021 — Unsupported JSX Pattern
104
+
105
+ **Trigger:** Array method chain before `.map()` cannot compile to SSR template.
106
+
107
+ #### SSR-Compatible Chains
108
+
109
+ - `.filter().map()`
110
+ - `.sort().map()` / `.toSorted().map()`
111
+ - `.filter().sort().map()`
112
+ - `.sort().filter().map()`
113
+
114
+ Other chains (`.reduce()`, `.slice()`, `.flatMap()`) fall back to client-side evaluation.
115
+
116
+ #### filter: Supported Predicates
117
+
118
+ - Property access: `t.done`, `t.price`
119
+ - Literals: `'active'`, `5`, `true`
120
+ - Comparison: `===`, `!==`, `>`, `<`, `>=`, `<=`
121
+ - Arithmetic: `+`, `-`, `*`, `/`, `%`
122
+ - Logical: `&&`, `||`, `!`
123
+ - Ternary: `cond ? a : b`
124
+
125
+ ```tsx
126
+ // ✅ SSR-compilable
127
+ {items().filter(t => !t.done).map(t => <li>{t.name}</li>)}
128
+ {items().filter(t => t.price > 100 && t.active).map(t => <li>{t.name}</li>)}
129
+
130
+ // ❌ BF021 — typeof, function calls, nested higher-order methods are not supported
131
+ {items().filter(t => typeof t === 'string').map(...)}
132
+ {items().filter(t => customFn(t)).map(...)}
133
+ {items().filter(t => t.tags.some(tag => tag.featured)).map(...)}
134
+ ```
135
+
136
+ #### sort: Supported Comparators
137
+
138
+ Simple subtraction: `(a, b) => a.field - b.field`:
139
+
140
+ ```tsx
141
+ // ✅ SSR-compilable
142
+ {items().sort((a, b) => a.price - b.price).map(...)} // ascending
143
+ {items().toSorted((a, b) => b.date - a.date).map(...)} // descending
144
+
145
+ // ❌ BF021 — block bodies, localeCompare, ternary operators, etc. are not supported
146
+ {items().sort((a, b) => { return a.price - b.price }).map(...)}
147
+ {items().sort((a, b) => a.name.localeCompare(b.name)).map(...)}
148
+ ```
149
+
150
+ #### Workaround
151
+
152
+ ```tsx
153
+ {/* @client */ todos().filter(t => t.items.some(i => i.done)).map(t => (
154
+ <li>{t.name}</li>
155
+ ))}
156
+ ```
157
+
158
+ ### BF023 — Missing Key in List
159
+
160
+ **Trigger:** `.map()` loop without `key` prop.
161
+
162
+ ```tsx
163
+ // ❌ BF023
164
+ {items().map(item => <li>{item.name}</li>)}
165
+ ```
166
+
167
+ **Fix:**
168
+
169
+ ```tsx
170
+ // ✅ Add key
171
+ {items().map(item => <li key={item.id}>{item.name}</li>)}
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Component Errors (BF043–BF044)
177
+
178
+ ### BF043 — Props Destructuring (Warning)
179
+
180
+ **Trigger:** Props destructured in function parameter.
181
+
182
+ ```tsx
183
+ // ⚠️ BF043
184
+ function Child({ count }: Props) {
185
+ return <span>{count}</span> // count is captured once
186
+ }
187
+ ```
188
+
189
+ ```
190
+ warning[BF043]: Destructuring props in function parameters captures values once.
191
+ = help: Use `props.count` for reactive access, or suppress with // @bf-ignore props-destructuring
192
+ ```
193
+
194
+ **Fix options:**
195
+
196
+ 1. Use direct props access:
197
+
198
+ ```tsx
199
+ function Child(props: Props) {
200
+ return <span>{props.count}</span> // Reactive
201
+ }
202
+ ```
203
+
204
+ 2. Suppress if intentional (static initial value):
205
+
206
+ ```tsx
207
+ // @bf-ignore props-destructuring
208
+ function Child({ initialCount }: Props) {
209
+ const [count, setCount] = createSignal(initialCount)
210
+ return <span>{count()}</span>
211
+ }
212
+ ```
213
+
214
+ ### BF044 — Signal/Memo Getter Not Called
215
+
216
+ **Trigger:** Signal/memo getter passed without calling it.
217
+
218
+ ```tsx
219
+ // ❌ BF044
220
+ <Child count={count} /> // Passing getter function, not the value
221
+ ```
222
+
223
+ **Fix:**
224
+
225
+ ```tsx
226
+ // ✅ Fixed
227
+ <Child count={count()} />
228
+ ```
229
+
230
+ ---
231
+
232
+ ## Suppressing Warnings
233
+
234
+ Suppress with `@bf-ignore`:
235
+
236
+ ```tsx
237
+ // @bf-ignore props-destructuring
238
+ function Component({ checked }: Props) {
239
+ // Warning suppressed
240
+ }
241
+ ```
242
+
243
+ **Available rules:**
244
+
245
+ | Rule ID | Error Code | Description |
246
+ |---------|------------|-------------|
247
+ | `props-destructuring` | BF043 | Props destructuring in function parameters |
248
+
249
+ ---
250
+
251
+ ## Error Code Quick Reference
252
+
253
+ | Code | Severity | Description |
254
+ |------|----------|-------------|
255
+ | BF001 | Error | Missing `"use client"` directive |
256
+ | BF003 | Error | Client component importing server component |
257
+ | BF011 | Error | Module-level reactive declaration without `/* @client */` |
258
+ | BF021 | Error | Unsupported JSX pattern for SSR |
259
+ | BF023 | Error | Missing key in list |
260
+ | BF043 | Warning | Props destructuring breaks reactivity |
261
+ | BF044 | Error | Signal/memo getter passed without calling it |
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: IR Schema Reference
3
+ description: JSON tree structure of the Intermediate Representation consumed by adapters and client-JS generation.
4
+ ---
5
+
6
+ # IR Schema Reference
7
+
8
+ The IR is a JSON tree between JSX parsing and output generation. Adapters consume IR without knowledge of the original JSX syntax.
9
+
10
+ ## Pipeline Position
11
+
12
+ ```
13
+ JSX Source → [Phase 1: analyzer + jsx-to-ir] → IR → [Phase 2a: adapter] → Template
14
+ → [Phase 2b: ir-to-client-js] → Client JS
15
+ ```
16
+
17
+ ## Node Types
18
+
19
+ Defined in [`packages/jsx/src/types.ts`](../../../packages/jsx/src/types.ts):
20
+
21
+ | Type | Description |
22
+ |------|-------------|
23
+ | `IRElement` | HTML/SVG element |
24
+ | `IRText` | Static text |
25
+ | `IRExpression` | Dynamic expression (`{braces}`) |
26
+ | `IRConditional` | Branching via ternary or logical expressions |
27
+ | `IRLoop` | List rendering via `.map()` (including filter/sort) |
28
+ | `IRComponent` | Child component reference |
29
+ | `IRFragment` | JSX fragment (`<>...</>`) |
30
+ | `IRIfStatement` | Early return within a component body |
31
+ | `IRProvider` | Context Provider |
32
+
33
+ ---
34
+
35
+ ## Hydration Markers
36
+
37
+ `slotId` and `needsScope` map to HTML attributes:
38
+
39
+ | IR Field | HTML Output | Purpose |
40
+ |----------|------------|---------|
41
+ | `needsScope: true` | `bf-s="ComponentName"` | Component root boundary |
42
+ | `slotId: "0"` | `bf="0"` | Reference for interactive elements |
43
+ | Conditional `slotId` | `bf-c="1"` | Anchor for conditional branches |
44
+
45
+
46
+ ---
47
+
48
+ ## Debugging
49
+
50
+ Pass `outputIR: true` to inspect the IR:
51
+
52
+ ```typescript
53
+ import { compileJSX } from '@barefootjs/jsx'
54
+
55
+ const result = compileJSX(source, 'Counter.tsx', {
56
+ adapter: new HonoAdapter(),
57
+ outputIR: true,
58
+ })
59
+
60
+ // result.ir contains the full ComponentIR
61
+ console.log(JSON.stringify(result.ir, null, 2))
62
+
63
+ // result.additionalFiles includes the *.ir.json file
64
+ // e.g., { path: 'Counter.ir.json', content: '...' }
65
+ ```