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
@@ -2,25 +2,26 @@ import { flushSync, track } from 'ripple';
2
2
 
3
3
  describe('switch statements', () => {
4
4
  it('renders simple switch with literal cases', () => {
5
- function App() {
6
- return <>
7
- let &[value] = track('b');
5
+ function App() @{
6
+ let &[value] = track('b');
7
+ <>
8
8
  <button onClick={() => (value = 'c')}>{'Change to C'}</button>
9
9
  <button onClick={() => (value = 'a')}>{'Change to A'}</button>
10
- switch (value) {
11
- case 'a':
12
- <div>{'Case A'}</div>
13
- break;
14
- case 'b':
15
- <div>{'Case B'}</div>
16
- break;
17
- case 'c':
10
+ @switch (value) {
11
+ @case 'a': {
12
+ <div>Case A</div>
13
+ }
14
+ @case 'b': {
15
+ <div>Case B</div>
16
+ }
17
+ @case 'c': {
18
18
  <div>{'Case C'}</div>
19
- break;
20
- default:
19
+ }
20
+ @default: {
21
21
  <div>{'Default Case'}</div>
22
+ }
22
23
  }
23
- </>;
24
+ </>
24
25
  }
25
26
 
26
27
  render(App);
@@ -37,21 +38,22 @@ describe('switch statements', () => {
37
38
  });
38
39
 
39
40
  it('renders switch with reactive discriminant', () => {
40
- function App() {
41
- return <>
42
- let &[count] = track(1);
41
+ function App() @{
42
+ let &[count] = track(1);
43
+ <>
43
44
  <button onClick={() => count++}>{'Increment'}</button>
44
- switch (count) {
45
- case 1:
45
+ @switch (count) {
46
+ @case 1: {
46
47
  <div>{'Count is 1'}</div>
47
- break;
48
- case 2:
48
+ }
49
+ @case 2: {
49
50
  <div>{'Count is 2'}</div>
50
- break;
51
- default:
51
+ }
52
+ @default: {
52
53
  <div>{'Count is other'}</div>
54
+ }
53
55
  }
54
- </>;
56
+ </>
55
57
  }
56
58
 
57
59
  render(App);
@@ -69,15 +71,18 @@ describe('switch statements', () => {
69
71
  });
70
72
 
71
73
  it('renders switch with default clause only', () => {
72
- function App() {
73
- return <>
74
- let &[value] = track('x');
74
+ function App() @{
75
+ let &[value] = track('x');
76
+ <>
75
77
  <button onClick={() => (value = 'y')}>{'Change Value'}</button>
76
- switch (value) {
77
- default:
78
- <div>{'Default for ' + value}</div>
78
+ @switch (value) {
79
+ @default: {
80
+ <div>
81
+ {'Default for ' + value}
82
+ </div>
83
+ }
79
84
  }
80
- </>;
85
+ </>
81
86
  }
82
87
 
83
88
  render(App);
@@ -89,24 +94,26 @@ describe('switch statements', () => {
89
94
  expect(container.querySelector('div').textContent).toBe('Default for y');
90
95
  });
91
96
 
92
- it('renders switch using empty case fall-through', () => {
93
- function App() {
94
- return <>
95
- let &[value] = track('a');
97
+ it('renders switch with isolated empty cases', () => {
98
+ function App() @{
99
+ let &[value] = track('a');
100
+ <>
96
101
  <button onClick={() => (value = 'b')}>{'Change to B'}</button>
97
102
  <button onClick={() => (value = 'c')}>{'Change to C'}</button>
98
- switch (value) {
99
- case 'a':
100
- <div>{'Case A'}</div>
101
- break;
102
- case 'b':
103
- case 'c':
104
- <div>{'Case B or C'}</div>
105
- break;
106
- default:
103
+ @switch (value) {
104
+ @case 'a': {
105
+ <div>Case A</div>
106
+ }
107
+ @case 'b': {
108
+ }
109
+ @case 'c': {
110
+ <div>Case B or C</div>
111
+ }
112
+ @default: {
107
113
  <div>{'Default Case'}</div>
114
+ }
108
115
  }
109
- </>;
116
+ </>
110
117
  }
111
118
 
112
119
  render(App);
@@ -117,7 +124,7 @@ describe('switch statements', () => {
117
124
  buttonB.click();
118
125
  flushSync();
119
126
 
120
- expect(container.querySelector('div').textContent).toBe('Case B or C');
127
+ expect(container.querySelector('div')).toBeNull();
121
128
 
122
129
  buttonC.click();
123
130
  flushSync();
@@ -125,38 +132,47 @@ describe('switch statements', () => {
125
132
  expect(container.querySelector('div').textContent).toBe('Case B or C');
126
133
 
127
134
  container.querySelector('div').textContent = 'DOM check';
128
- buttonB.click();
135
+ buttonC.click();
129
136
  flushSync();
130
137
 
131
138
  expect(container.querySelector('div').textContent).toBe('DOM check');
132
139
  });
133
140
 
134
141
  it('renders switch with template content and reacts to tracked changes', () => {
135
- function App() {
136
- return <>
137
- let &[status] = track('active');
138
- let &[message] = track('');
142
+ function App() @{
143
+ let &[status] = track('active');
144
+ let &[message] = track('');
145
+ <>
139
146
  <button onClick={() => (status = 'pending')}>{'Pending'}</button>
140
147
  <button onClick={() => (status = 'completed')}>{'Completed'}</button>
141
148
  <button onClick={() => (status = 'error')}>{'Error'}</button>
142
- switch (status) {
143
- case 'active':
149
+ @switch (status) {
150
+ @case 'active': {
144
151
  message = 'Currently active.';
145
- <div>{'Status: ' + message}</div>
146
- break;
147
- case 'pending':
152
+ <div>
153
+ {'Status: ' + message}
154
+ </div>
155
+ }
156
+ @case 'pending': {
148
157
  message = 'Waiting for completion.';
149
- <div>{'Status: ' + message}</div>
150
- break;
151
- case 'completed':
158
+ <div>
159
+ {'Status: ' + message}
160
+ </div>
161
+ }
162
+ @case 'completed': {
152
163
  message = 'Task finished!';
153
- <div class="success">{'Status: ' + message}</div>
154
- break;
155
- default:
164
+ <div class="success">
165
+ {'Status: ' + message}
166
+ </div>
167
+ }
168
+ @default: {
156
169
  message = 'An error occurred.';
157
- <div class="error">{'Status: ' + message}</div>
170
+ <div class="error">
171
+ {'Status: ' + message}
172
+ </div>
173
+ }
158
174
  }
159
- </>;
175
+ </>
160
176
  }
161
177
 
162
178
  render(App);
@@ -182,50 +198,56 @@ describe('switch statements', () => {
182
198
  });
183
199
 
184
200
  it(
185
- 'renders switch with multiple non-empty fall-through cases and reacts to tracked changes without recreating DOM unnecessarily',
201
+ 'renders switch with isolated cases and reacts to tracked changes without recreating DOM unnecessarily',
186
202
  () => {
187
- function App() {
188
- return <>
189
- let &[status] = track(0);
203
+ function App() @{
204
+ let &[status] = track(0);
205
+ <>
190
206
  <div>
191
- switch (status) {
192
- case -1:
193
- case 0:
207
+ @switch (status) {
208
+ @case -1: {
209
+ }
210
+ @case 0: {
194
211
  <p>{' Idle'}</p>
195
- case 1:
212
+ }
213
+ @case 1: {
196
214
  <p>{' Loading'}</p>
197
- case 2:
215
+ }
216
+ @case 2: {
198
217
  <p>{' Success'}</p>
199
- break;
200
- default:
201
- <p>{' Unknown status'}</p>
202
- <p>{' Unknown 2'}</p>
203
- case 3:
204
- <p>{' Error'}</p>
205
- <p>{' Error 2'}</p>
206
- <p>{' Error 3'}</p>
207
- break;
218
+ }
219
+ @default: {
220
+ <>
221
+ <p>{' Unknown status'}</p>
222
+ <p>{' Unknown 2'}</p>
223
+ </>
224
+ }
225
+ @case 3: {
226
+ <>
227
+ <p>{' Error'}</p>
228
+ <p>{' Error 2'}</p>
229
+ <p>{' Error 3'}</p>
230
+ </>
231
+ }
208
232
  }
209
233
  </div>
210
234
  <button
211
235
  onClick={() => {
212
236
  status = (status + 1) % 5;
213
237
  }}
214
- >
215
- {'Next Status'}
216
- </button>
217
- </>;
238
+ >{'Next Status'}</button>
239
+ </>
218
240
  }
219
241
 
220
242
  render(App);
221
243
  const button = container.querySelector('button');
222
244
 
223
- expect(container.querySelector('div').textContent).toBe(' Idle Loading Success');
245
+ expect(container.querySelector('div').textContent).toBe(' Idle');
224
246
 
225
247
  button.click();
226
248
  flushSync();
227
249
 
228
- expect(container.querySelector('div').textContent).toBe(' Loading Success');
250
+ expect(container.querySelector('div').textContent).toBe(' Loading');
229
251
 
230
252
  button.click();
231
253
  flushSync();
@@ -240,152 +262,140 @@ describe('switch statements', () => {
240
262
  button.click();
241
263
  flushSync();
242
264
 
243
- expect(container.querySelector('div').textContent).toBe(
244
- ' Unknown status Unknown 2 Error Error 2 Error 3',
245
- );
265
+ expect(container.querySelector('div').textContent).toBe(' Unknown status Unknown 2');
246
266
 
247
267
  button.click();
248
268
  flushSync();
249
269
 
250
- expect(container.querySelector('div').textContent).toBe(' Idle Loading Success');
270
+ expect(container.querySelector('div').textContent).toBe(' Idle');
251
271
  },
252
272
  );
253
273
 
254
- it(
255
- 'renders a fall-through default in the middle of switch cases and reacts to changes without recreating DOM unnecessarily',
256
- () => {
257
- function App() {
258
- return <>
259
- let &[value] = track('x');
260
- <button onClick={() => (value = 'a')}>{'Set A'}</button>
261
- <button onClick={() => (value = 'b')}>{'Set B'}</button>
262
- <button onClick={() => (value = 'c')}>{'Set C'}</button>
263
- <button onClick={() => (value = 'x')}>{'Set X'}</button>
264
- <div>
265
- switch (value) {
266
- case 'a':
267
- <div>{' Case A'}</div>
268
- break;
269
- // NOTE: This should be the default in the middle of the cases
270
- // However, jsdom (and other node-based dom libs) has a bug
271
- // that breaks out of the switch even if the default doesn't have a break
272
- // The browser works correctly.
273
- // So, we're just using a defined case in the middle to simulate default.
274
- case 'x':
275
- <div>{' Default Case for ' + value}</div>
276
- case 'b':
277
- <div>{' Case B'}</div>
278
- break;
279
- case 'c':
280
- <div>{' Case C'}</div>
274
+ it('renders a middle switch case without falling through to later cases', () => {
275
+ function App() @{
276
+ let &[value] = track('x');
277
+ <>
278
+ <button onClick={() => (value = 'a')}>{'Set A'}</button>
279
+ <button onClick={() => (value = 'b')}>{'Set B'}</button>
280
+ <button onClick={() => (value = 'c')}>{'Set C'}</button>
281
+ <button onClick={() => (value = 'x')}>{'Set X'}</button>
282
+ <div>
283
+ @switch (value) {
284
+ @case 'a': {
285
+ <div>{' Case A'}</div>
281
286
  }
282
- </div>
283
- </>;
284
- }
287
+ @case 'x': {
288
+ <div>
289
+ {' Default Case for ' + value}
290
+ </div>
291
+ }
292
+ @case 'b': {
293
+ <div>{' Case B'}</div>
294
+ }
295
+ @case 'c': {
296
+ <div>{' Case C'}</div>
297
+ }
298
+ }
299
+ </div>
300
+ </>
301
+ }
285
302
 
286
- render(App);
287
- const [buttonA, buttonB, buttonC, buttonX] = container.querySelectorAll('button');
303
+ render(App);
304
+ const [buttonA, buttonB, buttonC, buttonX] = container.querySelectorAll('button');
288
305
 
289
- expect(container.querySelector('div').textContent).toBe(' Default Case for x Case B');
290
- expect(container.querySelector('div').querySelectorAll('div').length).toBe(2);
306
+ expect(container.querySelector('div').textContent).toBe(' Default Case for x');
307
+ expect(container.querySelector('div').querySelectorAll('div').length).toBe(1);
291
308
 
292
- buttonA.click();
293
- flushSync();
309
+ buttonA.click();
310
+ flushSync();
294
311
 
295
- expect(container.querySelector('div').textContent).toBe(' Case A');
296
- expect(container.querySelector('div').querySelectorAll('div').length).toBe(1);
312
+ expect(container.querySelector('div').textContent).toBe(' Case A');
313
+ expect(container.querySelector('div').querySelectorAll('div').length).toBe(1);
297
314
 
298
- buttonC.click();
299
- flushSync();
315
+ buttonC.click();
316
+ flushSync();
300
317
 
301
- expect(container.querySelector('div').textContent).toBe(' Case C');
302
- expect(container.querySelector('div').querySelectorAll('div').length).toBe(1);
318
+ expect(container.querySelector('div').textContent).toBe(' Case C');
319
+ expect(container.querySelector('div').querySelectorAll('div').length).toBe(1);
303
320
 
304
- buttonB.click();
305
- flushSync();
321
+ buttonB.click();
322
+ flushSync();
306
323
 
307
- const bDiv = container.querySelector('div').querySelectorAll('div')[0];
308
- expect(bDiv.textContent).toBe(' Case B');
309
- bDiv.id = 'b';
324
+ const bDiv = container.querySelector('div').querySelectorAll('div')[0];
325
+ expect(bDiv.textContent).toBe(' Case B');
326
+ bDiv.id = 'b';
310
327
 
311
- buttonX.click();
312
- flushSync();
328
+ buttonX.click();
329
+ flushSync();
313
330
 
314
- // order should be correct with the previously rendered B element
315
- expect(container.querySelector('div').textContent).toBe(' Default Case for x Case B');
316
- expect(container.querySelector('div').querySelectorAll('div').length).toBe(2);
317
- // the previously rendered div should be preserved
318
- expect(container.querySelector('div').querySelectorAll('div')[1].id).toBe('b');
319
- },
320
- );
331
+ expect(container.querySelector('div').textContent).toBe(' Default Case for x');
332
+ expect(container.querySelector('div').querySelectorAll('div').length).toBe(1);
333
+ expect(container.querySelector('#b')).toBeNull();
334
+ });
321
335
 
322
- it('renders bare text nodes in switch fall-through cases without element wrappers', () => {
323
- function App() {
324
- return <>
325
- let value = 'a';
326
- <div>
327
- <span>{'before'}</span>
328
- switch (value) {
329
- case 'a':
330
- {'Case A'}
331
- case 'b':
332
- {'Case B'}
336
+ it('renders bare text nodes in switch cases without falling through', () => {
337
+ function App() @{
338
+ let value = 'a';
339
+ <div>
340
+ <span>{'before'}</span>
341
+ @switch (value) {
342
+ @case 'a': {
343
+ <>Case A</>
333
344
  }
334
- </div>
335
- </>;
345
+ @case 'b': {
346
+ <>Case B</>
347
+ }
348
+ }
349
+ </div>
336
350
  }
337
351
 
338
352
  render(App);
339
- expect(container.querySelector('div').textContent).toBe('beforeCase ACase B');
353
+ expect(container.querySelector('div').textContent).toBe('beforeCase A');
340
354
  });
341
355
 
342
356
  it('renders bare text nodes in switch cases without element wrappers', () => {
343
- function App() {
344
- return <>
345
- let value = 'a';
346
- <div>
347
- <span>{'before'}</span>
348
- switch (value) {
349
- case 'a':
350
- {'Case A'}
351
- break;
352
- case 'b':
353
- {'Case B'}
354
- break;
357
+ function App() @{
358
+ let value = 'a';
359
+ <div>
360
+ <span>{'before'}</span>
361
+ @switch (value) {
362
+ @case 'a': {
363
+ <>Case A</>
355
364
  }
356
- </div>
357
- </>;
365
+ @case 'b': {
366
+ <>Case B</>
367
+ }
368
+ }
369
+ </div>
358
370
  }
359
371
 
360
372
  render(App);
361
373
  expect(container.querySelector('div').textContent).toBe('beforeCase A');
362
374
  });
363
375
 
364
- it('renders switch with block-scoped cases and break inside blocks', () => {
365
- function App() {
366
- return <>
367
- let &[level] = track(1);
376
+ it('renders switch with isolated block-scoped cases', () => {
377
+ function App() @{
378
+ let &[level] = track(1);
379
+ <>
368
380
  <button
369
381
  onClick={() => {
370
382
  if (level === 1) level = 2;
371
383
  else if (level === 2) level = 3;
372
384
  else level = 1;
373
385
  }}
374
- >
375
- {'Toggle'}
376
- </button>
377
- switch (level) {
378
- case 1:
386
+ >{'Toggle'}</button>
387
+ @switch (level) {
388
+ @case 1: {
379
389
  <div class="level">{'Level 1'}</div>
380
- break;
381
- case 2:
390
+ }
391
+ @case 2: {
382
392
  <div class="level">{'Level 2'}</div>
383
- break;
384
- case 3:
393
+ }
394
+ @case 3: {
385
395
  <div class="level">{'Level 3'}</div>
386
- break;
396
+ }
387
397
  }
388
- </>;
398
+ </>
389
399
  }
390
400
 
391
401
  render(App);
@@ -5,15 +5,13 @@ describe('trackAsync hydration from serialized data (client)', () => {
5
5
  // This test verifies the client runtime can parse the serialized script tags
6
6
  // The full hydration round-trip is tested in hydration tests
7
7
 
8
- function App() {
9
- return <>
10
- try {
11
- let &[data] = trackAsync(() => Promise.resolve('fallback'));
12
- <p class="result">{data}</p>
13
- } pending {
14
- <p class="loading">{'loading...'}</p>
15
- }
16
- </>;
8
+ function App() @{
9
+ @try {
10
+ let &[data] = trackAsync(() => Promise.resolve('fallback'));
11
+ <p class="result">{data}</p>
12
+ } @pending {
13
+ <p class="loading">{'loading...'}</p>
14
+ }
17
15
  }
18
16
 
19
17
  render(App);
@@ -31,15 +29,13 @@ describe('trackAsync hydration from serialized data (client)', () => {
31
29
  let resolve_fn: (value: number) => void;
32
30
  const promise = new Promise<number>((r) => (resolve_fn = r));
33
31
 
34
- function App() {
35
- return <>
36
- try {
37
- let &[value] = trackAsync(() => promise);
38
- <span class="value">{value}</span>
39
- } pending {
40
- <span class="pending">{'waiting'}</span>
41
- }
42
- </>;
32
+ function App() @{
33
+ @try {
34
+ let &[value] = trackAsync(() => promise);
35
+ <span class="value">{value}</span>
36
+ } @pending {
37
+ <span class="pending">{'waiting'}</span>
38
+ }
43
39
  }
44
40
 
45
41
  render(App);
@@ -15,11 +15,9 @@ describe('client tracked numeric access', () => {
15
15
  it('throws when tracked values are accessed through numeric properties', () => {
16
16
  let value: any;
17
17
 
18
- function Test() {
19
- return <>
20
- value = track(0);
21
- <div />
22
- </>;
18
+ function Test() @{
19
+ value = track(0);
20
+ <div />
23
21
  }
24
22
 
25
23
  render(Test);
@@ -34,11 +32,9 @@ describe('client tracked numeric access', () => {
34
32
  it('throws when derived values are accessed through numeric properties', () => {
35
33
  let value: any;
36
34
 
37
- function Test() {
38
- return <>
39
- value = track(() => 1);
40
- <div />
41
- </>;
35
+ function Test() @{
36
+ value = track(() => 1);
37
+ <div />
42
38
  }
43
39
 
44
40
  render(Test);
@@ -54,12 +50,10 @@ describe('client tracked numeric access', () => {
54
50
  let value: any;
55
51
  let next: any;
56
52
 
57
- function Test() {
58
- return <>
59
- value = track(0);
60
- next = track(1);
61
- <div />
62
- </>;
53
+ function Test() @{
54
+ value = track(0);
55
+ next = track(1);
56
+ <div />
63
57
  }
64
58
 
65
59
  render(Test);
@@ -78,12 +72,10 @@ describe('client tracked numeric access', () => {
78
72
  let value: any;
79
73
  let derived: any;
80
74
 
81
- function Test() {
82
- return <>
83
- value = track(0);
84
- derived = track(() => value.value + 1);
85
- <div />
86
- </>;
75
+ function Test() @{
76
+ value = track(0);
77
+ derived = track(() => value.value + 1);
78
+ <div />
87
79
  }
88
80
 
89
81
  render(Test);
@@ -100,12 +92,10 @@ describe('client tracked numeric access', () => {
100
92
  let value: any;
101
93
  let derived: any;
102
94
 
103
- function Test() {
104
- return <>
105
- value = track(0);
106
- derived = track(() => value.value + 1);
107
- <div />
108
- </>;
95
+ function Test() @{
96
+ value = track(0);
97
+ derived = track(() => value.value + 1);
98
+ <div />
109
99
  }
110
100
 
111
101
  render(Test);