@pyreon/compiler 0.11.4 → 0.11.6

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.
@@ -1,1110 +1,1110 @@
1
- import { transformJSX } from "../jsx"
1
+ import { transformJSX } from '../jsx'
2
2
 
3
3
  // Helper: transform and return the code string
4
- const t = (code: string) => transformJSX(code, "input.tsx").code
4
+ const t = (code: string) => transformJSX(code, 'input.tsx').code
5
5
 
6
6
  // ─── Children ────────────────────────────────────────────────────────────────
7
7
 
8
- describe("JSX transform — children", () => {
9
- test("wraps dynamic child expression", () => {
10
- const result = t("<div>{count()}</div>")
11
- expect(result).toContain("_tpl(")
8
+ describe('JSX transform — children', () => {
9
+ test('wraps dynamic child expression', () => {
10
+ const result = t('<div>{count()}</div>')
11
+ expect(result).toContain('_tpl(')
12
12
  // Single-signal text binding uses _bindText for direct subscription
13
- expect(result).toContain("_bindText(count,")
13
+ expect(result).toContain('_bindText(count,')
14
14
  })
15
15
 
16
- test("does NOT wrap string literal child", () => {
17
- expect(t(`<div>{"static"}</div>`)).not.toContain("() =>")
16
+ test('does NOT wrap string literal child', () => {
17
+ expect(t(`<div>{"static"}</div>`)).not.toContain('() =>')
18
18
  })
19
19
 
20
- test("does NOT wrap numeric literal child", () => {
21
- expect(t("<div>{42}</div>")).not.toContain("() =>")
20
+ test('does NOT wrap numeric literal child', () => {
21
+ expect(t('<div>{42}</div>')).not.toContain('() =>')
22
22
  })
23
23
 
24
- test("does NOT wrap null child", () => {
25
- expect(t("<div>{null}</div>")).not.toContain("() =>")
24
+ test('does NOT wrap null child', () => {
25
+ expect(t('<div>{null}</div>')).not.toContain('() =>')
26
26
  })
27
27
 
28
- test("does NOT double-wrap existing arrow function", () => {
29
- const result = t("<div>{() => count()}</div>")
28
+ test('does NOT double-wrap existing arrow function', () => {
29
+ const result = t('<div>{() => count()}</div>')
30
30
  // Arrow should be unwrapped by template emission into _bindText(count, __t)
31
31
  // The original () => count() should NOT appear in the output
32
- expect(result).toContain("_bindText(count,")
33
- expect(result).not.toContain("() => count()")
32
+ expect(result).toContain('_bindText(count,')
33
+ expect(result).not.toContain('() => count()')
34
34
  })
35
35
 
36
- test("does NOT wrap a function expression child", () => {
37
- const result = t("<div>{function() { return x }}</div>")
36
+ test('does NOT wrap a function expression child', () => {
37
+ const result = t('<div>{function() { return x }}</div>')
38
38
  // Function expression body should be unwrapped by template emission
39
- expect(result).toContain("_bind")
39
+ expect(result).toContain('_bind')
40
40
  })
41
41
 
42
- test("does NOT wrap plain identifier (no call = not reactive)", () => {
43
- expect(t("<div>{title}</div>")).not.toContain("() =>")
42
+ test('does NOT wrap plain identifier (no call = not reactive)', () => {
43
+ expect(t('<div>{title}</div>')).not.toContain('() =>')
44
44
  })
45
45
 
46
- test("does NOT wrap ternary without calls", () => {
47
- expect(t("<div>{a ? b : c}</div>")).not.toContain("() =>")
46
+ test('does NOT wrap ternary without calls', () => {
47
+ expect(t('<div>{a ? b : c}</div>')).not.toContain('() =>')
48
48
  })
49
49
 
50
- test("wraps ternary that contains a call", () => {
51
- const result = t("<div>{a() ? b : c}</div>")
52
- expect(result).toContain("_tpl(")
53
- expect(result).toContain(".data = a() ? b : c")
50
+ test('wraps ternary that contains a call', () => {
51
+ const result = t('<div>{a() ? b : c}</div>')
52
+ expect(result).toContain('_tpl(')
53
+ expect(result).toContain('.data = a() ? b : c')
54
54
  })
55
55
 
56
- test("does NOT wrap logical expression without calls", () => {
57
- expect(t("<div>{show && <span />}</div>")).not.toContain("() =>")
56
+ test('does NOT wrap logical expression without calls', () => {
57
+ expect(t('<div>{show && <span />}</div>')).not.toContain('() =>')
58
58
  })
59
59
 
60
- test("wraps logical expression containing a call", () => {
61
- expect(t("<div>{show() && <span />}</div>")).toContain("() => show() && <span />")
60
+ test('wraps logical expression containing a call', () => {
61
+ expect(t('<div>{show() && <span />}</div>')).toContain('() => show() && <span />')
62
62
  })
63
63
 
64
- test("does NOT wrap object literal child", () => {
65
- expect(t("<div>{{ color: 'red' }}</div>")).not.toContain("() =>")
64
+ test('does NOT wrap object literal child', () => {
65
+ expect(t("<div>{{ color: 'red' }}</div>")).not.toContain('() =>')
66
66
  })
67
67
 
68
- test("does NOT wrap array literal child", () => {
69
- expect(t("<div>{[1, 2, 3]}</div>")).not.toContain("() =>")
68
+ test('does NOT wrap array literal child', () => {
69
+ expect(t('<div>{[1, 2, 3]}</div>')).not.toContain('() =>')
70
70
  })
71
71
 
72
- test("does NOT wrap boolean true literal", () => {
73
- expect(t("<div>{true}</div>")).not.toContain("() =>")
72
+ test('does NOT wrap boolean true literal', () => {
73
+ expect(t('<div>{true}</div>')).not.toContain('() =>')
74
74
  })
75
75
 
76
- test("does NOT wrap boolean false literal", () => {
77
- expect(t("<div>{false}</div>")).not.toContain("() =>")
76
+ test('does NOT wrap boolean false literal', () => {
77
+ expect(t('<div>{false}</div>')).not.toContain('() =>')
78
78
  })
79
79
 
80
- test("does NOT wrap undefined literal", () => {
81
- expect(t("<div>{undefined}</div>")).not.toContain("() =>")
80
+ test('does NOT wrap undefined literal', () => {
81
+ expect(t('<div>{undefined}</div>')).not.toContain('() =>')
82
82
  })
83
83
 
84
- test("does NOT wrap template literal without calls (no substitution)", () => {
85
- expect(t("<div>{`hello`}</div>")).not.toContain("() =>")
84
+ test('does NOT wrap template literal without calls (no substitution)', () => {
85
+ expect(t('<div>{`hello`}</div>')).not.toContain('() =>')
86
86
  })
87
87
 
88
- test("wraps template literal containing a call", () => {
89
- expect(t("<div>{`hello ${name()}`}</div>")).toContain("() =>")
88
+ test('wraps template literal containing a call', () => {
89
+ expect(t('<div>{`hello ${name()}`}</div>')).toContain('() =>')
90
90
  })
91
91
 
92
- test("wraps member access with call", () => {
93
- const result = t("<div>{obj.getValue()}</div>")
94
- expect(result).toContain("_tpl(")
92
+ test('wraps member access with call', () => {
93
+ const result = t('<div>{obj.getValue()}</div>')
94
+ expect(result).toContain('_tpl(')
95
95
  // Property access calls use _bind (not _bindText) to preserve this context
96
- expect(result).toContain("_bind")
96
+ expect(result).toContain('_bind')
97
97
  })
98
98
 
99
- test("does NOT wrap member access without call", () => {
100
- expect(t("<div>{obj.value}</div>")).not.toContain("() =>")
99
+ test('does NOT wrap member access without call', () => {
100
+ expect(t('<div>{obj.value}</div>')).not.toContain('() =>')
101
101
  })
102
102
 
103
- test("wraps binary expression containing a call", () => {
104
- const result = t("<div>{count() + 1}</div>")
105
- expect(result).toContain("_tpl(")
106
- expect(result).toContain(".data = count() + 1")
103
+ test('wraps binary expression containing a call', () => {
104
+ const result = t('<div>{count() + 1}</div>')
105
+ expect(result).toContain('_tpl(')
106
+ expect(result).toContain('.data = count() + 1')
107
107
  })
108
108
 
109
- test("does NOT wrap binary expression without calls", () => {
110
- expect(t("<div>{a + b}</div>")).not.toContain("() =>")
109
+ test('does NOT wrap binary expression without calls', () => {
110
+ expect(t('<div>{a + b}</div>')).not.toContain('() =>')
111
111
  })
112
112
 
113
- test("wraps tagged template expression", () => {
114
- expect(t("<div>{css`color: red`}</div>")).toContain("() =>")
113
+ test('wraps tagged template expression', () => {
114
+ expect(t('<div>{css`color: red`}</div>')).toContain('() =>')
115
115
  })
116
116
 
117
- test("empty JSX expression {} gets _tpl optimization", () => {
118
- const result = t("<div>{/* comment */}</div>")
119
- expect(result).toContain("_tpl(")
120
- expect(result).toContain("() => null")
117
+ test('empty JSX expression {} gets _tpl optimization', () => {
118
+ const result = t('<div>{/* comment */}</div>')
119
+ expect(result).toContain('_tpl(')
120
+ expect(result).toContain('() => null')
121
121
  })
122
122
  })
123
123
 
124
124
  // ─── Props ────────────────────────────────────────────────────────────────────
125
125
 
126
- describe("JSX transform — props", () => {
127
- test("wraps dynamic class prop", () => {
128
- expect(t("<div class={activeClass()} />")).toContain("() => activeClass()")
126
+ describe('JSX transform — props', () => {
127
+ test('wraps dynamic class prop', () => {
128
+ expect(t('<div class={activeClass()} />')).toContain('() => activeClass()')
129
129
  })
130
130
 
131
- test("wraps dynamic style prop", () => {
132
- expect(t("<div style={styles()} />")).toContain("() => styles()")
131
+ test('wraps dynamic style prop', () => {
132
+ expect(t('<div style={styles()} />')).toContain('() => styles()')
133
133
  })
134
134
 
135
- test("does NOT wrap string literal prop", () => {
136
- expect(t(`<div class="foo" />`)).not.toContain("() =>")
135
+ test('does NOT wrap string literal prop', () => {
136
+ expect(t(`<div class="foo" />`)).not.toContain('() =>')
137
137
  })
138
138
 
139
- test("does NOT wrap JSX string attribute", () => {
140
- expect(t(`<div class={"foo"} />`)).not.toContain("() =>")
139
+ test('does NOT wrap JSX string attribute', () => {
140
+ expect(t(`<div class={"foo"} />`)).not.toContain('() =>')
141
141
  })
142
142
 
143
- test("does NOT wrap onClick (event handler)", () => {
144
- const result = t("<button onClick={handleClick} />")
145
- expect(result).not.toContain("() => handleClick")
146
- expect(result).toContain("handleClick") // still present
143
+ test('does NOT wrap onClick (event handler)', () => {
144
+ const result = t('<button onClick={handleClick} />')
145
+ expect(result).not.toContain('() => handleClick')
146
+ expect(result).toContain('handleClick') // still present
147
147
  })
148
148
 
149
- test("does NOT wrap onInput (event handler)", () => {
150
- expect(t("<input onInput={handler} />")).not.toContain("() => handler")
149
+ test('does NOT wrap onInput (event handler)', () => {
150
+ expect(t('<input onInput={handler} />')).not.toContain('() => handler')
151
151
  })
152
152
 
153
- test("does NOT wrap onMouseEnter (event handler)", () => {
154
- expect(t("<div onMouseEnter={fn} />")).not.toContain("() => fn")
153
+ test('does NOT wrap onMouseEnter (event handler)', () => {
154
+ expect(t('<div onMouseEnter={fn} />')).not.toContain('() => fn')
155
155
  })
156
156
 
157
- test("does NOT wrap key prop", () => {
158
- expect(t("<div key={id} />")).not.toContain("() => id")
157
+ test('does NOT wrap key prop', () => {
158
+ expect(t('<div key={id} />')).not.toContain('() => id')
159
159
  })
160
160
 
161
- test("does NOT wrap ref prop", () => {
162
- expect(t("<div ref={myRef} />")).not.toContain("() => myRef")
161
+ test('does NOT wrap ref prop', () => {
162
+ expect(t('<div ref={myRef} />')).not.toContain('() => myRef')
163
163
  })
164
164
 
165
- test("does NOT wrap already-wrapped prop", () => {
166
- const result = t("<div class={() => cls()} />")
165
+ test('does NOT wrap already-wrapped prop', () => {
166
+ const result = t('<div class={() => cls()} />')
167
167
  expect(result.match(/\(\) =>/g)?.length).toBe(1)
168
168
  })
169
169
 
170
- test("does NOT wrap object literal prop (style)", () => {
171
- expect(t('<div style={{ color: "red" }} />')).not.toContain("() =>")
170
+ test('does NOT wrap object literal prop (style)', () => {
171
+ expect(t('<div style={{ color: "red" }} />')).not.toContain('() =>')
172
172
  })
173
173
 
174
- test("wraps object literal prop when it contains a call", () => {
175
- expect(t("<div style={{ color: theme() }} />")).toContain("() =>")
174
+ test('wraps object literal prop when it contains a call', () => {
175
+ expect(t('<div style={{ color: theme() }} />')).toContain('() =>')
176
176
  })
177
177
 
178
- test("does NOT wrap boolean shorthand attribute", () => {
178
+ test('does NOT wrap boolean shorthand attribute', () => {
179
179
  // <input disabled /> — no initializer at all
180
- expect(t("<input disabled />")).not.toContain("() =>")
180
+ expect(t('<input disabled />')).not.toContain('() =>')
181
181
  })
182
182
 
183
- test("wraps dynamic data-* attribute", () => {
184
- expect(t("<div data-id={getId()} />")).toContain("() => getId()")
183
+ test('wraps dynamic data-* attribute', () => {
184
+ expect(t('<div data-id={getId()} />')).toContain('() => getId()')
185
185
  })
186
186
 
187
- test("wraps dynamic aria-* attribute", () => {
188
- expect(t("<div aria-label={getLabel()} />")).toContain("() => getLabel()")
187
+ test('wraps dynamic aria-* attribute', () => {
188
+ expect(t('<div aria-label={getLabel()} />')).toContain('() => getLabel()')
189
189
  })
190
190
 
191
- test("does NOT wrap onFocus (event handler)", () => {
192
- expect(t("<input onFocus={handler} />")).not.toContain("() => handler")
191
+ test('does NOT wrap onFocus (event handler)', () => {
192
+ expect(t('<input onFocus={handler} />')).not.toContain('() => handler')
193
193
  })
194
194
 
195
- test("does NOT wrap onChange (event handler)", () => {
196
- expect(t("<input onChange={handler} />")).not.toContain("() => handler")
195
+ test('does NOT wrap onChange (event handler)', () => {
196
+ expect(t('<input onChange={handler} />')).not.toContain('() => handler')
197
197
  })
198
198
 
199
- test("wraps conditional prop expression with call", () => {
200
- expect(t("<div title={isActive() ? 'yes' : 'no'} />")).toContain("() =>")
199
+ test('wraps conditional prop expression with call', () => {
200
+ expect(t("<div title={isActive() ? 'yes' : 'no'} />")).toContain('() =>')
201
201
  })
202
202
  })
203
203
 
204
204
  // ─── Component elements ──────────────────────────────────────────────────────
205
205
 
206
- describe("JSX transform — component elements", () => {
207
- test("does NOT wrap props on component elements (uppercase tag)", () => {
208
- const result = t("<MyComponent value={count()} />")
209
- expect(result).not.toContain("() => count()")
210
- expect(result).toContain("count()")
206
+ describe('JSX transform — component elements', () => {
207
+ test('does NOT wrap props on component elements (uppercase tag)', () => {
208
+ const result = t('<MyComponent value={count()} />')
209
+ expect(result).not.toContain('() => count()')
210
+ expect(result).toContain('count()')
211
211
  })
212
212
 
213
- test("does NOT wrap any prop on uppercase component", () => {
214
- const result = t("<Button label={getText()} />")
215
- expect(result).not.toContain("() => getText()")
213
+ test('does NOT wrap any prop on uppercase component', () => {
214
+ const result = t('<Button label={getText()} />')
215
+ expect(result).not.toContain('() => getText()')
216
216
  })
217
217
 
218
- test("wraps children of component elements (via JSX expression)", () => {
218
+ test('wraps children of component elements (via JSX expression)', () => {
219
219
  // Children in expression containers are still wrapped
220
- const result = t("<MyComponent>{count()}</MyComponent>")
221
- expect(result).toContain("() => count()")
220
+ const result = t('<MyComponent>{count()}</MyComponent>')
221
+ expect(result).toContain('() => count()')
222
222
  })
223
223
 
224
- test("wraps props on lowercase DOM elements", () => {
225
- expect(t("<div title={getTitle()} />")).toContain("() => getTitle()")
224
+ test('wraps props on lowercase DOM elements', () => {
225
+ expect(t('<div title={getTitle()} />')).toContain('() => getTitle()')
226
226
  })
227
227
  })
228
228
 
229
229
  // ─── Spread attributes ──────────────────────────────────────────────────────
230
230
 
231
- describe("JSX transform — spread attributes", () => {
232
- test("spread props are left unchanged (not wrapped)", () => {
233
- const result = t("<div {...props} />")
231
+ describe('JSX transform — spread attributes', () => {
232
+ test('spread props are left unchanged (not wrapped)', () => {
233
+ const result = t('<div {...props} />')
234
234
  // Spread should remain as-is, no reactive wrapping
235
- expect(result).toContain("{...props}")
236
- expect(result).not.toContain("() => ...props")
235
+ expect(result).toContain('{...props}')
236
+ expect(result).not.toContain('() => ...props')
237
237
  })
238
238
 
239
- test("spread with other props — only non-spread dynamic props get wrapped", () => {
240
- const result = t("<div {...props} class={cls()} />")
241
- expect(result).toContain("{...props}")
242
- expect(result).toContain("() => cls()")
239
+ test('spread with other props — only non-spread dynamic props get wrapped', () => {
240
+ const result = t('<div {...props} class={cls()} />')
241
+ expect(result).toContain('{...props}')
242
+ expect(result).toContain('() => cls()')
243
243
  })
244
244
  })
245
245
 
246
246
  // ─── Static hoisting ─────────────────────────────────────────────────────────
247
247
 
248
- describe("JSX transform — static hoisting", () => {
249
- test("hoists static JSX child to module scope", () => {
250
- const result = t("<div>{<span>Hello</span>}</div>")
251
- expect(result).toContain("const _$h0")
252
- expect(result).toContain("<span>Hello</span>")
253
- expect(result).toContain("{_$h0}")
248
+ describe('JSX transform — static hoisting', () => {
249
+ test('hoists static JSX child to module scope', () => {
250
+ const result = t('<div>{<span>Hello</span>}</div>')
251
+ expect(result).toContain('const _$h0')
252
+ expect(result).toContain('<span>Hello</span>')
253
+ expect(result).toContain('{_$h0}')
254
254
  })
255
255
 
256
- test("hoists static self-closing JSX", () => {
257
- const result = t("<div>{<br />}</div>")
258
- expect(result).toContain("const _$h0")
259
- expect(result).toContain("{_$h0}")
256
+ test('hoists static self-closing JSX', () => {
257
+ const result = t('<div>{<br />}</div>')
258
+ expect(result).toContain('const _$h0')
259
+ expect(result).toContain('{_$h0}')
260
260
  })
261
261
 
262
- test("does NOT hoist JSX with dynamic props", () => {
263
- const result = t("<div>{<span class={cls()}>text</span>}</div>")
264
- expect(result).not.toContain("const _$h0")
262
+ test('does NOT hoist JSX with dynamic props', () => {
263
+ const result = t('<div>{<span class={cls()}>text</span>}</div>')
264
+ expect(result).not.toContain('const _$h0')
265
265
  })
266
266
 
267
- test("hoists JSX with static string prop", () => {
267
+ test('hoists JSX with static string prop', () => {
268
268
  const result = t(`<div>{<span class="foo">text</span>}</div>`)
269
- expect(result).toContain("const _$h0")
269
+ expect(result).toContain('const _$h0')
270
270
  })
271
271
 
272
- test("hoists multiple static JSX children independently", () => {
273
- const result = t("<div>{<span>A</span>}{<span>B</span>}</div>")
274
- expect(result).toContain("const _$h0")
275
- expect(result).toContain("const _$h1")
272
+ test('hoists multiple static JSX children independently', () => {
273
+ const result = t('<div>{<span>A</span>}{<span>B</span>}</div>')
274
+ expect(result).toContain('const _$h0')
275
+ expect(result).toContain('const _$h1')
276
276
  })
277
277
 
278
- test("hoists static fragment", () => {
279
- const result = t("<div>{<>text</>}</div>")
280
- expect(result).toContain("const _$h0")
278
+ test('hoists static fragment', () => {
279
+ const result = t('<div>{<>text</>}</div>')
280
+ expect(result).toContain('const _$h0')
281
281
  })
282
282
 
283
- test("does NOT hoist fragment with dynamic child", () => {
284
- const result = t("<div>{<>{count()}</>}</div>")
285
- expect(result).not.toContain("const _$h0")
283
+ test('does NOT hoist fragment with dynamic child', () => {
284
+ const result = t('<div>{<>{count()}</>}</div>')
285
+ expect(result).not.toContain('const _$h0')
286
286
  })
287
287
 
288
- test("hoisted declarations include @__PURE__ annotation", () => {
289
- const result = t("<div>{<span>Hello</span>}</div>")
290
- expect(result).toContain("/*@__PURE__*/")
288
+ test('hoisted declarations include @__PURE__ annotation', () => {
289
+ const result = t('<div>{<span>Hello</span>}</div>')
290
+ expect(result).toContain('/*@__PURE__*/')
291
291
  })
292
292
 
293
- test("does NOT hoist JSX with spread attributes (always dynamic)", () => {
294
- const result = t("<div>{<span {...props}>text</span>}</div>")
295
- expect(result).not.toContain("const _$h0")
293
+ test('does NOT hoist JSX with spread attributes (always dynamic)', () => {
294
+ const result = t('<div>{<span {...props}>text</span>}</div>')
295
+ expect(result).not.toContain('const _$h0')
296
296
  })
297
297
  })
298
298
 
299
299
  // ─── Mixed ────────────────────────────────────────────────────────────────────
300
300
 
301
- describe("JSX transform — mixed", () => {
302
- test("wraps props and children independently", () => {
303
- const result = t("<div class={cls()}>{text()}</div>")
304
- expect(result).toContain("_tpl(")
301
+ describe('JSX transform — mixed', () => {
302
+ test('wraps props and children independently', () => {
303
+ const result = t('<div class={cls()}>{text()}</div>')
304
+ expect(result).toContain('_tpl(')
305
305
  // className uses _bindDirect (single-signal), text uses _bindText
306
- expect(result).toContain("_bindDirect(cls,")
307
- expect(result).toContain("_bindText(text,")
306
+ expect(result).toContain('_bindDirect(cls,')
307
+ expect(result).toContain('_bindText(text,')
308
308
  })
309
309
 
310
- test("preserves static siblings of dynamic children", () => {
311
- const result = t("<div>static{count()}</div>")
312
- expect(result).toContain("_tpl(")
313
- expect(result).toContain("static")
314
- expect(result).toContain("_bindText(count,")
310
+ test('preserves static siblings of dynamic children', () => {
311
+ const result = t('<div>static{count()}</div>')
312
+ expect(result).toContain('_tpl(')
313
+ expect(result).toContain('static')
314
+ expect(result).toContain('_bindText(count,')
315
315
  })
316
316
 
317
- test("leaves code outside JSX completely unchanged", () => {
318
- const input = "const x = count() + 1"
317
+ test('leaves code outside JSX completely unchanged', () => {
318
+ const input = 'const x = count() + 1'
319
319
  expect(t(input)).toBe(input)
320
320
  })
321
321
 
322
- test("handles multiple JSX elements in one file", () => {
322
+ test('handles multiple JSX elements in one file', () => {
323
323
  const input = `
324
324
  const A = <div>{a()}</div>
325
325
  const B = <span>{b()}</span>
326
326
  `
327
327
  const result = t(input)
328
- expect(result).toContain("_tpl(")
329
- expect(result).toContain("_bindText(a,")
330
- expect(result).toContain("_bindText(b,")
328
+ expect(result).toContain('_tpl(')
329
+ expect(result).toContain('_bindText(a,')
330
+ expect(result).toContain('_bindText(b,')
331
331
  })
332
332
 
333
- test("handles deeply nested JSX", () => {
334
- const result = t("<div><span><em>{count()}</em></span></div>")
333
+ test('handles deeply nested JSX', () => {
334
+ const result = t('<div><span><em>{count()}</em></span></div>')
335
335
  // Template emission: 3 DOM elements → _tpl() call with _bindText binding
336
- expect(result).toContain("_tpl(")
337
- expect(result).toContain("_bindText(count,")
336
+ expect(result).toContain('_tpl(')
337
+ expect(result).toContain('_bindText(count,')
338
338
  })
339
339
 
340
- test("returns unchanged code when no JSX present", () => {
341
- const input = "const x = 1 + 2"
340
+ test('returns unchanged code when no JSX present', () => {
341
+ const input = 'const x = 1 + 2'
342
342
  expect(t(input)).toBe(input)
343
343
  })
344
344
 
345
- test("handles empty JSX element", () => {
346
- const result = t("<div></div>")
347
- expect(result).toContain("_tpl(")
348
- expect(result).toContain("<div></div>")
349
- expect(result).toContain("() => null")
345
+ test('handles empty JSX element', () => {
346
+ const result = t('<div></div>')
347
+ expect(result).toContain('_tpl(')
348
+ expect(result).toContain('<div></div>')
349
+ expect(result).toContain('() => null')
350
350
  })
351
351
 
352
- test("handles self-closing element with no props", () => {
353
- const result = t("<br />")
354
- expect(result).toBe("<br />")
352
+ test('handles self-closing element with no props', () => {
353
+ const result = t('<br />')
354
+ expect(result).toBe('<br />')
355
355
  })
356
356
  })
357
357
 
358
358
  // ─── Edge cases ──────────────────────────────────────────────────────────────
359
359
 
360
- describe("JSX transform — edge cases", () => {
361
- test("wraps chained method call", () => {
362
- expect(t("<div>{items().map(x => x)}</div>")).toContain("() =>")
360
+ describe('JSX transform — edge cases', () => {
361
+ test('wraps chained method call', () => {
362
+ expect(t('<div>{items().map(x => x)}</div>')).toContain('() =>')
363
363
  })
364
364
 
365
- test("does not emit _bindText for method calls (preserves this context)", () => {
365
+ test('does not emit _bindText for method calls (preserves this context)', () => {
366
366
  // value.toLocaleString() — property access must NOT use _bindText
367
367
  // because detaching the method loses `this` context
368
- const result = t("<div><p>{value.toLocaleString()}</p></div>")
369
- expect(result).not.toContain("_bindText(value.toLocaleString,")
370
- expect(result).toContain("_bind")
368
+ const result = t('<div><p>{value.toLocaleString()}</p></div>')
369
+ expect(result).not.toContain('_bindText(value.toLocaleString,')
370
+ expect(result).toContain('_bind')
371
371
  })
372
372
 
373
- test("toLocaleString on signal read preserves this context", () => {
373
+ test('toLocaleString on signal read preserves this context', () => {
374
374
  // {() => count().toLocaleString()} should NOT detach .toLocaleString
375
- const result = t("<div>{() => count().toLocaleString()}</div>")
376
- expect(result).not.toContain("_bindText(count,")
375
+ const result = t('<div>{() => count().toLocaleString()}</div>')
376
+ expect(result).not.toContain('_bindText(count,')
377
377
  // The arrow wraps a chained call — it should use _bind, not _bindText
378
- expect(result).toContain("_bind")
378
+ expect(result).toContain('_bind')
379
379
  })
380
380
 
381
- test("wraps nested call in array expression", () => {
382
- expect(t("<div>{[getItem()]}</div>")).toContain("() =>")
381
+ test('wraps nested call in array expression', () => {
382
+ expect(t('<div>{[getItem()]}</div>')).toContain('() =>')
383
383
  })
384
384
 
385
- test("handles JSX with only text children (no expression)", () => {
386
- const result = t("<div>hello world</div>")
387
- expect(result).toContain("_tpl(")
388
- expect(result).toContain("hello world")
389
- expect(result).toContain("() => null")
385
+ test('handles JSX with only text children (no expression)', () => {
386
+ const result = t('<div>hello world</div>')
387
+ expect(result).toContain('_tpl(')
388
+ expect(result).toContain('hello world')
389
+ expect(result).toContain('() => null')
390
390
  })
391
391
 
392
- test("does NOT wrap arrow function with params", () => {
393
- const result = t("<div>{(x: number) => x + 1}</div>")
394
- expect(result).not.toContain("() => (x")
392
+ test('does NOT wrap arrow function with params', () => {
393
+ const result = t('<div>{(x: number) => x + 1}</div>')
394
+ expect(result).not.toContain('() => (x')
395
395
  })
396
396
 
397
- test("handles .jsx file extension", () => {
398
- const result = transformJSX("<div>{count()}</div>", "file.jsx").code
399
- expect(result).toContain("_tpl(")
400
- expect(result).toContain("_bindText(count,")
397
+ test('handles .jsx file extension', () => {
398
+ const result = transformJSX('<div>{count()}</div>', 'file.jsx').code
399
+ expect(result).toContain('_tpl(')
400
+ expect(result).toContain('_bindText(count,')
401
401
  })
402
402
 
403
- test("handles .ts file extension (treated as TSX)", () => {
404
- const result = transformJSX("<div>{count()}</div>", "file.ts").code
405
- expect(result).toContain("_tpl(")
406
- expect(result).toContain("_bindText(count,")
403
+ test('handles .ts file extension (treated as TSX)', () => {
404
+ const result = transformJSX('<div>{count()}</div>', 'file.ts').code
405
+ expect(result).toContain('_tpl(')
406
+ expect(result).toContain('_bindText(count,')
407
407
  })
408
408
 
409
- test("wraps call inside array map", () => {
410
- expect(t("<ul>{items().map(i => <li>{i}</li>)}</ul>")).toContain("() =>")
409
+ test('wraps call inside array map', () => {
410
+ expect(t('<ul>{items().map(i => <li>{i}</li>)}</ul>')).toContain('() =>')
411
411
  })
412
412
 
413
- test("does NOT wrap callback function expression inside event prop", () => {
414
- const result = t("<button onClick={() => doSomething()} />")
413
+ test('does NOT wrap callback function expression inside event prop', () => {
414
+ const result = t('<button onClick={() => doSomething()} />')
415
415
  // onClick is an event handler, should not be wrapped at all
416
- expect(result).not.toContain("() => () =>")
416
+ expect(result).not.toContain('() => () =>')
417
417
  })
418
418
 
419
- test("wraps call deep in property access chain", () => {
420
- expect(t("<div>{store.getState().count}</div>")).toContain("() =>")
419
+ test('wraps call deep in property access chain', () => {
420
+ expect(t('<div>{store.getState().count}</div>')).toContain('() =>')
421
421
  })
422
422
 
423
- test("does NOT wrap function expression child (named)", () => {
424
- const result = t("<div>{function foo() { return 1 }}</div>")
425
- expect(result).not.toContain("() => function")
423
+ test('does NOT wrap function expression child (named)', () => {
424
+ const result = t('<div>{function foo() { return 1 }}</div>')
425
+ expect(result).not.toContain('() => function')
426
426
  })
427
427
  })
428
428
 
429
429
  // ─── TransformResult type ────────────────────────────────────────────────────
430
430
 
431
- describe("transformJSX return value", () => {
432
- test("returns object with code property", () => {
433
- const result = transformJSX("<div>{count()}</div>")
434
- expect(typeof result.code).toBe("string")
431
+ describe('transformJSX return value', () => {
432
+ test('returns object with code property', () => {
433
+ const result = transformJSX('<div>{count()}</div>')
434
+ expect(typeof result.code).toBe('string')
435
435
  })
436
436
 
437
- test("default filename is input.tsx", () => {
437
+ test('default filename is input.tsx', () => {
438
438
  // Should not throw with default filename
439
- const result = transformJSX("<div>{count()}</div>")
440
- expect(result.code).toContain("_tpl(")
441
- expect(result.code).toContain("_bindText(count,")
439
+ const result = transformJSX('<div>{count()}</div>')
440
+ expect(result.code).toContain('_tpl(')
441
+ expect(result.code).toContain('_bindText(count,')
442
442
  })
443
443
  })
444
444
 
445
445
  // ─── Template emission ──────────────────────────────────────────────────────
446
446
 
447
- describe("JSX transform — template emission", () => {
448
- test("emits _tpl for 2+ element tree", () => {
449
- const result = t("<div><span>hello</span></div>")
450
- expect(result).toContain("_tpl(")
451
- expect(result).toContain("<div><span>hello</span></div>")
447
+ describe('JSX transform — template emission', () => {
448
+ test('emits _tpl for 2+ element tree', () => {
449
+ const result = t('<div><span>hello</span></div>')
450
+ expect(result).toContain('_tpl(')
451
+ expect(result).toContain('<div><span>hello</span></div>')
452
452
  })
453
453
 
454
- test("emits _tpl for single element", () => {
455
- const result = t("<div>hello</div>")
456
- expect(result).toContain("_tpl(")
457
- expect(result).toContain("hello")
454
+ test('emits _tpl for single element', () => {
455
+ const result = t('<div>hello</div>')
456
+ expect(result).toContain('_tpl(')
457
+ expect(result).toContain('hello')
458
458
  })
459
459
 
460
- test("does NOT emit _tpl for component elements", () => {
461
- const result = t("<div><MyComponent /></div>")
462
- expect(result).not.toContain("_tpl(")
460
+ test('does NOT emit _tpl for component elements', () => {
461
+ const result = t('<div><MyComponent /></div>')
462
+ expect(result).not.toContain('_tpl(')
463
463
  })
464
464
 
465
- test("does NOT emit _tpl for spread attributes", () => {
466
- const result = t("<div {...props}><span /></div>")
467
- expect(result).not.toContain("_tpl(")
465
+ test('does NOT emit _tpl for spread attributes', () => {
466
+ const result = t('<div {...props}><span /></div>')
467
+ expect(result).not.toContain('_tpl(')
468
468
  })
469
469
 
470
- test("does NOT emit _tpl for keyed elements", () => {
471
- const result = t("<div key={id}><span /></div>")
472
- expect(result).not.toContain("_tpl(")
470
+ test('does NOT emit _tpl for keyed elements', () => {
471
+ const result = t('<div key={id}><span /></div>')
472
+ expect(result).not.toContain('_tpl(')
473
473
  })
474
474
 
475
- test("bakes static string attributes into HTML", () => {
475
+ test('bakes static string attributes into HTML', () => {
476
476
  const result = t('<div class="box"><span /></div>')
477
477
  // Quotes are escaped inside the _tpl("...") string literal
478
478
  expect(result).toContain('class=\\"box\\"')
479
- expect(result).toContain("_tpl(")
479
+ expect(result).toContain('_tpl(')
480
480
  })
481
481
 
482
- test("bakes boolean shorthand attributes into HTML", () => {
483
- const result = t("<div><input disabled /></div>")
484
- expect(result).toContain(" disabled")
485
- expect(result).toContain("_tpl(")
482
+ test('bakes boolean shorthand attributes into HTML', () => {
483
+ const result = t('<div><input disabled /></div>')
484
+ expect(result).toContain(' disabled')
485
+ expect(result).toContain('_tpl(')
486
486
  })
487
487
 
488
- test("generates _bindDirect for reactive class with single signal", () => {
489
- const result = t("<div class={cls()}><span /></div>")
490
- expect(result).toContain("_bindDirect(cls,")
491
- expect(result).toContain("className")
488
+ test('generates _bindDirect for reactive class with single signal', () => {
489
+ const result = t('<div class={cls()}><span /></div>')
490
+ expect(result).toContain('_bindDirect(cls,')
491
+ expect(result).toContain('className')
492
492
  })
493
493
 
494
- test("generates _bindText for reactive text child with single signal", () => {
495
- const result = t("<div><span>{name()}</span></div>")
496
- expect(result).toContain("_bindText(name,")
494
+ test('generates _bindText for reactive text child with single signal', () => {
495
+ const result = t('<div><span>{name()}</span></div>')
496
+ expect(result).toContain('_bindText(name,')
497
497
  })
498
498
 
499
- test("generates one-time set for static expression text", () => {
500
- const result = t("<div><span>{label}</span></div>")
501
- expect(result).toContain("textContent = label")
502
- expect(result).not.toContain("_bind(")
499
+ test('generates one-time set for static expression text', () => {
500
+ const result = t('<div><span>{label}</span></div>')
501
+ expect(result).toContain('textContent = label')
502
+ expect(result).not.toContain('_bind(')
503
503
  })
504
504
 
505
- test("generates delegated event for common events", () => {
506
- const result = t("<div><button onClick={handler}>click</button></div>")
505
+ test('generates delegated event for common events', () => {
506
+ const result = t('<div><button onClick={handler}>click</button></div>')
507
507
  // click is delegated — uses expando property instead of addEventListener
508
- expect(result).toContain("__ev_click = handler")
508
+ expect(result).toContain('__ev_click = handler')
509
509
  })
510
510
 
511
- test("uses element children indexing for nested access", () => {
512
- const result = t("<div><span>{a()}</span><em>{b()}</em></div>")
511
+ test('uses element children indexing for nested access', () => {
512
+ const result = t('<div><span>{a()}</span><em>{b()}</em></div>')
513
513
  // Can't have two expression children in same parent, but each is in its own element
514
- expect(result).toContain("__root.children[0]")
515
- expect(result).toContain("__root.children[1]")
514
+ expect(result).toContain('__root.children[0]')
515
+ expect(result).toContain('__root.children[1]')
516
516
  })
517
517
 
518
- test("handles deeply nested element paths", () => {
519
- const result = t("<table><tbody><tr><td>{text()}</td></tr></tbody></table>")
520
- expect(result).toContain("_tpl(")
521
- expect(result).toContain("_bindText(text,")
518
+ test('handles deeply nested element paths', () => {
519
+ const result = t('<table><tbody><tr><td>{text()}</td></tr></tbody></table>')
520
+ expect(result).toContain('_tpl(')
521
+ expect(result).toContain('_bindText(text,')
522
522
  })
523
523
 
524
- test("adds template imports when _tpl is emitted", () => {
525
- const result = transformJSX("<div><span>text</span></div>")
524
+ test('adds template imports when _tpl is emitted', () => {
525
+ const result = transformJSX('<div><span>text</span></div>')
526
526
  expect(result.code).toContain('import { _tpl } from "@pyreon/runtime-dom"')
527
527
  expect(result.usesTemplates).toBe(true)
528
528
  })
529
529
 
530
- test("adds template imports for single element", () => {
531
- const result = transformJSX("<div>text</div>")
530
+ test('adds template imports for single element', () => {
531
+ const result = transformJSX('<div>text</div>')
532
532
  expect(result.code).toContain('import { _tpl } from "@pyreon/runtime-dom"')
533
533
  expect(result.usesTemplates).toBe(true)
534
534
  })
535
535
 
536
- test("wraps _tpl call in braces when child of JSX element", () => {
536
+ test('wraps _tpl call in braces when child of JSX element', () => {
537
537
  // <Comp> is a component, so outer element is not templateized
538
538
  // but <span><em> inside it has 2 elements
539
- const result = t("<Comp><span><em>text</em></span></Comp>")
539
+ const result = t('<Comp><span><em>text</em></span></Comp>')
540
540
  // The inner span+em gets templateized inside the component children
541
- expect(result).toContain("{_tpl(")
541
+ expect(result).toContain('{_tpl(')
542
542
  })
543
543
 
544
- test("handles self-closing void elements in template", () => {
545
- const result = t("<div><br /><span>text</span></div>")
546
- expect(result).toContain("_tpl(")
547
- expect(result).toContain("<br>")
548
- expect(result).not.toContain("</br>")
544
+ test('handles self-closing void elements in template', () => {
545
+ const result = t('<div><br /><span>text</span></div>')
546
+ expect(result).toContain('_tpl(')
547
+ expect(result).toContain('<br>')
548
+ expect(result).not.toContain('</br>')
549
549
  })
550
550
 
551
- test("handles mixed static text and element children", () => {
551
+ test('handles mixed static text and element children', () => {
552
552
  const result = t('<div class="c"><span>inner</span></div>')
553
- expect(result).toContain("_tpl(")
554
- expect(result).toContain("<span>inner</span>")
553
+ expect(result).toContain('_tpl(')
554
+ expect(result).toContain('<span>inner</span>')
555
555
  })
556
556
 
557
- test("escapes quotes in HTML attribute values", () => {
557
+ test('escapes quotes in HTML attribute values', () => {
558
558
  const result = t('<div title="say &quot;hi&quot;"><span /></div>')
559
- expect(result).toContain("_tpl(")
559
+ expect(result).toContain('_tpl(')
560
560
  })
561
561
 
562
- test("returns null cleanup when no dynamic bindings", () => {
563
- const result = t("<div><span>static</span></div>")
564
- expect(result).toContain("() => null")
562
+ test('returns null cleanup when no dynamic bindings', () => {
563
+ const result = t('<div><span>static</span></div>')
564
+ expect(result).toContain('() => null')
565
565
  })
566
566
 
567
- test("composes multiple disposers in cleanup", () => {
568
- const result = t("<div class={a()}><span>{b()}</span></div>")
569
- expect(result).toContain("__d0()")
570
- expect(result).toContain("__d1()")
567
+ test('composes multiple disposers in cleanup', () => {
568
+ const result = t('<div class={a()}><span>{b()}</span></div>')
569
+ expect(result).toContain('__d0()')
570
+ expect(result).toContain('__d1()')
571
571
  })
572
572
 
573
- test("maps className to class in HTML", () => {
573
+ test('maps className to class in HTML', () => {
574
574
  const result = t('<div className="box"><span /></div>')
575
575
  // Quotes escaped in _tpl string literal
576
576
  expect(result).toContain('class=\\"box\\"')
577
- expect(result).not.toContain("className")
577
+ expect(result).not.toContain('className')
578
578
  })
579
579
 
580
- test("maps htmlFor to for in HTML", () => {
580
+ test('maps htmlFor to for in HTML', () => {
581
581
  const result = t('<div><label htmlFor="name">Name</label></div>')
582
582
  expect(result).toContain('for=\\"name\\"')
583
583
  })
584
584
 
585
- test("inlines fragments inside template", () => {
586
- const result = t("<div><><span>text</span></></div>")
585
+ test('inlines fragments inside template', () => {
586
+ const result = t('<div><><span>text</span></></div>')
587
587
  // Fragment children are inlined as direct children
588
- expect(result).toContain("_tpl(")
589
- expect(result).toContain("<span>text</span>")
588
+ expect(result).toContain('_tpl(')
589
+ expect(result).toContain('<span>text</span>')
590
590
  })
591
591
 
592
- test("bails on expression children containing JSX", () => {
593
- const result = t("<div><span />{show() && <em />}</div>")
594
- expect(result).not.toContain("_tpl(")
592
+ test('bails on expression children containing JSX', () => {
593
+ const result = t('<div><span />{show() && <em />}</div>')
594
+ expect(result).not.toContain('_tpl(')
595
595
  })
596
596
 
597
- test("handles mixed element + expression children", () => {
598
- const result = t("<div><span />{text()}</div>")
597
+ test('handles mixed element + expression children', () => {
598
+ const result = t('<div><span />{text()}</div>')
599
599
  // Mixed element + expression children use childNodes indexing
600
- expect(result).toContain("_tpl(")
601
- expect(result).toContain("childNodes[")
602
- expect(result).toContain("_bindText(text,")
600
+ expect(result).toContain('_tpl(')
601
+ expect(result).toContain('childNodes[')
602
+ expect(result).toContain('_bindText(text,')
603
603
  })
604
604
 
605
- test("benchmark-like row structure", () => {
605
+ test('benchmark-like row structure', () => {
606
606
  const result = t(
607
607
  '<tr class={cls()}><td class="id">{String(row.id)}</td><td>{row.label()}</td></tr>',
608
608
  )
609
- expect(result).toContain("_tpl(")
609
+ expect(result).toContain('_tpl(')
610
610
  expect(result).toContain('<td class=\\"id\\"></td><td></td>')
611
611
  // className uses _bindDirect (single-signal cls())
612
- expect(result).toContain("_bindDirect(cls,")
612
+ expect(result).toContain('_bindDirect(cls,')
613
613
  // String(row.id) has args → combined _bind; row.label() is property access → _bind
614
- expect(result).toContain(".data = String(row.id)")
615
- expect(result).toContain("row.label()")
614
+ expect(result).toContain('.data = String(row.id)')
615
+ expect(result).toContain('row.label()')
616
616
  })
617
617
 
618
- test("handles multiple expression children", () => {
619
- const result = t("<div><span>{a()}{b()}</span></div>")
620
- expect(result).toContain("_tpl(")
618
+ test('handles multiple expression children', () => {
619
+ const result = t('<div><span>{a()}{b()}</span></div>')
620
+ expect(result).toContain('_tpl(')
621
621
  // Both are single-signal → _bindText
622
- expect(result).toContain("_bindText(a,")
623
- expect(result).toContain("_bindText(b,")
622
+ expect(result).toContain('_bindText(a,')
623
+ expect(result).toContain('_bindText(b,')
624
624
  // Each expression gets its own placeholder and childNodes access
625
- expect(result).toContain("childNodes[0]")
626
- expect(result).toContain("childNodes[1]")
625
+ expect(result).toContain('childNodes[0]')
626
+ expect(result).toContain('childNodes[1]')
627
627
  })
628
628
 
629
- test("handles mixed text + element + expression children", () => {
630
- const result = t("<div>hello<span />{name()}</div>")
631
- expect(result).toContain("_tpl(")
632
- expect(result).toContain("childNodes[")
633
- expect(result).toContain("_bindText(name,")
629
+ test('handles mixed text + element + expression children', () => {
630
+ const result = t('<div>hello<span />{name()}</div>')
631
+ expect(result).toContain('_tpl(')
632
+ expect(result).toContain('childNodes[')
633
+ expect(result).toContain('_bindText(name,')
634
634
  })
635
635
 
636
- test("handles fragment with element children inside template", () => {
637
- const result = t("<div><><span>a</span><em>b</em></></div>")
638
- expect(result).toContain("_tpl(")
639
- expect(result).toContain("<span>a</span>")
640
- expect(result).toContain("<em>b</em>")
636
+ test('handles fragment with element children inside template', () => {
637
+ const result = t('<div><><span>a</span><em>b</em></></div>')
638
+ expect(result).toContain('_tpl(')
639
+ expect(result).toContain('<span>a</span>')
640
+ expect(result).toContain('<em>b</em>')
641
641
  })
642
642
 
643
- test("bails on fragment with non-eligible children", () => {
644
- const result = t("<div><><Component /></></div>")
645
- expect(result).not.toContain("_tpl(")
643
+ test('bails on fragment with non-eligible children', () => {
644
+ const result = t('<div><><Component /></></div>')
645
+ expect(result).not.toContain('_tpl(')
646
646
  })
647
647
 
648
- test("handles static expression in mixed children", () => {
649
- const result = t("<div><span />{label}</div>")
650
- expect(result).toContain("_tpl(")
651
- expect(result).toContain("childNodes[")
652
- expect(result).toContain("createTextNode(label)")
648
+ test('handles static expression in mixed children', () => {
649
+ const result = t('<div><span />{label}</div>')
650
+ expect(result).toContain('_tpl(')
651
+ expect(result).toContain('childNodes[')
652
+ expect(result).toContain('createTextNode(label)')
653
653
  })
654
654
 
655
- test("bakes static numeric literal attr into HTML", () => {
656
- const result = t("<div tabindex={0}><span /></div>")
657
- expect(result).toContain("_tpl(")
655
+ test('bakes static numeric literal attr into HTML', () => {
656
+ const result = t('<div tabindex={0}><span /></div>')
657
+ expect(result).toContain('_tpl(')
658
658
  expect(result).toContain('tabindex=\\"0\\"')
659
659
  })
660
660
 
661
- test("bakes static true keyword attr into HTML", () => {
662
- const result = t("<div hidden={true}><span /></div>")
663
- expect(result).toContain("_tpl(")
664
- expect(result).toContain(" hidden")
661
+ test('bakes static true keyword attr into HTML', () => {
662
+ const result = t('<div hidden={true}><span /></div>')
663
+ expect(result).toContain('_tpl(')
664
+ expect(result).toContain(' hidden')
665
665
  })
666
666
 
667
- test("omits false keyword attr from HTML", () => {
668
- const result = t("<div hidden={false}><span /></div>")
669
- expect(result).toContain("_tpl(")
670
- expect(result).not.toContain("hidden")
667
+ test('omits false keyword attr from HTML', () => {
668
+ const result = t('<div hidden={false}><span /></div>')
669
+ expect(result).toContain('_tpl(')
670
+ expect(result).not.toContain('hidden')
671
671
  })
672
672
 
673
- test("omits null keyword attr from HTML", () => {
674
- const result = t("<div hidden={null}><span /></div>")
675
- expect(result).toContain("_tpl(")
676
- expect(result).not.toContain("hidden")
673
+ test('omits null keyword attr from HTML', () => {
674
+ const result = t('<div hidden={null}><span /></div>')
675
+ expect(result).toContain('_tpl(')
676
+ expect(result).not.toContain('hidden')
677
677
  })
678
678
 
679
- test("emits setAttribute for undefined keyword attr", () => {
680
- const result = t("<div hidden={undefined}><span /></div>")
681
- expect(result).toContain("_tpl(")
679
+ test('emits setAttribute for undefined keyword attr', () => {
680
+ const result = t('<div hidden={undefined}><span /></div>')
681
+ expect(result).toContain('_tpl(')
682
682
  expect(result).toContain('setAttribute("hidden", undefined)')
683
683
  })
684
684
 
685
- test("one-time set for non-class static expression attribute", () => {
686
- const result = t("<div title={someVar}><span /></div>")
685
+ test('one-time set for non-class static expression attribute', () => {
686
+ const result = t('<div title={someVar}><span /></div>')
687
687
  expect(result).toContain('setAttribute("title", someVar)')
688
- expect(result).not.toContain("_bind(")
688
+ expect(result).not.toContain('_bind(')
689
689
  })
690
690
 
691
- test("_bindDirect for non-class single-signal dynamic attribute", () => {
692
- const result = t("<div title={getTitle()}><span /></div>")
693
- expect(result).toContain("_bindDirect(getTitle,")
691
+ test('_bindDirect for non-class single-signal dynamic attribute', () => {
692
+ const result = t('<div title={getTitle()}><span /></div>')
693
+ expect(result).toContain('_bindDirect(getTitle,')
694
694
  expect(result).toContain('setAttribute("title"')
695
695
  })
696
696
 
697
- test("ref attribute in template binds .current", () => {
698
- const result = t("<div ref={myRef}><span /></div>")
699
- expect(result).toContain("myRef.current = __root")
697
+ test('ref attribute in template binds .current', () => {
698
+ const result = t('<div ref={myRef}><span /></div>')
699
+ expect(result).toContain('myRef.current = __root')
700
700
  })
701
701
 
702
- test("handles non-void self-closing element as closing tag", () => {
703
- const result = t("<div><span></span></div>")
704
- expect(result).toContain("_tpl(")
705
- expect(result).toContain("<span></span>")
702
+ test('handles non-void self-closing element as closing tag', () => {
703
+ const result = t('<div><span></span></div>')
704
+ expect(result).toContain('_tpl(')
705
+ expect(result).toContain('<span></span>')
706
706
  })
707
707
 
708
- test("handles nested fragment with expression child", () => {
709
- const result = t("<div><><span />{name()}</></div>")
708
+ test('handles nested fragment with expression child', () => {
709
+ const result = t('<div><><span />{name()}</></div>')
710
710
  // Fragment with expression is inlined, expression with JSX is not present
711
- expect(result).toContain("_tpl(")
711
+ expect(result).toContain('_tpl(')
712
712
  })
713
713
 
714
- test("handles fragment with expression containing no JSX", () => {
715
- const result = t("<div><><span />{count()}</></div>")
716
- expect(result).toContain("_tpl(")
717
- expect(result).toContain("_bindText(count,")
714
+ test('handles fragment with expression containing no JSX', () => {
715
+ const result = t('<div><><span />{count()}</></div>')
716
+ expect(result).toContain('_tpl(')
717
+ expect(result).toContain('_bindText(count,')
718
718
  })
719
719
 
720
- test("handles nested fragment with text children", () => {
721
- const result = t("<div><>hello</></div>")
722
- expect(result).toContain("_tpl(")
723
- expect(result).toContain("hello")
720
+ test('handles nested fragment with text children', () => {
721
+ const result = t('<div><>hello</></div>')
722
+ expect(result).toContain('_tpl(')
723
+ expect(result).toContain('hello')
724
724
  })
725
725
 
726
- test("bails on fragment with non-element non-expression child", () => {
726
+ test('bails on fragment with non-element non-expression child', () => {
727
727
  // Fragment containing a component should bail
728
- const result = t("<div><><MyComp /></></div>")
729
- expect(result).not.toContain("_tpl(")
728
+ const result = t('<div><><MyComp /></></div>')
729
+ expect(result).not.toContain('_tpl(')
730
730
  })
731
731
 
732
- test("empty expression inside template is handled", () => {
733
- const result = t("<div><span />{/* comment */}</div>")
734
- expect(result).toContain("_tpl(")
732
+ test('empty expression inside template is handled', () => {
733
+ const result = t('<div><span />{/* comment */}</div>')
734
+ expect(result).toContain('_tpl(')
735
735
  })
736
736
 
737
- test("static expression with multi-expression context uses placeholder", () => {
738
- const result = t("<div><span>{label}{other}</span></div>")
739
- expect(result).toContain("_tpl(")
740
- expect(result).toContain("childNodes[0]")
741
- expect(result).toContain("childNodes[1]")
737
+ test('static expression with multi-expression context uses placeholder', () => {
738
+ const result = t('<div><span>{label}{other}</span></div>')
739
+ expect(result).toContain('_tpl(')
740
+ expect(result).toContain('childNodes[0]')
741
+ expect(result).toContain('childNodes[1]')
742
742
  })
743
743
  })
744
744
 
745
745
  // ─── Compiler warnings ─────────────────────────────────────────────────────
746
746
 
747
- describe("JSX transform — warnings", () => {
748
- test("warns on <For> without by prop", () => {
749
- const result = transformJSX("<For each={items}>{(item) => <li>{item}</li>}</For>")
747
+ describe('JSX transform — warnings', () => {
748
+ test('warns on <For> without by prop', () => {
749
+ const result = transformJSX('<For each={items}>{(item) => <li>{item}</li>}</For>')
750
750
  expect(result.warnings).toHaveLength(1)
751
- expect(result.warnings[0]?.code).toBe("missing-key-on-for")
751
+ expect(result.warnings[0]?.code).toBe('missing-key-on-for')
752
752
  expect(result.warnings[0]?.line).toBeGreaterThan(0)
753
753
  expect(result.warnings[0]?.column).toBeGreaterThanOrEqual(0)
754
754
  })
755
755
 
756
- test("no warning on <For> with by prop", () => {
756
+ test('no warning on <For> with by prop', () => {
757
757
  const result = transformJSX(
758
- "<For each={items} by={(item) => item.id}>{(item) => <li>{item}</li>}</For>",
758
+ '<For each={items} by={(item) => item.id}>{(item) => <li>{item}</li>}</For>',
759
759
  )
760
- const forWarnings = result.warnings.filter((w) => w.code === "missing-key-on-for")
760
+ const forWarnings = result.warnings.filter((w) => w.code === 'missing-key-on-for')
761
761
  expect(forWarnings).toHaveLength(0)
762
762
  })
763
763
 
764
- test("no warning on non-For elements without by", () => {
765
- const result = transformJSX("<div each={items}>{text()}</div>")
766
- const forWarnings = result.warnings.filter((w) => w.code === "missing-key-on-for")
764
+ test('no warning on non-For elements without by', () => {
765
+ const result = transformJSX('<div each={items}>{text()}</div>')
766
+ const forWarnings = result.warnings.filter((w) => w.code === 'missing-key-on-for')
767
767
  expect(forWarnings).toHaveLength(0)
768
768
  })
769
769
  })
770
770
 
771
771
  // ─── Hoisting in prop position ──────────────────────────────────────────────
772
772
 
773
- describe("JSX transform — static JSX attribute hoisting", () => {
774
- test("hoists static JSX in a DOM element prop", () => {
775
- const result = t("<div icon={<span>icon</span>} />")
776
- expect(result).toContain("const _$h0")
777
- expect(result).toContain("<span>icon</span>")
773
+ describe('JSX transform — static JSX attribute hoisting', () => {
774
+ test('hoists static JSX in a DOM element prop', () => {
775
+ const result = t('<div icon={<span>icon</span>} />')
776
+ expect(result).toContain('const _$h0')
777
+ expect(result).toContain('<span>icon</span>')
778
778
  })
779
779
  })
780
780
 
781
781
  // ─── Additional branch coverage tests ────────────────────────────────────────
782
782
 
783
- describe("JSX transform — child expression branches (non-template context)", () => {
784
- test("wraps dynamic child expression inside a component (non-template path)", () => {
783
+ describe('JSX transform — child expression branches (non-template context)', () => {
784
+ test('wraps dynamic child expression inside a component (non-template path)', () => {
785
785
  // Component elements skip template emission, so the child expression
786
786
  // goes through the walk() JSX expression handler (lines 195-209)
787
- const result = t("<MyComponent>{count()}</MyComponent>")
788
- expect(result).toContain("() => count()")
787
+ const result = t('<MyComponent>{count()}</MyComponent>')
788
+ expect(result).toContain('() => count()')
789
789
  })
790
790
 
791
- test("does NOT wrap non-dynamic child expression inside a component", () => {
791
+ test('does NOT wrap non-dynamic child expression inside a component', () => {
792
792
  // Component context: child expression with no calls — shouldWrap returns false
793
793
  // This hits the else branch where neither hoist nor wrap applies (lines 202-204)
794
- const result = t("<MyComponent>{someVar}</MyComponent>")
795
- expect(result).not.toContain("() =>")
796
- expect(result).toContain("someVar")
794
+ const result = t('<MyComponent>{someVar}</MyComponent>')
795
+ expect(result).not.toContain('() =>')
796
+ expect(result).toContain('someVar')
797
797
  })
798
798
 
799
- test("empty expression in component child is left unchanged", () => {
799
+ test('empty expression in component child is left unchanged', () => {
800
800
  // Empty expression (comment) inside component — expr is undefined, line 205-208
801
- const result = t("<MyComponent>{/* comment */}</MyComponent>")
802
- expect(result).not.toContain("() =>")
801
+ const result = t('<MyComponent>{/* comment */}</MyComponent>')
802
+ expect(result).not.toContain('() =>')
803
803
  })
804
804
  })
805
805
 
806
- describe("JSX transform — nested fragment in templateFragmentCount", () => {
807
- test("handles nested fragment inside fragment in template", () => {
806
+ describe('JSX transform — nested fragment in templateFragmentCount', () => {
807
+ test('handles nested fragment inside fragment in template', () => {
808
808
  // This triggers templateFragmentCount being called recursively for nested fragments
809
809
  // (lines 318-323)
810
- const result = t("<div><><><span>text</span></></></div>")
811
- expect(result).toContain("_tpl(")
812
- expect(result).toContain("<span>text</span>")
810
+ const result = t('<div><><><span>text</span></></></div>')
811
+ expect(result).toContain('_tpl(')
812
+ expect(result).toContain('<span>text</span>')
813
813
  })
814
814
 
815
- test("bails on nested fragment with non-eligible child", () => {
815
+ test('bails on nested fragment with non-eligible child', () => {
816
816
  // Nested fragment containing a component — hits line 325 (return -1)
817
- const result = t("<div><><><MyComp /></></></div>")
818
- expect(result).not.toContain("_tpl(")
817
+ const result = t('<div><><><MyComp /></></></div>')
818
+ expect(result).not.toContain('_tpl(')
819
819
  })
820
820
 
821
- test("nested fragment with expression child in templateFragmentCount", () => {
821
+ test('nested fragment with expression child in templateFragmentCount', () => {
822
822
  // Fragment in fragment with expression — templateFragmentCount handles expression
823
- const result = t("<div><><>{count()}</></></div>")
824
- expect(result).toContain("_tpl(")
825
- expect(result).toContain("_bindText(count,")
823
+ const result = t('<div><><>{count()}</></></div>')
824
+ expect(result).toContain('_tpl(')
825
+ expect(result).toContain('_bindText(count,')
826
826
  })
827
827
 
828
- test("nested fragment with expression containing JSX bails", () => {
828
+ test('nested fragment with expression containing JSX bails', () => {
829
829
  // Fragment in fragment with JSX-containing expression — bails
830
- const result = t("<div><><>{show() && <em />}</></></div>")
831
- expect(result).not.toContain("_tpl(")
830
+ const result = t('<div><><>{show() && <em />}</></></div>')
831
+ expect(result).not.toContain('_tpl(')
832
832
  })
833
833
 
834
- test("nested fragment with empty expression in templateFragmentCount", () => {
834
+ test('nested fragment with empty expression in templateFragmentCount', () => {
835
835
  // Fragment in fragment with empty expression (comment)
836
- const result = t("<div><><>{/* comment */}</></></div>")
837
- expect(result).toContain("_tpl(")
836
+ const result = t('<div><><>{/* comment */}</></></div>')
837
+ expect(result).toContain('_tpl(')
838
838
  })
839
839
  })
840
840
 
841
- describe("JSX transform — template attribute string expression", () => {
842
- test("bakes string expression attribute into HTML in template", () => {
841
+ describe('JSX transform — template attribute string expression', () => {
842
+ test('bakes string expression attribute into HTML in template', () => {
843
843
  // class={"static"} — string literal in JSX expression → baked into HTML (line 427)
844
844
  const result = t('<div class={"static-value"}><span /></div>')
845
- expect(result).toContain("_tpl(")
845
+ expect(result).toContain('_tpl(')
846
846
  expect(result).toContain('class=\\"static-value\\"')
847
- expect(result).not.toContain("className")
847
+ expect(result).not.toContain('className')
848
848
  })
849
849
 
850
- test("bakes non-class string expression attribute into HTML", () => {
850
+ test('bakes non-class string expression attribute into HTML', () => {
851
851
  // title={"hello"} as expression — different attr name (line 427)
852
852
  const result = t('<div title={"hello"}><span /></div>')
853
- expect(result).toContain("_tpl(")
853
+ expect(result).toContain('_tpl(')
854
854
  expect(result).toContain('title=\\"hello\\"')
855
855
  })
856
856
  })
857
857
 
858
- describe("JSX transform — one-time className set in template", () => {
859
- test("one-time className assignment for non-reactive class expression", () => {
858
+ describe('JSX transform — one-time className set in template', () => {
859
+ test('one-time className assignment for non-reactive class expression', () => {
860
860
  // class={someVar} where someVar has no calls — one-time set (line 450)
861
- const result = t("<div class={someVar}><span /></div>")
862
- expect(result).toContain("_tpl(")
863
- expect(result).toContain("className = someVar")
864
- expect(result).not.toContain("_bind(")
861
+ const result = t('<div class={someVar}><span /></div>')
862
+ expect(result).toContain('_tpl(')
863
+ expect(result).toContain('className = someVar')
864
+ expect(result).not.toContain('_bind(')
865
865
  })
866
866
  })
867
867
 
868
- describe("JSX transform — isStaticAttrs edge cases", () => {
869
- test("static JSX with boolean expression prop is static", () => {
868
+ describe('JSX transform — isStaticAttrs edge cases', () => {
869
+ test('static JSX with boolean expression prop is static', () => {
870
870
  // Boolean literal in expression: disabled={true} — isStatic returns true
871
- const result = t("<div>{<input disabled={true} />}</div>")
872
- expect(result).toContain("const _$h0")
871
+ const result = t('<div>{<input disabled={true} />}</div>')
872
+ expect(result).toContain('const _$h0')
873
873
  })
874
874
 
875
- test("static JSX with false expression prop is static", () => {
876
- const result = t("<div>{<input disabled={false} />}</div>")
877
- expect(result).toContain("const _$h0")
875
+ test('static JSX with false expression prop is static', () => {
876
+ const result = t('<div>{<input disabled={false} />}</div>')
877
+ expect(result).toContain('const _$h0')
878
878
  })
879
879
 
880
- test("static JSX with null expression prop is static", () => {
881
- const result = t("<div>{<input disabled={null} />}</div>")
882
- expect(result).toContain("const _$h0")
880
+ test('static JSX with null expression prop is static', () => {
881
+ const result = t('<div>{<input disabled={null} />}</div>')
882
+ expect(result).toContain('const _$h0')
883
883
  })
884
884
 
885
- test("static JSX with numeric expression prop is static", () => {
886
- const result = t("<div>{<input tabindex={0} />}</div>")
887
- expect(result).toContain("const _$h0")
885
+ test('static JSX with numeric expression prop is static', () => {
886
+ const result = t('<div>{<input tabindex={0} />}</div>')
887
+ expect(result).toContain('const _$h0')
888
888
  })
889
889
 
890
- test("static JSX with true expression prop is static", () => {
891
- const result = t("<div>{<input disabled={true} />}</div>")
892
- expect(result).toContain("const _$h0")
890
+ test('static JSX with true expression prop is static', () => {
891
+ const result = t('<div>{<input disabled={true} />}</div>')
892
+ expect(result).toContain('const _$h0')
893
893
  })
894
894
 
895
- test("static JSX with empty expression prop is static", () => {
895
+ test('static JSX with empty expression prop is static', () => {
896
896
  // Empty expression in attribute: disabled={/* comment */} — expr is undefined
897
- const result = t("<div>{<input disabled={/* comment */} />}</div>")
898
- expect(result).toContain("const _$h0")
897
+ const result = t('<div>{<input disabled={/* comment */} />}</div>')
898
+ expect(result).toContain('const _$h0')
899
899
  })
900
900
  })
901
901
 
902
- describe("JSX transform — isStaticChild edge cases", () => {
903
- test("nested static fragment child is recognized as static", () => {
902
+ describe('JSX transform — isStaticChild edge cases', () => {
903
+ test('nested static fragment child is recognized as static', () => {
904
904
  // Fragment as child of a JSX element being checked for staticness
905
- const result = t("<div>{<div><>text</></div>}</div>")
906
- expect(result).toContain("const _$h0")
905
+ const result = t('<div>{<div><>text</></div>}</div>')
906
+ expect(result).toContain('const _$h0')
907
907
  })
908
908
 
909
- test("nested fragment with dynamic child prevents hoisting", () => {
910
- const result = t("<div>{<div><>{count()}</></div>}</div>")
911
- expect(result).not.toContain("const _$h0")
909
+ test('nested fragment with dynamic child prevents hoisting', () => {
910
+ const result = t('<div>{<div><>{count()}</></div>}</div>')
911
+ expect(result).not.toContain('const _$h0')
912
912
  })
913
913
 
914
- test("expression child in static check — static literal", () => {
914
+ test('expression child in static check — static literal', () => {
915
915
  // Expression container with static value inside a JSX node being checked for staticness
916
916
  const result = t('<div>{<div>{"hello"}</div>}</div>')
917
- expect(result).toContain("const _$h0")
917
+ expect(result).toContain('const _$h0')
918
918
  })
919
919
 
920
- test("expression child in static check — dynamic call prevents hoisting", () => {
921
- const result = t("<div>{<div>{count()}</div>}</div>")
922
- expect(result).not.toContain("const _$h0")
920
+ test('expression child in static check — dynamic call prevents hoisting', () => {
921
+ const result = t('<div>{<div>{count()}</div>}</div>')
922
+ expect(result).not.toContain('const _$h0')
923
923
  })
924
924
 
925
- test("expression child with empty expression is static", () => {
926
- const result = t("<div>{<div>{/* comment */}</div>}</div>")
927
- expect(result).toContain("const _$h0")
925
+ test('expression child with empty expression is static', () => {
926
+ const result = t('<div>{<div>{/* comment */}</div>}</div>')
927
+ expect(result).toContain('const _$h0')
928
928
  })
929
929
  })
930
930
 
931
931
  // ─── Additional branch coverage for 95%+ ──────────────────────────────────────
932
932
 
933
- describe("JSX transform — isStaticAttrs boolean shorthand (hoisting path)", () => {
934
- test("hoists static JSX with boolean shorthand attribute (no initializer)", () => {
933
+ describe('JSX transform — isStaticAttrs boolean shorthand (hoisting path)', () => {
934
+ test('hoists static JSX with boolean shorthand attribute (no initializer)', () => {
935
935
  // This triggers isStaticAttrs → !prop.initializer → return true (line 719/2340)
936
- const result = t("<div>{<input disabled />}</div>")
937
- expect(result).toContain("const _$h0")
936
+ const result = t('<div>{<input disabled />}</div>')
937
+ expect(result).toContain('const _$h0')
938
938
  })
939
939
  })
940
940
 
941
- describe("JSX transform — isStaticChild with element/self-closing children", () => {
942
- test("hoists static JSX with self-closing element child", () => {
941
+ describe('JSX transform — isStaticChild with element/self-closing children', () => {
942
+ test('hoists static JSX with self-closing element child', () => {
943
943
  // Triggers isStaticChild → isJsxSelfClosingElement path (line 735/2356)
944
- const result = t("<div>{<div><br /></div>}</div>")
945
- expect(result).toContain("const _$h0")
944
+ const result = t('<div>{<div><br /></div>}</div>')
945
+ expect(result).toContain('const _$h0')
946
946
  })
947
947
 
948
- test("hoists static JSX with nested element child", () => {
948
+ test('hoists static JSX with nested element child', () => {
949
949
  // Triggers isStaticChild → isJsxElement path (line 736/2357)
950
- const result = t("<div>{<div><span>text</span></div>}</div>")
951
- expect(result).toContain("const _$h0")
950
+ const result = t('<div>{<div><span>text</span></div>}</div>')
951
+ expect(result).toContain('const _$h0')
952
952
  })
953
953
 
954
- test("does NOT hoist when nested element child has dynamic props", () => {
954
+ test('does NOT hoist when nested element child has dynamic props', () => {
955
955
  // isStaticChild → isJsxElement → isStaticJSXNode returns false
956
- const result = t("<div>{<div><span class={cls()}>text</span></div>}</div>")
957
- expect(result).not.toContain("const _$h0")
956
+ const result = t('<div>{<div><span class={cls()}>text</span></div>}</div>')
957
+ expect(result).not.toContain('const _$h0')
958
958
  })
959
959
 
960
- test("does NOT hoist when self-closing child has dynamic props", () => {
960
+ test('does NOT hoist when self-closing child has dynamic props', () => {
961
961
  // isStaticChild → isJsxSelfClosingElement → isStaticJSXNode returns false
962
- const result = t("<div>{<div><input value={val()} /></div>}</div>")
963
- expect(result).not.toContain("const _$h0")
962
+ const result = t('<div>{<div><input value={val()} /></div>}</div>')
963
+ expect(result).not.toContain('const _$h0')
964
964
  })
965
965
  })
966
966
 
967
- describe("JSX transform — template ref/event without expression", () => {
968
- test("ref shorthand (no expression) in template is handled", () => {
967
+ describe('JSX transform — template ref/event without expression', () => {
968
+ test('ref shorthand (no expression) in template is handled', () => {
969
969
  // Triggers the else branch of ref initializer check (line 2003)
970
- const result = t("<div ref><span /></div>")
971
- expect(result).toContain("_tpl(")
972
- expect(result).not.toContain(".current")
970
+ const result = t('<div ref><span /></div>')
971
+ expect(result).toContain('_tpl(')
972
+ expect(result).not.toContain('.current')
973
973
  })
974
974
 
975
- test("onClick shorthand (no expression) in template is handled", () => {
975
+ test('onClick shorthand (no expression) in template is handled', () => {
976
976
  // Triggers the else branch of event initializer check (line 2017)
977
- const result = t("<div onClick><span /></div>")
978
- expect(result).toContain("_tpl(")
979
- expect(result).not.toContain("addEventListener")
977
+ const result = t('<div onClick><span /></div>')
978
+ expect(result).toContain('_tpl(')
979
+ expect(result).not.toContain('addEventListener')
980
980
  })
981
981
  })
982
982
 
983
- describe("JSX transform — empty expression in DOM prop (non-template path)", () => {
984
- test("empty expression in DOM prop with spread (non-template) is handled", () => {
983
+ describe('JSX transform — empty expression in DOM prop (non-template path)', () => {
984
+ test('empty expression in DOM prop with spread (non-template) is handled', () => {
985
985
  // Spread prevents template emission → walk handles attrs
986
986
  // class={/* comment */} has no expression → else branch at line 1799
987
- const result = t("<div {...props} class={/* comment */} />")
988
- expect(result).not.toContain("() =>")
989
- expect(result).toContain("{...props}")
987
+ const result = t('<div {...props} class={/* comment */} />')
988
+ expect(result).not.toContain('() =>')
989
+ expect(result).toContain('{...props}')
990
990
  })
991
991
  })
992
992
 
993
- describe("JSX transform — whitespace-only text stripped in flattenChildren", () => {
994
- test("whitespace-only text between elements is stripped in template", () => {
993
+ describe('JSX transform — whitespace-only text stripped in flattenChildren', () => {
994
+ test('whitespace-only text between elements is stripped in template', () => {
995
995
  // Triggers the else branch of `if (trimmed)` in flattenChildren (line 2207)
996
996
  const result = t(`<div>
997
997
  <span>a</span>
998
998
  <em>b</em>
999
999
  </div>`)
1000
- expect(result).toContain("_tpl(")
1001
- expect(result).toContain("<span>a</span>")
1002
- expect(result).toContain("<em>b</em>")
1000
+ expect(result).toContain('_tpl(')
1001
+ expect(result).toContain('<span>a</span>')
1002
+ expect(result).toContain('<em>b</em>')
1003
1003
  })
1004
1004
  })
1005
1005
 
1006
- describe("JSX transform — fragment inside flattenChildren", () => {
1007
- test("fragment children are flattened during template child processing", () => {
1006
+ describe('JSX transform — fragment inside flattenChildren', () => {
1007
+ test('fragment children are flattened during template child processing', () => {
1008
1008
  // This specifically exercises the isJsxFragment branch in flattenChildren (line 2223)
1009
1009
  // The key is that this fragment is processed via flattenChildren (not templateFragmentCount)
1010
1010
  // because the outer element is a template-eligible JsxElement
1011
- const result = t("<div><><span>one</span><em>two</em></></div>")
1012
- expect(result).toContain("_tpl(")
1013
- expect(result).toContain("<span>one</span>")
1014
- expect(result).toContain("<em>two</em>")
1011
+ const result = t('<div><><span>one</span><em>two</em></></div>')
1012
+ expect(result).toContain('_tpl(')
1013
+ expect(result).toContain('<span>one</span>')
1014
+ expect(result).toContain('<em>two</em>')
1015
1015
  })
1016
1016
  })
1017
1017
 
1018
- describe("JSX transform — member expression tag names", () => {
1019
- test("member expression tag name treated as empty in warnings", () => {
1018
+ describe('JSX transform — member expression tag names', () => {
1019
+ test('member expression tag name treated as empty in warnings', () => {
1020
1020
  // <ns.Component> has non-identifier tagName → tagName is "" (line 1762)
1021
- const result = transformJSX("<ns.Comp value={x} />")
1021
+ const result = transformJSX('<ns.Comp value={x} />')
1022
1022
  expect(result.warnings).toHaveLength(0)
1023
1023
  })
1024
1024
 
1025
- test("member expression tag in element position triggers non-identifier path", () => {
1025
+ test('member expression tag in element position triggers non-identifier path', () => {
1026
1026
  // <ns.div> has a member expression tag → jsxTagName returns "" → templateElementCount returns -1
1027
- const result = t("<ns.div><span /></ns.div>")
1027
+ const result = t('<ns.div><span /></ns.div>')
1028
1028
  // Should not produce template since tagName is not an identifier
1029
- expect(result).not.toContain("_tpl(")
1029
+ expect(result).not.toContain('_tpl(')
1030
1030
  })
1031
1031
  })
1032
1032
 
1033
1033
  // ─── Template emission edge cases ─────────────────────────────────────────────
1034
1034
 
1035
- describe("JSX transform — template emission edge cases", () => {
1036
- test("non-delegated event (onMouseEnter) uses addEventListener not delegation", () => {
1037
- const result = t("<div onMouseEnter={handler}><span /></div>")
1038
- expect(result).toContain("_tpl(")
1035
+ describe('JSX transform — template emission edge cases', () => {
1036
+ test('non-delegated event (onMouseEnter) uses addEventListener not delegation', () => {
1037
+ const result = t('<div onMouseEnter={handler}><span /></div>')
1038
+ expect(result).toContain('_tpl(')
1039
1039
  // mouseenter is NOT in DELEGATED_EVENTS → must use addEventListener
1040
1040
  // onMouseEnter → eventName = "m" + "ouseEnter" = "mouseEnter"
1041
- expect(result).toContain("addEventListener(")
1042
- expect(result).toContain("mouseEnter")
1043
- expect(result).not.toContain("__ev_")
1041
+ expect(result).toContain('addEventListener(')
1042
+ expect(result).toContain('mouseEnter')
1043
+ expect(result).not.toContain('__ev_')
1044
1044
  })
1045
1045
 
1046
- test("template with both dynamic attribute AND dynamic child text", () => {
1047
- const result = t("<div title={getTitle()}>{count()}</div>")
1048
- expect(result).toContain("_tpl(")
1046
+ test('template with both dynamic attribute AND dynamic child text', () => {
1047
+ const result = t('<div title={getTitle()}>{count()}</div>')
1048
+ expect(result).toContain('_tpl(')
1049
1049
  // Dynamic attribute binding
1050
- expect(result).toContain("_bindDirect(getTitle,")
1050
+ expect(result).toContain('_bindDirect(getTitle,')
1051
1051
  // Dynamic child text binding
1052
- expect(result).toContain("_bindText(count,")
1052
+ expect(result).toContain('_bindText(count,')
1053
1053
  })
1054
1054
 
1055
- test("template with multiple dynamic attributes on same element", () => {
1056
- const result = t("<div class={cls()} title={getTitle()}><span /></div>")
1057
- expect(result).toContain("_tpl(")
1055
+ test('template with multiple dynamic attributes on same element', () => {
1056
+ const result = t('<div class={cls()} title={getTitle()}><span /></div>')
1057
+ expect(result).toContain('_tpl(')
1058
1058
  // Both attributes should get _bindDirect bindings
1059
- expect(result).toContain("_bindDirect(cls,")
1060
- expect(result).toContain("_bindDirect(getTitle,")
1059
+ expect(result).toContain('_bindDirect(cls,')
1060
+ expect(result).toContain('_bindDirect(getTitle,')
1061
1061
  })
1062
1062
 
1063
- test("template with static + dynamic children mixed", () => {
1064
- const result = t("<div><span>static text</span>{count()}</div>")
1065
- expect(result).toContain("_tpl(")
1066
- expect(result).toContain("static text")
1067
- expect(result).toContain("_bindText(count,")
1063
+ test('template with static + dynamic children mixed', () => {
1064
+ const result = t('<div><span>static text</span>{count()}</div>')
1065
+ expect(result).toContain('_tpl(')
1066
+ expect(result).toContain('static text')
1067
+ expect(result).toContain('_bindText(count,')
1068
1068
  // Mixed children use childNodes indexing
1069
- expect(result).toContain("childNodes[")
1069
+ expect(result).toContain('childNodes[')
1070
1070
  })
1071
1071
 
1072
- test("template with nested component inside DOM elements bails", () => {
1072
+ test('template with nested component inside DOM elements bails', () => {
1073
1073
  // Component child inside a DOM element prevents template emission
1074
- const result = t("<div><span><MyComponent /></span></div>")
1075
- expect(result).not.toContain("_tpl(")
1074
+ const result = t('<div><span><MyComponent /></span></div>')
1075
+ expect(result).not.toContain('_tpl(')
1076
1076
  })
1077
1077
 
1078
- test("fragment with template-eligible children inside template", () => {
1079
- const result = t("<div><><span>a</span>{name()}</></div>")
1080
- expect(result).toContain("_tpl(")
1081
- expect(result).toContain("<span>a</span>")
1082
- expect(result).toContain("_bindText(name,")
1078
+ test('fragment with template-eligible children inside template', () => {
1079
+ const result = t('<div><><span>a</span>{name()}</></div>')
1080
+ expect(result).toContain('_tpl(')
1081
+ expect(result).toContain('<span>a</span>')
1082
+ expect(result).toContain('_bindText(name,')
1083
1083
  })
1084
1084
  })
1085
1085
 
1086
1086
  // ─── Style attribute handling in templates ───────────────────────────────────
1087
1087
 
1088
- describe("JSX transform — style attribute in templates", () => {
1089
- test("style object literal uses Object.assign in _bind", () => {
1088
+ describe('JSX transform — style attribute in templates', () => {
1089
+ test('style object literal uses Object.assign in _bind', () => {
1090
1090
  const result = t('<div style={{ overflow: "hidden" }}>text</div>')
1091
- expect(result).toContain("_tpl(")
1092
- expect(result).toContain("Object.assign(__root.style,")
1091
+ expect(result).toContain('_tpl(')
1092
+ expect(result).toContain('Object.assign(__root.style,')
1093
1093
  expect(result).toContain('overflow: "hidden"')
1094
1094
  })
1095
1095
 
1096
- test("style string literal inlines as HTML attribute", () => {
1096
+ test('style string literal inlines as HTML attribute', () => {
1097
1097
  const result = t('<div style="color: red">text</div>')
1098
- expect(result).toContain("_tpl(")
1098
+ expect(result).toContain('_tpl(')
1099
1099
  expect(result).toContain('style=\\"color: red\\"')
1100
1100
  // Static string should NOT go through _bind
1101
- expect(result).not.toContain("Object.assign")
1102
- expect(result).not.toContain("cssText")
1101
+ expect(result).not.toContain('Object.assign')
1102
+ expect(result).not.toContain('cssText')
1103
1103
  })
1104
1104
 
1105
- test("reactive style uses cssText in _bind", () => {
1106
- const result = t("<div style={() => getStyle()}>text</div>")
1107
- expect(result).toContain("_tpl(")
1108
- expect(result).toContain("style.cssText")
1105
+ test('reactive style uses cssText in _bind', () => {
1106
+ const result = t('<div style={() => getStyle()}>text</div>')
1107
+ expect(result).toContain('_tpl(')
1108
+ expect(result).toContain('style.cssText')
1109
1109
  })
1110
1110
  })