ripple 0.3.68 → 0.3.70

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 (182) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -2
  4. package/src/runtime/element.js +1 -1
  5. package/src/runtime/index-client.js +11 -11
  6. package/src/runtime/index-server.js +7 -4
  7. package/src/runtime/internal/client/bindings.js +1 -1
  8. package/src/runtime/internal/client/blocks.js +13 -4
  9. package/src/runtime/internal/client/component.js +55 -0
  10. package/src/runtime/internal/client/composite.js +4 -2
  11. package/src/runtime/internal/client/expression.js +65 -7
  12. package/src/runtime/internal/client/hmr.js +54 -43
  13. package/src/runtime/internal/client/index.js +5 -1
  14. package/src/runtime/internal/client/portal.js +70 -69
  15. package/src/runtime/internal/client/render.js +3 -0
  16. package/src/runtime/internal/server/index.js +92 -8
  17. package/tests/client/__snapshots__/html.test.tsrx.snap +3 -3
  18. package/tests/client/array/array.copy-within.test.tsrx +33 -31
  19. package/tests/client/array/array.derived.test.tsrx +186 -169
  20. package/tests/client/array/array.iteration.test.tsrx +40 -37
  21. package/tests/client/array/array.mutations.test.tsrx +113 -101
  22. package/tests/client/array/array.static.test.tsrx +119 -101
  23. package/tests/client/array/array.to-methods.test.tsrx +24 -21
  24. package/tests/client/async-suspend.test.tsrx +247 -246
  25. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +0 -1
  26. package/tests/client/basic/basic.attributes.test.tsrx +428 -423
  27. package/tests/client/basic/basic.collections.test.tsrx +109 -102
  28. package/tests/client/basic/basic.components.test.tsrx +323 -205
  29. package/tests/client/basic/basic.errors.test.tsrx +91 -91
  30. package/tests/client/basic/basic.events.test.tsrx +114 -115
  31. package/tests/client/basic/basic.get-set.test.tsrx +97 -87
  32. package/tests/client/basic/basic.hmr.test.tsrx +19 -16
  33. package/tests/client/basic/basic.reactivity.test.tsrx +199 -191
  34. package/tests/client/basic/basic.rendering.test.tsrx +272 -182
  35. package/tests/client/basic/basic.styling.test.tsrx +23 -22
  36. package/tests/client/basic/basic.utilities.test.tsrx +10 -8
  37. package/tests/client/boundaries.test.tsrx +26 -26
  38. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +5 -5
  39. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +5 -5
  40. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -81
  41. package/tests/client/compiler/compiler.attributes.test.tsrx +15 -15
  42. package/tests/client/compiler/compiler.basic.test.tsrx +322 -314
  43. package/tests/client/compiler/compiler.regex.test.tsrx +44 -47
  44. package/tests/client/compiler/compiler.tracked-access.test.tsrx +38 -38
  45. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  46. package/tests/client/compiler/compiler.typescript.test.tsrx +2 -2
  47. package/tests/client/composite/composite.dynamic-components.test.tsrx +47 -48
  48. package/tests/client/composite/composite.generics.test.tsrx +168 -192
  49. package/tests/client/composite/composite.props.test.tsrx +97 -81
  50. package/tests/client/composite/composite.reactivity.test.tsrx +177 -147
  51. package/tests/client/composite/composite.render.test.tsrx +122 -105
  52. package/tests/client/computed-properties.test.tsrx +28 -28
  53. package/tests/client/context.test.tsrx +21 -21
  54. package/tests/client/css/global-additional-cases.test.tsrx +58 -58
  55. package/tests/client/css/global-advanced-selectors.test.tsrx +16 -16
  56. package/tests/client/css/global-at-rules.test.tsrx +10 -10
  57. package/tests/client/css/global-basic.test.tsrx +14 -14
  58. package/tests/client/css/global-classes-ids.test.tsrx +14 -14
  59. package/tests/client/css/global-combinators.test.tsrx +10 -10
  60. package/tests/client/css/global-complex-nesting.test.tsrx +14 -14
  61. package/tests/client/css/global-edge-cases.test.tsrx +18 -18
  62. package/tests/client/css/global-keyframes.test.tsrx +12 -12
  63. package/tests/client/css/global-nested.test.tsrx +10 -10
  64. package/tests/client/css/global-pseudo.test.tsrx +12 -12
  65. package/tests/client/css/global-scoping.test.tsrx +20 -20
  66. package/tests/client/css/style-identifier.test.tsrx +126 -259
  67. package/tests/client/date.test.tsrx +146 -133
  68. package/tests/client/dynamic-elements.test.tsrx +398 -365
  69. package/tests/client/events.test.tsrx +292 -290
  70. package/tests/client/for.test.tsrx +156 -153
  71. package/tests/client/head.test.tsrx +105 -96
  72. package/tests/client/html.test.tsrx +122 -26
  73. package/tests/client/input-value.test.tsrx +1361 -1314
  74. package/tests/client/lazy-array.test.tsrx +16 -13
  75. package/tests/client/lazy-destructuring.test.tsrx +257 -213
  76. package/tests/client/map.test.tsrx +65 -60
  77. package/tests/client/media-query.test.tsrx +22 -20
  78. package/tests/client/object.test.tsrx +87 -81
  79. package/tests/client/portal.test.tsrx +57 -51
  80. package/tests/client/ref.test.tsrx +233 -202
  81. package/tests/client/return.test.tsrx +71 -2560
  82. package/tests/client/set.test.tsrx +54 -45
  83. package/tests/client/svg.test.tsrx +216 -186
  84. package/tests/client/switch.test.tsrx +194 -193
  85. package/tests/client/track-async-hydration.test.tsrx +18 -14
  86. package/tests/client/tracked-index-access.test.tsrx +28 -18
  87. package/tests/client/try.test.tsrx +675 -548
  88. package/tests/client/tsx.test.tsrx +373 -311
  89. package/tests/client/typescript-generics.test.tsrx +145 -145
  90. package/tests/client/url/url.derived.test.tsrx +33 -28
  91. package/tests/client/url/url.parsing.test.tsrx +61 -51
  92. package/tests/client/url/url.partial-removal.test.tsrx +56 -48
  93. package/tests/client/url/url.reactivity.test.tsrx +142 -125
  94. package/tests/client/url/url.serialization.test.tsrx +13 -11
  95. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +34 -29
  96. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +25 -21
  97. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +50 -45
  98. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +111 -99
  99. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +49 -43
  100. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +14 -12
  101. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +16 -14
  102. package/tests/hydration/basic.test.js +3 -3
  103. package/tests/hydration/compiled/client/basic.js +586 -651
  104. package/tests/hydration/compiled/client/composite.js +79 -104
  105. package/tests/hydration/compiled/client/events.js +140 -148
  106. package/tests/hydration/compiled/client/for.js +1005 -1018
  107. package/tests/hydration/compiled/client/head.js +124 -134
  108. package/tests/hydration/compiled/client/hmr.js +41 -48
  109. package/tests/hydration/compiled/client/html-in-template.js +38 -41
  110. package/tests/hydration/compiled/client/html.js +970 -1314
  111. package/tests/hydration/compiled/client/if-children.js +234 -249
  112. package/tests/hydration/compiled/client/if.js +182 -189
  113. package/tests/hydration/compiled/client/mixed-control-flow.js +347 -303
  114. package/tests/hydration/compiled/client/nested-control-flow.js +1084 -832
  115. package/tests/hydration/compiled/client/portal.js +65 -85
  116. package/tests/hydration/compiled/client/reactivity.js +84 -90
  117. package/tests/hydration/compiled/client/return.js +38 -1939
  118. package/tests/hydration/compiled/client/switch.js +218 -224
  119. package/tests/hydration/compiled/client/track-async-serialization.js +250 -259
  120. package/tests/hydration/compiled/client/try.js +123 -132
  121. package/tests/hydration/compiled/server/basic.js +773 -831
  122. package/tests/hydration/compiled/server/composite.js +166 -191
  123. package/tests/hydration/compiled/server/events.js +170 -184
  124. package/tests/hydration/compiled/server/for.js +851 -909
  125. package/tests/hydration/compiled/server/head.js +206 -216
  126. package/tests/hydration/compiled/server/hmr.js +64 -72
  127. package/tests/hydration/compiled/server/html-in-template.js +42 -76
  128. package/tests/hydration/compiled/server/html.js +1362 -1667
  129. package/tests/hydration/compiled/server/if-children.js +419 -445
  130. package/tests/hydration/compiled/server/if.js +194 -208
  131. package/tests/hydration/compiled/server/mixed-control-flow.js +249 -257
  132. package/tests/hydration/compiled/server/nested-control-flow.js +491 -515
  133. package/tests/hydration/compiled/server/portal.js +152 -160
  134. package/tests/hydration/compiled/server/reactivity.js +94 -106
  135. package/tests/hydration/compiled/server/return.js +28 -2172
  136. package/tests/hydration/compiled/server/switch.js +274 -286
  137. package/tests/hydration/compiled/server/track-async-serialization.js +340 -358
  138. package/tests/hydration/compiled/server/try.js +167 -185
  139. package/tests/hydration/components/basic.tsrx +320 -272
  140. package/tests/hydration/components/composite.tsrx +44 -32
  141. package/tests/hydration/components/events.tsrx +101 -91
  142. package/tests/hydration/components/for.tsrx +510 -452
  143. package/tests/hydration/components/head.tsrx +87 -80
  144. package/tests/hydration/components/hmr.tsrx +22 -17
  145. package/tests/hydration/components/html-in-template.tsrx +22 -17
  146. package/tests/hydration/components/html.tsrx +525 -443
  147. package/tests/hydration/components/if-children.tsrx +158 -148
  148. package/tests/hydration/components/if.tsrx +109 -95
  149. package/tests/hydration/components/mixed-control-flow.tsrx +100 -96
  150. package/tests/hydration/components/nested-control-flow.tsrx +215 -203
  151. package/tests/hydration/components/portal.tsrx +41 -34
  152. package/tests/hydration/components/reactivity.tsrx +37 -27
  153. package/tests/hydration/components/return.tsrx +12 -556
  154. package/tests/hydration/components/switch.tsrx +120 -114
  155. package/tests/hydration/components/track-async-serialization.tsrx +107 -91
  156. package/tests/hydration/components/try.tsrx +55 -40
  157. package/tests/hydration/html.test.js +4 -4
  158. package/tests/hydration/return.test.js +13 -532
  159. package/tests/server/await.test.tsrx +3 -3
  160. package/tests/server/basic.attributes.test.tsrx +264 -195
  161. package/tests/server/basic.components.test.tsrx +296 -169
  162. package/tests/server/basic.test.tsrx +300 -198
  163. package/tests/server/compiler.test.tsrx +62 -60
  164. package/tests/server/composite.props.test.tsrx +77 -63
  165. package/tests/server/composite.test.tsrx +168 -192
  166. package/tests/server/context.test.tsrx +18 -12
  167. package/tests/server/dynamic-elements.test.tsrx +197 -180
  168. package/tests/server/for.test.tsrx +85 -78
  169. package/tests/server/head.test.tsrx +50 -43
  170. package/tests/server/html-nesting-validation.test.tsrx +8 -8
  171. package/tests/server/if.test.tsrx +57 -51
  172. package/tests/server/lazy-destructuring.test.tsrx +366 -294
  173. package/tests/server/return.test.tsrx +76 -1355
  174. package/tests/server/streaming-ssr.test.tsrx +4 -75
  175. package/tests/server/style-identifier.test.tsrx +169 -131
  176. package/tests/server/switch.test.tsrx +91 -85
  177. package/tests/server/track-async-serialization.test.tsrx +105 -85
  178. package/tests/server/try.test.tsrx +374 -280
  179. package/tests/utils/compiler-compat-config.test.js +2 -2
  180. package/tests/utils/runtime-imports.test.js +10 -0
  181. package/types/index.d.ts +8 -0
  182. package/tests/client/__snapshots__/html.test.rsrx.snap +0 -40
@@ -2,13 +2,15 @@ import { trackAsync } from 'ripple';
2
2
 
3
3
  describe('try block with catch and pending (server)', () => {
4
4
  it('renders resolved content with an empty pending fallback', async () => {
5
- component App() {
6
- <span>{'before'}</span>
7
- try {
8
- let &[data] = trackAsync(() => Promise.resolve('resolved value'));
9
- <p>{data}</p>
10
- } pending {}
11
- <span>{'after'}</span>
5
+ function App() {
6
+ return <>
7
+ <span>{'before'}</span>
8
+ try {
9
+ let &[data] = trackAsync(() => Promise.resolve('resolved value'));
10
+ <p>{data}</p>
11
+ } pending {}
12
+ <span>{'after'}</span>
13
+ </>;
12
14
  }
13
15
 
14
16
  const { body } = await render(App);
@@ -19,20 +21,24 @@ describe('try block with catch and pending (server)', () => {
19
21
  });
20
22
 
21
23
  it('catch block works when component throws before await with pending block', async () => {
22
- component ThrowingChild() {
23
- throw new Error('sync error');
24
- let &[data] = trackAsync(() => Promise.resolve('hello'));
25
- <p>{data}</p>
26
- }
27
-
28
- component App() {
29
- try {
30
- <ThrowingChild />
31
- } pending {
32
- <p>{'loading...'}</p>
33
- } catch (err) {
34
- <p>{'caught error'}</p>
35
- }
24
+ function ThrowingChild() {
25
+ return <>
26
+ throw new Error('sync error');
27
+ let &[data] = trackAsync(() => Promise.resolve('hello'));
28
+ <p>{data}</p>
29
+ </>;
30
+ }
31
+
32
+ function App() {
33
+ return <>
34
+ try {
35
+ <ThrowingChild />
36
+ } pending {
37
+ <p>{'loading...'}</p>
38
+ } catch (err) {
39
+ <p>{'caught error'}</p>
40
+ }
41
+ </>;
36
42
  }
37
43
 
38
44
  const { body } = await render(App);
@@ -41,20 +47,24 @@ describe('try block with catch and pending (server)', () => {
41
47
  });
42
48
 
43
49
  it('catch block works when component throws after await with pending block', async () => {
44
- component ThrowingAfterAwait() {
45
- let &[data] = trackAsync(() => Promise.resolve('hello'));
46
- throw new Error('error after await');
47
- <p>{data}</p>
48
- }
49
-
50
- component App() {
51
- try {
52
- <ThrowingAfterAwait />
53
- } pending {
54
- <p>{'loading...'}</p>
55
- } catch (err) {
56
- <p>{'caught error'}</p>
57
- }
50
+ function ThrowingAfterAwait() {
51
+ return <>
52
+ let &[data] = trackAsync(() => Promise.resolve('hello'));
53
+ throw new Error('error after await');
54
+ <p>{data}</p>
55
+ </>;
56
+ }
57
+
58
+ function App() {
59
+ return <>
60
+ try {
61
+ <ThrowingAfterAwait />
62
+ } pending {
63
+ <p>{'loading...'}</p>
64
+ } catch (err) {
65
+ <p>{'caught error'}</p>
66
+ }
67
+ </>;
58
68
  }
59
69
 
60
70
  const { body } = await render(App);
@@ -63,15 +73,17 @@ describe('try block with catch and pending (server)', () => {
63
73
  });
64
74
 
65
75
  it('catch block works with try/catch/pending when async body rejects', async () => {
66
- component App() {
67
- try {
68
- let &[data] = trackAsync(() => Promise.reject(new Error('rejected')));
69
- <p>{data}</p>
70
- } pending {
71
- <p>{'loading...'}</p>
72
- } catch (err) {
73
- <p>{'caught rejection'}</p>
74
- }
76
+ function App() {
77
+ return <>
78
+ try {
79
+ let &[data] = trackAsync(() => Promise.reject(new Error('rejected')));
80
+ <p>{data}</p>
81
+ } pending {
82
+ <p>{'loading...'}</p>
83
+ } catch (err) {
84
+ <p>{'caught rejection'}</p>
85
+ }
86
+ </>;
75
87
  }
76
88
 
77
89
  const { body } = await render(App);
@@ -80,17 +92,19 @@ describe('try block with catch and pending (server)', () => {
80
92
  });
81
93
 
82
94
  it('removes pending content for nested try/pending blocks', async () => {
83
- component App() {
84
- try {
95
+ function App() {
96
+ return <>
85
97
  try {
86
- let &[data] = trackAsync(() => Promise.resolve('resolved'));
87
- <p>{data}</p>
98
+ try {
99
+ let &[data] = trackAsync(() => Promise.resolve('resolved'));
100
+ <p>{data}</p>
101
+ } pending {
102
+ <p>{'inner loading...'}</p>
103
+ }
88
104
  } pending {
89
- <p>{'inner loading...'}</p>
105
+ <p>{'outer loading...'}</p>
90
106
  }
91
- } pending {
92
- <p>{'outer loading...'}</p>
93
- }
107
+ </>;
94
108
  }
95
109
 
96
110
  const { body } = await render(App);
@@ -102,17 +116,21 @@ describe('try block with catch and pending (server)', () => {
102
116
 
103
117
  describe('trackAsync directly in component body (server)', () => {
104
118
  it('resolves trackAsync used directly in a component', async () => {
105
- component App() {
106
- try {
107
- <DataChild />
108
- } catch (err) {
109
- <p>{'error'}</p>
110
- }
119
+ function App() {
120
+ return <>
121
+ try {
122
+ <DataChild />
123
+ } catch (err) {
124
+ <p>{'error'}</p>
125
+ }
126
+ </>;
111
127
  }
112
128
 
113
- component DataChild() {
114
- let &[data] = trackAsync(() => Promise.resolve('from child'));
115
- <p>{data}</p>
129
+ function DataChild() {
130
+ return <>
131
+ let &[data] = trackAsync(() => Promise.resolve('from child'));
132
+ <p>{data}</p>
133
+ </>;
116
134
  }
117
135
 
118
136
  const { body } = await render(App);
@@ -121,18 +139,20 @@ describe('trackAsync directly in component body (server)', () => {
121
139
  });
122
140
 
123
141
  it('resolves multiple trackAsync values in the same component', async () => {
124
- component App() {
125
- try {
126
- let &[a] = trackAsync(() => Promise.resolve('hello'));
127
- let &[b] = trackAsync(() => Promise.resolve('world'));
128
- <p>
129
- {a}
130
- {' '}
131
- {b}
132
- </p>
133
- } catch (err) {
134
- <p>{'error'}</p>
135
- }
142
+ function App() {
143
+ return <>
144
+ try {
145
+ let &[a] = trackAsync(() => Promise.resolve('hello'));
146
+ let &[b] = trackAsync(() => Promise.resolve('world'));
147
+ <p>
148
+ {a}
149
+ {' '}
150
+ {b}
151
+ </p>
152
+ } catch (err) {
153
+ <p>{'error'}</p>
154
+ }
155
+ </>;
136
156
  }
137
157
 
138
158
  const { body } = await render(App);
@@ -141,17 +161,21 @@ describe('trackAsync directly in component body (server)', () => {
141
161
  });
142
162
 
143
163
  it('renders catch when trackAsync rejects in a child component without its own try', async () => {
144
- component RejectChild() {
145
- let &[data] = trackAsync(() => Promise.reject(new Error('child rejected')));
146
- <p>{data}</p>
164
+ function RejectChild() {
165
+ return <>
166
+ let &[data] = trackAsync(() => Promise.reject(new Error('child rejected')));
167
+ <p>{data}</p>
168
+ </>;
147
169
  }
148
170
 
149
- component App() {
150
- try {
151
- <RejectChild />
152
- } catch (err) {
153
- <p>{'parent caught it'}</p>
154
- }
171
+ function App() {
172
+ return <>
173
+ try {
174
+ <RejectChild />
175
+ } catch (err) {
176
+ <p>{'parent caught it'}</p>
177
+ }
178
+ </>;
155
179
  }
156
180
 
157
181
  const { body } = await render(App);
@@ -159,17 +183,19 @@ describe('trackAsync directly in component body (server)', () => {
159
183
  });
160
184
 
161
185
  it('chained trackAsync resolves both values', async () => {
162
- component App() {
163
- try {
164
- let &[name] = trackAsync(() => Promise.resolve('ripple'));
165
- let &[upper] = trackAsync(() => {
166
- const n = name;
167
- return Promise.resolve(n.toUpperCase());
168
- });
169
- <p>{upper}</p>
170
- } catch (err) {
171
- <p>{'error'}</p>
172
- }
186
+ function App() {
187
+ return <>
188
+ try {
189
+ let &[name] = trackAsync(() => Promise.resolve('ripple'));
190
+ let &[upper] = trackAsync(() => {
191
+ const n = name;
192
+ return Promise.resolve(n.toUpperCase());
193
+ });
194
+ <p>{upper}</p>
195
+ } catch (err) {
196
+ <p>{'error'}</p>
197
+ }
198
+ </>;
173
199
  }
174
200
 
175
201
  const { body } = await render(App);
@@ -178,17 +204,19 @@ describe('trackAsync directly in component body (server)', () => {
178
204
  });
179
205
 
180
206
  it('chained trackAsync catches when first rejects', async () => {
181
- component App() {
182
- try {
183
- let &[name] = trackAsync(() => Promise.reject<string>(new Error('first failed')));
184
- let &[upper] = trackAsync(() => {
185
- const n = name;
186
- return Promise.resolve(n.toUpperCase());
187
- });
188
- <p>{upper}</p>
189
- } catch (err: Error) {
190
- <p>{err.message}</p>
191
- }
207
+ function App() {
208
+ return <>
209
+ try {
210
+ let &[name] = trackAsync(() => Promise.reject<string>(new Error('first failed')));
211
+ let &[upper] = trackAsync(() => {
212
+ const n = name;
213
+ return Promise.resolve(n.toUpperCase());
214
+ });
215
+ <p>{upper}</p>
216
+ } catch (err: Error) {
217
+ <p>{err.message}</p>
218
+ }
219
+ </>;
192
220
  }
193
221
 
194
222
  const { body } = await render(App);
@@ -196,17 +224,19 @@ describe('trackAsync directly in component body (server)', () => {
196
224
  });
197
225
 
198
226
  it('chained trackAsync catches when second rejects', async () => {
199
- component App() {
200
- try {
201
- let &[name] = trackAsync(() => Promise.resolve('ripple'));
202
- let &[upper] = trackAsync(() => {
203
- const n = name;
204
- return Promise.reject(new Error('second failed'));
205
- });
206
- <p>{upper}</p>
207
- } catch (err: Error) {
208
- <p>{err.message}</p>
209
- }
227
+ function App() {
228
+ return <>
229
+ try {
230
+ let &[name] = trackAsync(() => Promise.resolve('ripple'));
231
+ let &[upper] = trackAsync(() => {
232
+ const n = name;
233
+ return Promise.reject(new Error('second failed'));
234
+ });
235
+ <p>{upper}</p>
236
+ } catch (err: Error) {
237
+ <p>{err.message}</p>
238
+ }
239
+ </>;
210
240
  }
211
241
 
212
242
  const { body } = await render(App);
@@ -216,25 +246,31 @@ describe('trackAsync directly in component body (server)', () => {
216
246
 
217
247
  describe('nested child components with try/catch boundaries (server)', () => {
218
248
  it('inner try/catch catches error from its own child', async () => {
219
- component ThrowingChild() {
220
- throw new Error('inner error');
221
- <p>{'should not render'}</p>
249
+ function ThrowingChild() {
250
+ return <>
251
+ throw new Error('inner error');
252
+ <p>{'should not render'}</p>
253
+ </>;
222
254
  }
223
255
 
224
- component Inner() {
225
- try {
226
- <ThrowingChild />
227
- } catch (err: Error) {
228
- <p>{err.message}</p>
229
- }
256
+ function Inner() {
257
+ return <>
258
+ try {
259
+ <ThrowingChild />
260
+ } catch (err: Error) {
261
+ <p>{err.message}</p>
262
+ }
263
+ </>;
230
264
  }
231
265
 
232
- component App() {
233
- try {
234
- <Inner />
235
- } catch (err) {
236
- <p>{'outer caught'}</p>
237
- }
266
+ function App() {
267
+ return <>
268
+ try {
269
+ <Inner />
270
+ } catch (err) {
271
+ <p>{'outer caught'}</p>
272
+ }
273
+ </>;
238
274
  }
239
275
 
240
276
  const { body } = await render(App);
@@ -243,25 +279,31 @@ describe('nested child components with try/catch boundaries (server)', () => {
243
279
  });
244
280
 
245
281
  it('inner try/catch catches async rejection from its own child', async () => {
246
- component AsyncChild() {
247
- let &[data] = trackAsync(() => Promise.reject(new Error('async inner error')));
248
- <p>{data}</p>
282
+ function AsyncChild() {
283
+ return <>
284
+ let &[data] = trackAsync(() => Promise.reject(new Error('async inner error')));
285
+ <p>{data}</p>
286
+ </>;
249
287
  }
250
288
 
251
- component Inner() {
252
- try {
253
- <AsyncChild />
254
- } catch (err: Error) {
255
- <p>{err.message}</p>
256
- }
289
+ function Inner() {
290
+ return <>
291
+ try {
292
+ <AsyncChild />
293
+ } catch (err: Error) {
294
+ <p>{err.message}</p>
295
+ }
296
+ </>;
257
297
  }
258
298
 
259
- component App() {
260
- try {
261
- <Inner />
262
- } catch (err) {
263
- <p>{'outer caught'}</p>
264
- }
299
+ function App() {
300
+ return <>
301
+ try {
302
+ <Inner />
303
+ } catch (err) {
304
+ <p>{'outer caught'}</p>
305
+ }
306
+ </>;
265
307
  }
266
308
 
267
309
  const { body } = await render(App);
@@ -270,25 +312,31 @@ describe('nested child components with try/catch boundaries (server)', () => {
270
312
  });
271
313
 
272
314
  it('error propagates to outer catch when inner try has no catch', async () => {
273
- component ThrowingChild() {
274
- throw new Error('propagated error');
275
- <p>{'should not render'}</p>
315
+ function ThrowingChild() {
316
+ return <>
317
+ throw new Error('propagated error');
318
+ <p>{'should not render'}</p>
319
+ </>;
276
320
  }
277
321
 
278
- component Inner() {
279
- try {
280
- <ThrowingChild />
281
- } pending {
282
- <p>{'loading...'}</p>
283
- }
322
+ function Inner() {
323
+ return <>
324
+ try {
325
+ <ThrowingChild />
326
+ } pending {
327
+ <p>{'loading...'}</p>
328
+ }
329
+ </>;
284
330
  }
285
331
 
286
- component App() {
287
- try {
288
- <Inner />
289
- } catch (err: Error) {
290
- <p>{err.message}</p>
291
- }
332
+ function App() {
333
+ return <>
334
+ try {
335
+ <Inner />
336
+ } catch (err: Error) {
337
+ <p>{err.message}</p>
338
+ }
339
+ </>;
292
340
  }
293
341
 
294
342
  const { body } = await render(App);
@@ -297,25 +345,31 @@ describe('nested child components with try/catch boundaries (server)', () => {
297
345
  });
298
346
 
299
347
  it('async rejection propagates to outer catch when inner try has no catch', async () => {
300
- component AsyncChild() {
301
- let &[data] = trackAsync(() => Promise.reject(new Error('async propagated')));
302
- <p>{data}</p>
348
+ function AsyncChild() {
349
+ return <>
350
+ let &[data] = trackAsync(() => Promise.reject(new Error('async propagated')));
351
+ <p>{data}</p>
352
+ </>;
303
353
  }
304
354
 
305
- component Inner() {
306
- try {
307
- <AsyncChild />
308
- } pending {
309
- <p>{'loading...'}</p>
310
- }
355
+ function Inner() {
356
+ return <>
357
+ try {
358
+ <AsyncChild />
359
+ } pending {
360
+ <p>{'loading...'}</p>
361
+ }
362
+ </>;
311
363
  }
312
364
 
313
- component App() {
314
- try {
315
- <Inner />
316
- } catch (err: Error) {
317
- <p>{err.message}</p>
318
- }
365
+ function App() {
366
+ return <>
367
+ try {
368
+ <Inner />
369
+ } catch (err: Error) {
370
+ <p>{err.message}</p>
371
+ }
372
+ </>;
319
373
  }
320
374
 
321
375
  const { body } = await render(App);
@@ -326,33 +380,41 @@ describe('nested child components with try/catch boundaries (server)', () => {
326
380
  it(
327
381
  'multiple nested levels: error propagates through pending-only boundaries to nearest catch',
328
382
  async () => {
329
- component ThrowingChild() {
330
- throw new Error('deep error');
331
- <p>{'should not render'}</p>
383
+ function ThrowingChild() {
384
+ return <>
385
+ throw new Error('deep error');
386
+ <p>{'should not render'}</p>
387
+ </>;
332
388
  }
333
389
 
334
- component Level3() {
335
- try {
336
- <ThrowingChild />
337
- } pending {
338
- <p>{'level3 loading'}</p>
339
- }
390
+ function Level3() {
391
+ return <>
392
+ try {
393
+ <ThrowingChild />
394
+ } pending {
395
+ <p>{'level3 loading'}</p>
396
+ }
397
+ </>;
340
398
  }
341
399
 
342
- component Level2() {
343
- try {
344
- <Level3 />
345
- } pending {
346
- <p>{'level2 loading'}</p>
347
- }
400
+ function Level2() {
401
+ return <>
402
+ try {
403
+ <Level3 />
404
+ } pending {
405
+ <p>{'level2 loading'}</p>
406
+ }
407
+ </>;
348
408
  }
349
409
 
350
- component App() {
351
- try {
352
- <Level2 />
353
- } catch (err: Error) {
354
- <p>{err.message}</p>
355
- }
410
+ function App() {
411
+ return <>
412
+ try {
413
+ <Level2 />
414
+ } catch (err: Error) {
415
+ <p>{err.message}</p>
416
+ }
417
+ </>;
356
418
  }
357
419
 
358
420
  const { body } = await render(App);
@@ -361,23 +423,29 @@ describe('nested child components with try/catch boundaries (server)', () => {
361
423
  );
362
424
 
363
425
  it('sibling components: one fails, the other does not affect catch', async () => {
364
- component GoodChild() {
365
- let &[data] = trackAsync(() => Promise.resolve('good'));
366
- <p>{data}</p>
426
+ function GoodChild() {
427
+ return <>
428
+ let &[data] = trackAsync(() => Promise.resolve('good'));
429
+ <p>{data}</p>
430
+ </>;
367
431
  }
368
432
 
369
- component BadChild() {
370
- let &[data] = trackAsync(() => Promise.reject(new Error('bad child')));
371
- <p>{data}</p>
433
+ function BadChild() {
434
+ return <>
435
+ let &[data] = trackAsync(() => Promise.reject(new Error('bad child')));
436
+ <p>{data}</p>
437
+ </>;
372
438
  }
373
439
 
374
- component App() {
375
- try {
376
- <GoodChild />
377
- <BadChild />
378
- } catch (err: Error) {
379
- <p>{err.message}</p>
380
- }
440
+ function App() {
441
+ return <>
442
+ try {
443
+ <GoodChild />
444
+ <BadChild />
445
+ } catch (err: Error) {
446
+ <p>{err.message}</p>
447
+ }
448
+ </>;
381
449
  }
382
450
 
383
451
  const { body } = await render(App);
@@ -386,27 +454,33 @@ describe('nested child components with try/catch boundaries (server)', () => {
386
454
  });
387
455
 
388
456
  it('independent try/catch boundaries each handle their own errors', async () => {
389
- component FailChild() {
390
- let &[data] = trackAsync(() => Promise.reject(new Error('fail')));
391
- <p>{data}</p>
457
+ function FailChild() {
458
+ return <>
459
+ let &[data] = trackAsync(() => Promise.reject(new Error('fail')));
460
+ <p>{data}</p>
461
+ </>;
392
462
  }
393
463
 
394
- component SuccessChild() {
395
- let &[data] = trackAsync(() => Promise.resolve('success'));
396
- <p>{data}</p>
464
+ function SuccessChild() {
465
+ return <>
466
+ let &[data] = trackAsync(() => Promise.resolve('success'));
467
+ <p>{data}</p>
468
+ </>;
397
469
  }
398
470
 
399
- component App() {
400
- try {
401
- <FailChild />
402
- } catch (err: Error) {
403
- <p>{err.message}</p>
404
- }
405
- try {
406
- <SuccessChild />
407
- } catch (err) {
408
- <p>{'should not catch'}</p>
409
- }
471
+ function App() {
472
+ return <>
473
+ try {
474
+ <FailChild />
475
+ } catch (err: Error) {
476
+ <p>{err.message}</p>
477
+ }
478
+ try {
479
+ <SuccessChild />
480
+ } catch (err) {
481
+ <p>{'should not catch'}</p>
482
+ }
483
+ </>;
410
484
  }
411
485
 
412
486
  const { body } = await render(App);
@@ -416,24 +490,30 @@ describe('nested child components with try/catch boundaries (server)', () => {
416
490
  });
417
491
 
418
492
  it('inner catch handles rejection, outer renders normally', async () => {
419
- component AsyncChild() {
420
- let &[data] = trackAsync(() => Promise.reject(new Error('handled inside')));
421
- <p>{data}</p>
493
+ function AsyncChild() {
494
+ return <>
495
+ let &[data] = trackAsync(() => Promise.reject(new Error('handled inside')));
496
+ <p>{data}</p>
497
+ </>;
422
498
  }
423
499
 
424
- component Inner() {
425
- try {
426
- <AsyncChild />
427
- } catch (err: Error) {
428
- <span>{err.message}</span>
429
- }
500
+ function Inner() {
501
+ return <>
502
+ try {
503
+ <AsyncChild />
504
+ } catch (err: Error) {
505
+ <span>{err.message}</span>
506
+ }
507
+ </>;
430
508
  }
431
509
 
432
- component App() {
433
- <div>
434
- <h1>{'App'}</h1>
435
- <Inner />
436
- </div>
510
+ function App() {
511
+ return <>
512
+ <div>
513
+ <h1>{'App'}</h1>
514
+ <Inner />
515
+ </div>
516
+ </>;
437
517
  }
438
518
 
439
519
  const { body } = await render(App);
@@ -442,22 +522,26 @@ describe('nested child components with try/catch boundaries (server)', () => {
442
522
  });
443
523
 
444
524
  it('sync error in child after trackAsync routes to catch boundary', async () => {
445
- component BrokenChild() {
446
- let &[data] = trackAsync(() => Promise.resolve('loaded'));
447
- throw new Error('sync after async');
448
- <p>{data}</p>
525
+ function BrokenChild() {
526
+ return <>
527
+ let &[data] = trackAsync(() => Promise.resolve('loaded'));
528
+ throw new Error('sync after async');
529
+ <p>{data}</p>
530
+ </>;
449
531
  }
450
532
 
451
- component Inner() {
452
- try {
453
- <BrokenChild />
454
- } catch (err: Error) {
455
- <p>{err.message}</p>
456
- }
533
+ function Inner() {
534
+ return <>
535
+ try {
536
+ <BrokenChild />
537
+ } catch (err: Error) {
538
+ <p>{err.message}</p>
539
+ }
540
+ </>;
457
541
  }
458
542
 
459
- component App() {
460
- <Inner />
543
+ function App() {
544
+ return <><Inner /></>;
461
545
  }
462
546
 
463
547
  const { body } = await render(App);
@@ -465,25 +549,31 @@ describe('nested child components with try/catch boundaries (server)', () => {
465
549
  });
466
550
 
467
551
  it('outer try with pending, inner try with catch: rejection goes to inner catch', async () => {
468
- component AsyncChild() {
469
- let &[data] = trackAsync(() => Promise.reject(new Error('inner rejection')));
470
- <p>{data}</p>
552
+ function AsyncChild() {
553
+ return <>
554
+ let &[data] = trackAsync(() => Promise.reject(new Error('inner rejection')));
555
+ <p>{data}</p>
556
+ </>;
471
557
  }
472
558
 
473
- component Inner() {
474
- try {
475
- <AsyncChild />
476
- } catch (err: Error) {
477
- <p>{err.message}</p>
478
- }
559
+ function Inner() {
560
+ return <>
561
+ try {
562
+ <AsyncChild />
563
+ } catch (err: Error) {
564
+ <p>{err.message}</p>
565
+ }
566
+ </>;
479
567
  }
480
568
 
481
- component App() {
482
- try {
483
- <Inner />
484
- } pending {
485
- <p>{'outer loading'}</p>
486
- }
569
+ function App() {
570
+ return <>
571
+ try {
572
+ <Inner />
573
+ } pending {
574
+ <p>{'outer loading'}</p>
575
+ }
576
+ </>;
487
577
  }
488
578
 
489
579
  const { body } = await render(App);
@@ -492,25 +582,29 @@ describe('nested child components with try/catch boundaries (server)', () => {
492
582
  });
493
583
 
494
584
  it('deeply nested: async resolves through multiple component layers', async () => {
495
- component DataFetcher() {
496
- let &[data] = trackAsync(() => Promise.resolve('deep data'));
497
- <span>{data}</span>
585
+ function DataFetcher() {
586
+ return <>
587
+ let &[data] = trackAsync(() => Promise.resolve('deep data'));
588
+ <span>{data}</span>
589
+ </>;
498
590
  }
499
591
 
500
- component Level2() {
501
- <div><DataFetcher /></div>
592
+ function Level2() {
593
+ return <><div><DataFetcher /></div></>;
502
594
  }
503
595
 
504
- component Level1() {
505
- <section><Level2 /></section>
596
+ function Level1() {
597
+ return <><section><Level2 /></section></>;
506
598
  }
507
599
 
508
- component App() {
509
- try {
510
- <Level1 />
511
- } catch (err) {
512
- <p>{'error'}</p>
513
- }
600
+ function App() {
601
+ return <>
602
+ try {
603
+ <Level1 />
604
+ } catch (err) {
605
+ <p>{'error'}</p>
606
+ }
607
+ </>;
514
608
  }
515
609
 
516
610
  const { body } = await render(App);