ripple 0.3.71 → 0.3.74

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 (165) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -8
  4. package/src/runtime/index-client.js +3 -13
  5. package/src/runtime/internal/client/blocks.js +3 -25
  6. package/src/runtime/internal/client/for.js +80 -5
  7. package/src/runtime/internal/client/index.js +0 -2
  8. package/src/runtime/internal/client/types.d.ts +0 -10
  9. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  10. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  11. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  12. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  13. package/tests/client/array/array.derived.test.tsrx +97 -109
  14. package/tests/client/array/array.iteration.test.tsrx +28 -28
  15. package/tests/client/array/array.mutations.test.tsrx +68 -68
  16. package/tests/client/array/array.static.test.tsrx +82 -92
  17. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  18. package/tests/client/async-suspend.test.tsrx +180 -179
  19. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  20. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  21. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  22. package/tests/client/basic/basic.collections.test.tsrx +59 -71
  23. package/tests/client/basic/basic.components.test.tsrx +196 -222
  24. package/tests/client/basic/basic.errors.test.tsrx +72 -78
  25. package/tests/client/basic/basic.events.test.tsrx +80 -85
  26. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  27. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  28. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  29. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  30. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  31. package/tests/client/boundaries.test.tsrx +18 -18
  32. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  33. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  34. package/tests/client/compiler/compiler.basic.test.tsrx +364 -296
  35. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  36. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  37. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  38. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  39. package/tests/client/composite/composite.dynamic-components.test.tsrx +41 -44
  40. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  41. package/tests/client/composite/composite.props.test.tsrx +66 -74
  42. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  43. package/tests/client/composite/composite.render.test.tsrx +92 -101
  44. package/tests/client/computed-properties.test.tsrx +14 -18
  45. package/tests/client/context.test.tsrx +14 -18
  46. package/tests/client/css/global-additional-cases.test.tsrx +491 -437
  47. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  48. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  49. package/tests/client/css/global-basic.test.tsrx +105 -98
  50. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  51. package/tests/client/css/global-combinators.test.tsrx +83 -78
  52. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  53. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  54. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  55. package/tests/client/css/global-nested.test.tsrx +88 -78
  56. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  57. package/tests/client/css/global-scoping.test.tsrx +145 -125
  58. package/tests/client/css/style-identifier.test.tsrx +62 -69
  59. package/tests/client/date.test.tsrx +83 -83
  60. package/tests/client/dynamic-elements.test.tsrx +227 -283
  61. package/tests/client/events.test.tsrx +252 -266
  62. package/tests/client/for.test.tsrx +120 -127
  63. package/tests/client/head.test.tsrx +40 -48
  64. package/tests/client/html.test.tsrx +37 -49
  65. package/tests/client/input-value.test.tsrx +1125 -1354
  66. package/tests/client/lazy-array.test.tsrx +10 -16
  67. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  68. package/tests/client/map.test.tsrx +39 -41
  69. package/tests/client/media-query.test.tsrx +15 -19
  70. package/tests/client/object.test.tsrx +46 -56
  71. package/tests/client/portal.test.tsrx +31 -37
  72. package/tests/client/ref.test.tsrx +173 -193
  73. package/tests/client/return.test.tsrx +62 -37
  74. package/tests/client/set.test.tsrx +33 -33
  75. package/tests/client/svg.test.tsrx +195 -215
  76. package/tests/client/switch.test.tsrx +201 -191
  77. package/tests/client/track-async-hydration.test.tsrx +14 -18
  78. package/tests/client/tracked-index-access.test.tsrx +18 -28
  79. package/tests/client/try.test.tsrx +494 -619
  80. package/tests/client/tsx.test.tsrx +290 -371
  81. package/tests/client/typescript-generics.test.tsrx +121 -129
  82. package/tests/client/url/url.derived.test.tsrx +21 -25
  83. package/tests/client/url/url.parsing.test.tsrx +35 -35
  84. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  85. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  86. package/tests/client/url/url.serialization.test.tsrx +8 -8
  87. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  88. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  89. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  90. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  91. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  92. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  93. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  94. package/tests/hydration/compiled/client/basic.js +396 -325
  95. package/tests/hydration/compiled/client/composite.js +52 -44
  96. package/tests/hydration/compiled/client/for.js +734 -604
  97. package/tests/hydration/compiled/client/head.js +183 -103
  98. package/tests/hydration/compiled/client/html.js +93 -86
  99. package/tests/hydration/compiled/client/if-children.js +95 -71
  100. package/tests/hydration/compiled/client/if.js +113 -89
  101. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  102. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  103. package/tests/hydration/compiled/client/reactivity.js +26 -24
  104. package/tests/hydration/compiled/client/return.js +8 -42
  105. package/tests/hydration/compiled/client/switch.js +208 -173
  106. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  107. package/tests/hydration/compiled/client/try.js +29 -21
  108. package/tests/hydration/compiled/server/basic.js +210 -221
  109. package/tests/hydration/compiled/server/composite.js +13 -14
  110. package/tests/hydration/compiled/server/for.js +427 -444
  111. package/tests/hydration/compiled/server/head.js +199 -189
  112. package/tests/hydration/compiled/server/html.js +33 -41
  113. package/tests/hydration/compiled/server/if-children.js +114 -117
  114. package/tests/hydration/compiled/server/if.js +77 -83
  115. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  116. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  117. package/tests/hydration/compiled/server/reactivity.js +24 -22
  118. package/tests/hydration/compiled/server/return.js +6 -18
  119. package/tests/hydration/compiled/server/switch.js +179 -176
  120. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  121. package/tests/hydration/compiled/server/try.js +31 -35
  122. package/tests/hydration/components/basic.tsrx +216 -286
  123. package/tests/hydration/components/composite.tsrx +32 -42
  124. package/tests/hydration/components/events.tsrx +81 -101
  125. package/tests/hydration/components/for.tsrx +270 -336
  126. package/tests/hydration/components/head.tsrx +43 -39
  127. package/tests/hydration/components/hmr.tsrx +16 -22
  128. package/tests/hydration/components/html-in-template.tsrx +15 -21
  129. package/tests/hydration/components/html.tsrx +442 -526
  130. package/tests/hydration/components/if-children.tsrx +107 -125
  131. package/tests/hydration/components/if.tsrx +68 -90
  132. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  133. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  134. package/tests/hydration/components/portal.tsrx +33 -41
  135. package/tests/hydration/components/reactivity.tsrx +26 -34
  136. package/tests/hydration/components/return.tsrx +4 -6
  137. package/tests/hydration/components/switch.tsrx +73 -78
  138. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  139. package/tests/hydration/components/try.tsrx +37 -51
  140. package/tests/hydration/switch.test.js +8 -8
  141. package/tests/server/await.test.tsrx +3 -3
  142. package/tests/server/basic.attributes.test.tsrx +120 -167
  143. package/tests/server/basic.components.test.tsrx +163 -197
  144. package/tests/server/basic.test.tsrx +298 -220
  145. package/tests/server/compiler.test.tsrx +142 -72
  146. package/tests/server/composite.props.test.tsrx +54 -58
  147. package/tests/server/composite.test.tsrx +165 -167
  148. package/tests/server/context.test.tsrx +13 -17
  149. package/tests/server/dynamic-elements.test.tsrx +103 -135
  150. package/tests/server/for.test.tsrx +115 -84
  151. package/tests/server/head.test.tsrx +31 -31
  152. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  153. package/tests/server/if.test.tsrx +49 -59
  154. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  155. package/tests/server/return.test.tsrx +58 -36
  156. package/tests/server/streaming-ssr.test.tsrx +4 -4
  157. package/tests/server/style-identifier.test.tsrx +58 -66
  158. package/tests/server/switch.test.tsrx +89 -97
  159. package/tests/server/track-async-serialization.test.tsrx +85 -103
  160. package/tests/server/try.test.tsrx +275 -360
  161. package/tests/utils/ref-types.test.js +72 -0
  162. package/tests/utils/vite-plugin-config.test.js +41 -74
  163. package/types/index.d.ts +1 -0
  164. package/src/runtime/internal/client/compat.js +0 -40
  165. package/tests/utils/compiler-compat-config.test.js +0 -38
@@ -3,8 +3,8 @@ import type { Tracked, PropsNoChildren } from 'ripple';
3
3
 
4
4
  describe('basic client', () => {
5
5
  it('render static text', async () => {
6
- function Basic() {
7
- return <><div>{'Hello World'}</div></>;
6
+ function Basic() @{
7
+ <div>{'Hello World'}</div>
8
8
  }
9
9
 
10
10
  const { head, body } = await render(Basic);
@@ -14,11 +14,9 @@ describe('basic client', () => {
14
14
  });
15
15
 
16
16
  it('renders string interpolation as escaped text', async () => {
17
- function Basic() {
18
- return <>
19
- let markup = '<span>Not HTML</span>';
20
- <div>{markup}</div>
21
- </>;
17
+ function Basic() @{
18
+ let markup = '<span>Not HTML</span>';
19
+ <div>{markup}</div>
22
20
  }
23
21
 
24
22
  const { body } = await render(Basic);
@@ -26,32 +24,35 @@ describe('basic client', () => {
26
24
  expect(body).toBeHtml('<div>&lt;span>Not HTML&lt;/span></div>');
27
25
  });
28
26
 
29
- it('renders direct double-quoted text children as text', async () => {
30
- function Basic() {
31
- return <>
32
- <div>"Rock &amp; &quot;Roll&quot;"</div>
33
- <div>"line\nbreak"</div>
34
- <pre>"first
35
- second"</pre>
36
- </>;
27
+ it('renders direct JSX text children as text', async () => {
28
+ function Basic() @{
29
+ <>
30
+ <div>Rock &amp; &quot;Roll&quot;</div>
31
+ <div>line break</div>
32
+ <pre>
33
+ first
34
+ second
35
+ </pre>
36
+ </>
37
37
  }
38
38
 
39
39
  const { body } = await render(Basic);
40
40
 
41
41
  expect(body).toBeHtml(
42
- '<div>Rock &amp; "Roll"</div><div>line\\nbreak</div><pre>first\nsecond</pre>',
42
+ '<div>Rock &amp; "Roll"</div><div>line break</div><pre>first\nsecond</pre>',
43
43
  );
44
44
  });
45
45
 
46
- it('does not render TSRX statements outside returned component templates', async () => {
47
- function Basic() {
46
+ it('does not render JavaScript statements outside returned component templates', async () => {
47
+ function Basic() @{
48
48
  const ready = true;
49
49
 
50
50
  if (ready) {
51
- <div class="leaked">"should not render"</div>
51
+ const leaked = 'should not render';
52
+ void leaked;
52
53
  }
53
54
 
54
- return <>"Hello world"</>;
55
+ <>Hello world</>
55
56
  }
56
57
 
57
58
  const { body } = await render(Basic);
@@ -60,14 +61,12 @@ second"</pre>
60
61
  });
61
62
 
62
63
  it('renders primitive component return branches', async () => {
63
- function Basic() {
64
+ function Basic() @{
64
65
  const ready = false;
65
-
66
66
  if (!ready) {
67
67
  return 'Waiting';
68
68
  }
69
-
70
- return <>"Ready"</>;
69
+ <>Ready</>
71
70
  }
72
71
 
73
72
  const { body } = await render(Basic);
@@ -105,10 +104,115 @@ second"</pre>
105
104
  expect(body).toBeHtml('');
106
105
  });
107
106
 
108
- it('does not render elements after an ASI return', async () => {
107
+ it('does not stringify adjacent call-containing expression children', async () => {
108
+ function child(label: string) @{
109
+ <span>{label}</span>
110
+ }
111
+
112
+ function empty() {
113
+ return null;
114
+ }
115
+
116
+ const Constructed = function Constructed(label: string) {
117
+ return child(label);
118
+ } as unknown as {
119
+ new (label: string): ReturnType<typeof child>;
120
+ };
121
+
122
+ const factory = child;
123
+
124
+ function tag(_strings: TemplateStringsArray) {
125
+ return child('tagged');
126
+ }
127
+
128
+ const lookup = {
129
+ member: child('member'),
130
+ };
131
+
132
+ function getKey(): keyof typeof lookup {
133
+ return 'member';
134
+ }
135
+
136
+ function touch() {
137
+ return null;
138
+ }
139
+
140
+ let assigned;
141
+
142
+ function Basic() @{
143
+ <>
144
+ <div>
145
+ {'call:'}
146
+ {child('call')}
147
+ </div>
148
+ <div>
149
+ {'new:'}
150
+ {new Constructed('new')}
151
+ </div>
152
+ <div>
153
+ {'chain:'}
154
+ {factory?.('chain')}
155
+ </div>
156
+ <div>
157
+ {'ts-wrapper:'}
158
+ {child('ts-wrapper')!}
159
+ </div>
160
+ <div>
161
+ {'array:'}
162
+ {[child('array')]}
163
+ </div>
164
+ <div>
165
+ {'assignment:'}
166
+ {assigned = child('assignment')}
167
+ </div>
168
+ <div>
169
+ {'logical:'}
170
+ {true && child('logical')}
171
+ </div>
172
+ <div>
173
+ {'conditional:'}
174
+ {true ? child('conditional') : ''}
175
+ </div>
176
+ <div>
177
+ {'member:'}
178
+ {lookup[getKey()]}
179
+ </div>
180
+ <div>
181
+ {'object:'}
182
+ {{
183
+ [Symbol.for('ripple.element')]: true,
184
+ render() {
185
+ return child('object');
186
+ },
187
+ }}
188
+ </div>
189
+ <div>
190
+ {'sequence:'}
191
+ {(touch(), child('sequence'))}
192
+ </div>
193
+ <div>
194
+ {'tagged:'}
195
+ {tag`tagged`}
196
+ </div>
197
+ <div>
198
+ {'unary:'}
199
+ {void empty()}
200
+ </div>
201
+ </>
202
+ }
203
+
204
+ const { body } = await render(Basic);
205
+
206
+ expect(body).toBeHtml(
207
+ '<div>call:<span>call</span></div><div>new:<span>new</span></div><div>chain:<span>chain</span></div><div>ts-wrapper:<span>ts-wrapper</span></div><div>array:<span>array</span></div><div>assignment:<span>assignment</span></div><div>logical:<span>logical</span></div><div>conditional:<span>conditional</span></div><div>member:<span>member</span></div><div>object:<span>object</span></div><div>sequence:<span>sequence</span></div><div>tagged:<span>tagged</span></div><div>unary:</div>',
208
+ );
209
+ });
210
+
211
+ it('does not render unreachable statements after an ASI return', async () => {
109
212
  function Basic() {
110
213
  return;
111
- <div>"should not render"</div>
214
+ const leaked = 'should not render';
215
+ void leaked;
112
216
  }
113
217
 
114
218
  const { body } = await render(Basic);
@@ -117,14 +221,10 @@ second"</pre>
117
221
  });
118
222
 
119
223
  it('renders inline tsrx fragments', async () => {
120
- function Basic() {
121
- return <>
122
- const content = <>
123
- const label = 'Server';
124
- <span>{label}</span>
125
- </>;
126
- <div>{content}</div>
127
- </>;
224
+ function Basic() @{
225
+ const label = 'Server';
226
+ const content = <span>{label}</span>;
227
+ <div>{content}</div>
128
228
  }
129
229
 
130
230
  const { body } = await render(Basic);
@@ -133,11 +233,9 @@ second"</pre>
133
233
  });
134
234
 
135
235
  it('renders Fragment innerHTML', async () => {
136
- function Basic() {
137
- return <>
138
- const html = '<strong>Server Fragment HTML</strong>';
139
- <Fragment innerHTML={html} />
140
- </>;
236
+ function Basic() @{
237
+ const html = '<strong>Server Fragment HTML</strong>';
238
+ <Fragment innerHTML={html} />
141
239
  }
142
240
 
143
241
  const { body } = await render(Basic);
@@ -148,28 +246,20 @@ second"</pre>
148
246
 
149
247
  it('renders deeply nested tsx and tsrx expression values', async () => {
150
248
  function makeFragment(label: string) {
249
+ const test = <>
250
+ {[1, 2, 3, 4].map((item) => <div class="helper-item">{item}</div>)}
251
+ </>;
151
252
  return <>
152
253
  <span class="label">{label}</span>
153
- const test = <tsx>
154
- {[1, 2, 3, 4].map(
155
- (item) => <tsx>
156
- {<>
157
- <div class="helper-item">{item}</div>
158
- </>}
159
- </tsx>,
160
- )}
161
- </tsx>;
162
254
  {test}
163
255
  </>;
164
256
  }
165
257
 
166
- function Basic() {
167
- return <>
168
- {<tsx>
169
- {[1, 2, 3].map((item) => <div class="app-item">{item}</div>)}
170
- </tsx>}
258
+ function Basic() @{
259
+ <>
260
+ {[1, 2, 3].map((item) => <div class="app-item">{item}</div>)}
171
261
  {makeFragment('from helper')}
172
- </>;
262
+ </>
173
263
  }
174
264
 
175
265
  const { body } = await render(Basic);
@@ -180,19 +270,15 @@ second"</pre>
180
270
  });
181
271
 
182
272
  it('renders tsrx nested directly inside a top-level tsx expression value', async () => {
183
- function Basic() {
184
- return <>
185
- const content = <tsx>
186
- <section class="outer">
187
- {<>
188
- <div class="inner">
189
- {'from tsrx'}
190
- </div>
191
- </>}
192
- </section>
193
- </tsx>;
194
- {content}
273
+ function Basic() @{
274
+ const content = <>
275
+ <section class="outer">
276
+ <div class="inner">{'from tsrx'}</div>
277
+ </section>
195
278
  </>;
279
+ <>
280
+ {content}
281
+ </>
196
282
  }
197
283
 
198
284
  const { body } = await render(Basic);
@@ -201,21 +287,17 @@ second"</pre>
201
287
  });
202
288
 
203
289
  it('renders nested elements from tsrx inside a top-level tsx value', async () => {
204
- function Basic() {
205
- return <>
206
- const content = <tsx>
207
- <div class="wrapper">
208
- {<>
209
- <section class="native">
210
- <span class="nested-tsrx">
211
- {'inside nested tsrx'}
212
- </span>
213
- </section>
214
- </>}
215
- </div>
216
- </tsx>;
217
- {content}
290
+ function Basic() @{
291
+ const content = <>
292
+ <div class="wrapper">
293
+ <section class="native">
294
+ <span class="nested-tsrx">{'inside nested tsrx'}</span>
295
+ </section>
296
+ </div>
218
297
  </>;
298
+ <>
299
+ {content}
300
+ </>
219
301
  }
220
302
 
221
303
  const { body } = await render(Basic);
@@ -226,18 +308,12 @@ second"</pre>
226
308
  });
227
309
 
228
310
  it('renders tsx declared before a top-level tsx value', async () => {
229
- function Basic() {
230
- return <>
231
- const nested = <tsx>
232
- <span class="nested-tsx">
233
- {'inside nested tsx'}
234
- </span>
235
- </tsx>;
236
- const content = <tsx>
237
- <div class="native">{nested}</div>
238
- </tsx>;
311
+ function Basic() @{
312
+ const nested = <span class="nested-tsx">inside nested tsx</span>;
313
+ const content = <><div class="native">{nested}</div></>;
314
+ <>
239
315
  {content}
240
- </>;
316
+ </>
241
317
  }
242
318
 
243
319
  const { body } = await render(Basic);
@@ -248,21 +324,17 @@ second"</pre>
248
324
  });
249
325
 
250
326
  it('flattens nested primitive arrays inside mixed tsrx collections', async () => {
251
- function Basic() {
252
- return <>
253
- <div>
254
- {<tsx>
255
- {[
256
- 'start:',
257
- ['one', 2, true, null, false],
258
- <strong>
259
- {'!'}
260
- </strong>,
261
- ':end',
262
- ]}
263
- </tsx>}
264
- </div>
265
- </>;
327
+ function Basic() @{
328
+ <div>
329
+ {<>
330
+ {[
331
+ 'start:',
332
+ ['one', 2, true, null, false],
333
+ <strong>{'!'}</strong>,
334
+ ':end',
335
+ ]}
336
+ </>}
337
+ </div>
266
338
  }
267
339
 
268
340
  const { body } = await render(Basic);
@@ -271,12 +343,14 @@ second"</pre>
271
343
  });
272
344
 
273
345
  it('flattens direct primitive array expressions', async () => {
274
- function Basic() {
275
- return <>
276
- const items = ['start:', ['one', 2], null, true, false, ':end'];
277
- <div>{['start:', ['one', 2], null, true, false, ':end']}</div>
346
+ function Basic() @{
347
+ const items = ['start:', ['one', 2], null, true, false, ':end'];
348
+ <>
349
+ <div>
350
+ {['start:', ['one', 2], null, true, false, ':end']}
351
+ </div>
278
352
  <div>{items}</div>
279
- </>;
353
+ </>
280
354
  }
281
355
 
282
356
  const { body } = await render(Basic);
@@ -285,16 +359,16 @@ second"</pre>
285
359
  });
286
360
 
287
361
  it('flattens conditional primitive array expressions', async () => {
288
- function Basic() {
289
- return <>
290
- const condition = true;
291
- const ternary_items = condition
292
- ? ['start:', ['one', 2], null, true, false, ':end']
293
- : ['fallback'];
294
- const logical_items = condition && ['start:', ['one', 2], null, true, false, ':end'];
362
+ function Basic() @{
363
+ const condition = true;
364
+ const ternary_items = condition
365
+ ? ['start:', ['one', 2], null, true, false, ':end']
366
+ : ['fallback'];
367
+ const logical_items = condition && ['start:', ['one', 2], null, true, false, ':end'];
368
+ <>
295
369
  <div>{ternary_items}</div>
296
370
  <div>{logical_items}</div>
297
- </>;
371
+ </>
298
372
  }
299
373
 
300
374
  const { body } = await render(Basic);
@@ -303,13 +377,11 @@ second"</pre>
303
377
  });
304
378
 
305
379
  it('renders tracked state updates', async () => {
306
- function Counter() {
307
- return <>
308
- let &[count] = track(0);
309
- count++;
310
- count = count + 5;
311
- <div>{count}</div>
312
- </>;
380
+ function Counter() @{
381
+ let &[count] = track(0);
382
+ count++;
383
+ count = count + 5;
384
+ <div>{count}</div>
313
385
  }
314
386
 
315
387
  const { body } = await render(Counter);
@@ -321,19 +393,17 @@ second"</pre>
321
393
  function Child({ count, ...rest }: PropsNoChildren<{
322
394
  count: Tracked<number>;
323
395
  class: { test: boolean };
324
- }>) {
325
- return <>
396
+ }>) @{
397
+ <>
326
398
  <div {...rest}>{'Child Component'}</div>
327
399
  <div>{count.value}</div>
328
- </>;
400
+ </>
329
401
  }
330
402
 
331
- function Parent() {
332
- return <>
333
- const count = track(10);
334
- let Dynamic = track(() => Child);
335
- <@Dynamic {count} class={{ test: true }} />
336
- </>;
403
+ function Parent() @{
404
+ const count = track(10);
405
+ let Dynamic = track(() => Child);
406
+ <@Dynamic {count} class={{ test: true }} />
337
407
  }
338
408
 
339
409
  const { body } = await render(Parent);
@@ -342,13 +412,11 @@ second"</pre>
342
412
  });
343
413
 
344
414
  it('renders tracked object properties', async () => {
345
- function ObjCounter() {
346
- return <>
347
- const obj = { count: track(2) };
348
- obj.count.value += 3;
349
- obj.count.value = obj.count.value + 1;
350
- <div>{obj.count.value}</div>
351
- </>;
415
+ function ObjCounter() @{
416
+ const obj = { count: track(2) };
417
+ obj.count.value += 3;
418
+ obj.count.value = obj.count.value + 1;
419
+ <div>{obj.count.value}</div>
352
420
  }
353
421
 
354
422
  const { body } = await render(ObjCounter);
@@ -357,13 +425,11 @@ second"</pre>
357
425
  });
358
426
 
359
427
  it('renders spread props with tracked values', async () => {
360
- function SpreadProps() {
361
- return <>
362
- let &[id] = track('unique-id');
363
- let &[isActive] = track(true);
364
- let &[styles] = track({ color: 'red', fontSize: '16px' });
365
- <div {...{ id: id, class: { active: isActive }, style: styles }}>{'Spread Props'}</div>
366
- </>;
428
+ function SpreadProps() @{
429
+ let &[id] = track('unique-id');
430
+ let &[isActive] = track(true);
431
+ let &[styles] = track({ color: 'red', fontSize: '16px' });
432
+ <div {...{ id: id, class: { active: isActive }, style: styles }}>{'Spread Props'}</div>
367
433
  }
368
434
 
369
435
  const { body } = await render(SpreadProps);
@@ -374,15 +440,15 @@ second"</pre>
374
440
  });
375
441
 
376
442
  it('handles AssignExpressions with tracked values or properties correctly', async () => {
377
- function Assignments() {
378
- return <>
379
- let &[count] = track(0);
380
- const obj = { value: track(5) };
381
- count += 10;
382
- obj.value.value *= 2;
443
+ function Assignments() @{
444
+ let &[count] = track(0);
445
+ const obj = { value: track(5) };
446
+ count += 10;
447
+ obj.value.value *= 2;
448
+ <>
383
449
  <div>{count}</div>
384
450
  <div>{obj.value.value}</div>
385
- </>;
451
+ </>
386
452
  }
387
453
 
388
454
  const { body } = await render(Assignments);
@@ -391,15 +457,17 @@ second"</pre>
391
457
  });
392
458
 
393
459
  it(`handles derived changes via tracked dependencies' changes`, async () => {
394
- function Derived() {
395
- return <>
396
- let &[base] = track(5);
397
- let &[multiplier] = track(3);
398
- let &[derived] = track(() => base * multiplier);
399
- <div>{derived}</div>
400
- base += 2;
401
- <div>{derived}</div>
402
- </>;
460
+ function Derived() @{
461
+ let &[base] = track(5);
462
+ let &[multiplier] = track(3);
463
+ let &[derived] = track(() => base * multiplier);
464
+ const before = derived;
465
+ base += 2;
466
+ const after = derived;
467
+ <>
468
+ <div>{before}</div>
469
+ <div>{after}</div>
470
+ </>
403
471
  }
404
472
 
405
473
  const { body } = await render(Derived);
@@ -408,16 +476,18 @@ second"</pre>
408
476
  });
409
477
 
410
478
  it(`handles derived changes based on another derived's dependencies' changes`, async () => {
411
- function NestedDerived() {
412
- return <>
413
- let &[a] = track(2);
414
- let &[b] = track(3);
415
- let &[sum] = track(() => a + b);
416
- let &[product] = track(() => sum * 2);
417
- <div>{product}</div>
418
- a = 4;
419
- <div>{product}</div>
420
- </>;
479
+ function NestedDerived() @{
480
+ let &[a] = track(2);
481
+ let &[b] = track(3);
482
+ let &[sum] = track(() => a + b);
483
+ let &[product] = track(() => sum * 2);
484
+ const before = product;
485
+ a = 4;
486
+ const after = product;
487
+ <>
488
+ <div>{before}</div>
489
+ <div>{after}</div>
490
+ </>
421
491
  }
422
492
 
423
493
  const { body } = await render(NestedDerived);
@@ -426,23 +496,31 @@ second"</pre>
426
496
  });
427
497
 
428
498
  it('handles lexical scopes correctly', async () => {
429
- function LexicalScopes() {
430
- return <>
431
- let &[x] = track(1);
499
+ function LexicalScopes() @{
500
+ let &[x] = track(1);
501
+ let nested = '';
502
+ let deep = '';
503
+ let deeper = '';
504
+ {
505
+ let &[x] = track(10);
506
+ nested = String(x);
507
+ }
508
+ {
509
+ let &[x] = track(12);
510
+ deep = String(x);
511
+ {
512
+ let &[x] = track(15);
513
+ deeper = String(x);
514
+ }
515
+ }
516
+ <>
432
517
  <div>{x}</div>
518
+ <div>{nested}</div>
433
519
  <div>
434
- let &[x] = track(10);
435
- {x}
436
- </div>
437
- <div>
438
- let &[x] = track(12);
439
- {x}
440
- <span>
441
- let &[x] = track(15);
442
- {x}
443
- </span>
520
+ {deep}
521
+ <span>{deeper}</span>
444
522
  </div>
445
- </>;
523
+ </>
446
524
  }
447
525
 
448
526
  const { body } = await render(LexicalScopes);
@@ -451,48 +529,48 @@ second"</pre>
451
529
  });
452
530
 
453
531
  it('runs nested JavaScript blocks inside component-local callables', async () => {
454
- function App() {
455
- return <>
456
- function readFunction() {
457
- const label = 'function outer';
458
- let result = '';
532
+ function App() @{
533
+ function readFunction() {
534
+ const label = 'function outer';
535
+ let result = '';
536
+
537
+ {
538
+ const label = 'function inner';
539
+ result = label;
540
+ }
459
541
 
460
- {
461
- const label = 'function inner';
462
- result = label;
463
- }
542
+ return `${result} / ${label}`;
543
+ }
544
+ const readArrow = () => {
545
+ const offset = 5;
546
+ let value = offset;
464
547
 
465
- return `${result} / ${label}`;
548
+ {
549
+ const offset = 17;
550
+ value += offset;
466
551
  }
467
- const readArrow = () => {
468
- const offset = 5;
469
- let value = offset;
552
+
553
+ return value;
554
+ };
555
+ class Reader {
556
+ read() {
557
+ const label = 'method outer';
558
+ let result = '';
470
559
 
471
560
  {
472
- const offset = 17;
473
- value += offset;
561
+ const label = 'method inner';
562
+ result = label;
474
563
  }
475
564
 
476
- return value;
477
- };
478
- class Reader {
479
- read() {
480
- const label = 'method outer';
481
- let result = '';
482
-
483
- {
484
- const label = 'method inner';
485
- result = label;
486
- }
487
-
488
- return `${result} / ${label}`;
489
- }
565
+ return `${result} / ${label}`;
490
566
  }
491
- const reader = new Reader();
567
+ }
568
+ const reader = new Reader();
569
+ <>
492
570
  <div class="block-function">{readFunction()}</div>
493
571
  <div class="block-arrow">{readArrow()}</div>
494
572
  <div class="block-method">{reader.read()}</div>
495
- </>;
573
+ </>
496
574
  }
497
575
 
498
576
  const { body } = await render(App);