ripple 0.3.128 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +267 -0
  2. package/package.json +10 -4
  3. package/src/runtime/element.js +23 -6
  4. package/src/runtime/index-client.js +81 -41
  5. package/src/runtime/index-server.js +1 -0
  6. package/src/runtime/internal/client/blocks.js +173 -91
  7. package/src/runtime/internal/client/component.js +4 -30
  8. package/src/runtime/internal/client/composite.js +12 -13
  9. package/src/runtime/internal/client/constants.js +9 -0
  10. package/src/runtime/internal/client/context.js +12 -19
  11. package/src/runtime/internal/client/css.js +7 -9
  12. package/src/runtime/internal/client/events.js +178 -90
  13. package/src/runtime/internal/client/expression.js +45 -25
  14. package/src/runtime/internal/client/for.js +409 -129
  15. package/src/runtime/internal/client/head.js +10 -5
  16. package/src/runtime/internal/client/html.js +1 -0
  17. package/src/runtime/internal/client/hydration.js +152 -10
  18. package/src/runtime/internal/client/if.js +239 -50
  19. package/src/runtime/internal/client/index.js +4 -12
  20. package/src/runtime/internal/client/operations.js +40 -61
  21. package/src/runtime/internal/client/portal.js +163 -85
  22. package/src/runtime/internal/client/render.js +39 -39
  23. package/src/runtime/internal/client/rpc.js +3 -3
  24. package/src/runtime/internal/client/runtime.js +592 -433
  25. package/src/runtime/internal/client/selector.js +5 -2
  26. package/src/runtime/internal/client/template.js +133 -158
  27. package/src/runtime/internal/client/transport.js +38 -0
  28. package/src/runtime/internal/client/try.js +465 -426
  29. package/src/runtime/internal/client/types.d.ts +56 -23
  30. package/src/runtime/internal/client/utils.js +1 -3
  31. package/src/runtime/internal/server/dynamic.js +20 -21
  32. package/src/runtime/internal/server/index.js +325 -275
  33. package/src/runtime/internal/server/rpc.js +3 -2
  34. package/src/runtime/internal/server/transport.js +16 -0
  35. package/src/runtime/transport.js +21 -0
  36. package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
  37. package/tests/client/array/array.copy-within.test.tsrx +12 -12
  38. package/tests/client/array/array.derived.test.tsrx +46 -46
  39. package/tests/client/array/array.iteration.test.tsrx +10 -10
  40. package/tests/client/array/array.mutations.test.tsrx +20 -20
  41. package/tests/client/array/array.static.test.tsrx +11 -11
  42. package/tests/client/array/array.to-methods.test.tsrx +6 -6
  43. package/tests/client/async-suspend.test.tsrx +74 -75
  44. package/tests/client/basic/basic.attributes.test.tsrx +86 -83
  45. package/tests/client/basic/basic.collections.test.tsrx +12 -12
  46. package/tests/client/basic/basic.components.test.tsrx +99 -25
  47. package/tests/client/basic/basic.errors.test.tsrx +18 -18
  48. package/tests/client/basic/basic.events.test.tsrx +42 -42
  49. package/tests/client/basic/basic.get-set.test.tsrx +8 -8
  50. package/tests/client/basic/basic.reactivity.test.tsrx +73 -38
  51. package/tests/client/basic/basic.rendering.test.tsrx +25 -25
  52. package/tests/client/basic/basic.utilities.test.tsrx +3 -3
  53. package/tests/client/boundaries.test.tsrx +8 -8
  54. package/tests/client/boxed-locals.test.tsrx +452 -0
  55. package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
  56. package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
  57. package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
  58. package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
  59. package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
  60. package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
  61. package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
  62. package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
  63. package/tests/client/composite/composite.props.test.tsrx +149 -12
  64. package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
  65. package/tests/client/composite/composite.render.test.tsrx +26 -9
  66. package/tests/client/css/scoped-styles.test.tsrx +8 -8
  67. package/tests/client/date.test.tsrx +42 -42
  68. package/tests/client/derived-release.test.tsrx +370 -0
  69. package/tests/client/dynamic-elements.test.tsrx +45 -45
  70. package/tests/client/events.test.tsrx +97 -71
  71. package/tests/client/for-selector.test.tsrx +14 -14
  72. package/tests/client/for-single-root-items.test.tsrx +118 -3
  73. package/tests/client/for.test.tsrx +332 -31
  74. package/tests/client/head.test.tsrx +19 -19
  75. package/tests/client/html.test.tsrx +11 -9
  76. package/tests/client/if-block.test.tsrx +80 -0
  77. package/tests/client/map.test.tsrx +16 -16
  78. package/tests/client/media-query.test.tsrx +7 -7
  79. package/tests/client/portal.test.tsrx +224 -26
  80. package/tests/client/primitive-text.test.tsrx +50 -0
  81. package/tests/client/prop-kind-switch.test.tsrx +141 -0
  82. package/tests/client/ref.test.tsrx +17 -17
  83. package/tests/client/return.test.tsrx +26 -3
  84. package/tests/client/root-boundary.test.tsrx +42 -0
  85. package/tests/client/scoped-flush.test.tsrx +8 -8
  86. package/tests/client/set.test.tsrx +6 -6
  87. package/tests/client/svg.test.tsrx +11 -11
  88. package/tests/client/switch.test.tsrx +44 -44
  89. package/tests/client/track-async-hydration.test.tsrx +4 -4
  90. package/tests/client/try.test.tsrx +151 -83
  91. package/tests/client/tsx.test.tsrx +43 -40
  92. package/tests/client/url/url.derived.test.tsrx +6 -6
  93. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
  94. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
  95. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
  96. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
  97. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
  98. package/tests/hydration/basic.test.js +74 -1
  99. package/tests/hydration/build-components.js +22 -1
  100. package/tests/hydration/compiled/client/basic.js +1142 -713
  101. package/tests/hydration/compiled/client/composite.js +151 -100
  102. package/tests/hydration/compiled/client/events.js +184 -171
  103. package/tests/hydration/compiled/client/for.js +1472 -1132
  104. package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
  105. package/tests/hydration/compiled/client/head.js +254 -201
  106. package/tests/hydration/compiled/client/hmr.js +54 -41
  107. package/tests/hydration/compiled/client/html-in-template.js +54 -39
  108. package/tests/hydration/compiled/client/html.js +1633 -1263
  109. package/tests/hydration/compiled/client/if-children.js +420 -270
  110. package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
  111. package/tests/hydration/compiled/client/if.js +229 -219
  112. package/tests/hydration/compiled/client/mixed-control-flow.js +420 -404
  113. package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1277
  114. package/tests/hydration/compiled/client/portal.js +87 -95
  115. package/tests/hydration/compiled/client/reactivity.js +135 -101
  116. package/tests/hydration/compiled/client/return.js +28 -19
  117. package/tests/hydration/compiled/client/streaming.js +390 -306
  118. package/tests/hydration/compiled/client/switch.js +258 -266
  119. package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
  120. package/tests/hydration/compiled/client/try.js +173 -129
  121. package/tests/hydration/compiled/client/typed-text.js +71 -0
  122. package/tests/hydration/compiled/fixtures/money.js +10 -0
  123. package/tests/hydration/compiled/server/basic.js +123 -6
  124. package/tests/hydration/compiled/server/composite.js +16 -30
  125. package/tests/hydration/compiled/server/events.js +66 -18
  126. package/tests/hydration/compiled/server/for.js +117 -41
  127. package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
  128. package/tests/hydration/compiled/server/head.js +20 -20
  129. package/tests/hydration/compiled/server/hmr.js +2 -2
  130. package/tests/hydration/compiled/server/html.js +70 -238
  131. package/tests/hydration/compiled/server/if-children.js +107 -15
  132. package/tests/hydration/compiled/server/if.js +11 -15
  133. package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
  134. package/tests/hydration/compiled/server/portal.js +14 -22
  135. package/tests/hydration/compiled/server/reactivity.js +14 -14
  136. package/tests/hydration/compiled/server/streaming.js +19 -19
  137. package/tests/hydration/compiled/server/switch.js +8 -8
  138. package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
  139. package/tests/hydration/compiled/server/try.js +8 -8
  140. package/tests/hydration/compiled/server/typed-text.js +17 -0
  141. package/tests/hydration/components/basic.tsrx +44 -8
  142. package/tests/hydration/components/composite.tsrx +2 -2
  143. package/tests/hydration/components/events.tsrx +25 -25
  144. package/tests/hydration/components/for.tsrx +115 -67
  145. package/tests/hydration/components/fragment-cursor.tsrx +650 -0
  146. package/tests/hydration/components/head.tsrx +16 -16
  147. package/tests/hydration/components/hmr.tsrx +2 -2
  148. package/tests/hydration/components/html.tsrx +7 -7
  149. package/tests/hydration/components/if-children.tsrx +72 -25
  150. package/tests/hydration/components/if.tsrx +18 -18
  151. package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
  152. package/tests/hydration/components/portal.tsrx +3 -3
  153. package/tests/hydration/components/reactivity.tsrx +16 -16
  154. package/tests/hydration/components/streaming.tsrx +20 -20
  155. package/tests/hydration/components/switch.tsrx +20 -20
  156. package/tests/hydration/components/text-types.ts +4 -0
  157. package/tests/hydration/components/track-async-serialization.tsrx +80 -26
  158. package/tests/hydration/components/try.tsrx +8 -8
  159. package/tests/hydration/components/typed-text.tsrx +22 -0
  160. package/tests/hydration/fixtures/money.js +10 -0
  161. package/tests/hydration/for.test.js +36 -0
  162. package/tests/hydration/fragment-cursor.test.js +111 -0
  163. package/tests/hydration/if-children.test.js +24 -0
  164. package/tests/hydration/streaming.test.js +19 -0
  165. package/tests/hydration/track-async-serialization.test.js +87 -2
  166. package/tests/hydration/tsconfig.text-types.json +10 -0
  167. package/tests/hydration/typed-text.test.js +34 -0
  168. package/tests/server/await.test.tsrx +3 -3
  169. package/tests/server/basic.attributes.test.tsrx +42 -42
  170. package/tests/server/basic.components.test.tsrx +64 -8
  171. package/tests/server/basic.test.tsrx +34 -32
  172. package/tests/server/compiler.test.tsrx +1 -70
  173. package/tests/server/composite.props.test.tsrx +6 -6
  174. package/tests/server/dynamic-elements.test.tsrx +31 -8
  175. package/tests/server/for.test.tsrx +94 -0
  176. package/tests/server/head.test.tsrx +11 -11
  177. package/tests/server/scoped-styles.test.tsrx +2 -2
  178. package/tests/server/streaming-ssr.test.tsrx +48 -43
  179. package/tests/server/track-async-serialization.test.tsrx +204 -21
  180. package/tests/server/try.test.tsrx +48 -48
  181. package/tests/types/transport.ts +40 -0
  182. package/tests/utils/vite-plugin-config.test.js +23 -0
  183. package/types/index.d.ts +48 -7
  184. package/types/server.d.ts +3 -0
  185. package/types/transport.d.ts +15 -0
  186. package/src/runtime/internal/client/switch.js +0 -113
  187. package/src/utils/errors.js +0 -13
  188. package/tests/client/lazy-array.test.tsrx +0 -31
  189. package/tests/client/lazy-destructuring.test.tsrx +0 -438
  190. package/tests/client/tracked-index-access.test.tsrx +0 -113
  191. package/tests/server/lazy-destructuring.test.tsrx +0 -595
  192. package/tests/server/tracked-index-access.test.tsrx +0 -76
@@ -12,6 +12,74 @@ import {
12
12
  } from 'ripple';
13
13
 
14
14
  describe('try block with catch and pending', () => {
15
+ it('keeps sibling boundary requests and catch resets independent', async () => {
16
+ const requests: {
17
+ resolve: (value: string) => void;
18
+ reject: (error: Error) => void;
19
+ }[] = [];
20
+
21
+ function load() {
22
+ return new Promise<string>((resolve, reject) => {
23
+ requests.push({ resolve, reject });
24
+ });
25
+ }
26
+
27
+ function Boundary() @{
28
+ @try {
29
+ const value = trackAsync(load);
30
+ <p class="resolved">{value.value}</p>
31
+ } @pending {
32
+ <p class="pending">{'loading'}</p>
33
+ } @catch (error, reset) {
34
+ <button class="retry" onClick={reset}>{(error as Error).message}</button>
35
+ }
36
+ }
37
+
38
+ function App() @{
39
+ <>
40
+ <section class="first">
41
+ <Boundary />
42
+ </section>
43
+ <section class="second">
44
+ <Boundary />
45
+ </section>
46
+ </>
47
+ }
48
+
49
+ async function settle() {
50
+ await new Promise((resolve) => setTimeout(resolve, 0));
51
+ flushSync();
52
+ }
53
+
54
+ render(App);
55
+ await settle();
56
+ expect(container.querySelectorAll('.pending')).toHaveLength(2);
57
+
58
+ requests[1].resolve('second result');
59
+ await settle();
60
+ const second = container.querySelector('.second .resolved');
61
+ expect(second?.textContent).toBe('second result');
62
+ expect(container.querySelector('.first .pending')).not.toBeNull();
63
+
64
+ requests[0].reject(new Error('first failed'));
65
+ await settle();
66
+ expect(container.querySelector('.first .retry')?.textContent).toBe('first failed');
67
+ expect(container.querySelector('.second .resolved')).toBe(second);
68
+
69
+ (container.querySelector('.first .retry') as HTMLButtonElement).click();
70
+ await settle();
71
+ expect(requests).toHaveLength(3);
72
+ expect(container.querySelector('.first .pending')).not.toBeNull();
73
+ expect(container.querySelector('.first .retry')).toBeNull();
74
+ expect(container.querySelector('.second .resolved')).toBe(second);
75
+
76
+ requests[2].resolve('first recovered');
77
+ await settle();
78
+ expect(container.querySelector('.first .resolved')?.textContent).toBe('first recovered');
79
+ expect(container.querySelector('.second .resolved')).toBe(second);
80
+ expect(container.querySelectorAll('.pending, .retry')).toHaveLength(0);
81
+ });
82
+
15
83
  it('renders nothing for an empty pending fallback before resolving', async () => {
16
84
  let resolve_value: (value: string) => void = () => {};
17
85
  const promise = new Promise<string>((resolve) => {
@@ -22,8 +90,8 @@ describe('try block with catch and pending', () => {
22
90
  <>
23
91
  <span class="before">{'before'}</span>
24
92
  @try {
25
- let &[data] = trackAsync(() => promise);
26
- <p class="resolved">{data}</p>
93
+ const data = trackAsync(() => promise);
94
+ <p class="resolved">{data.value}</p>
27
95
  } @pending {
28
96
  }
29
97
  <span class="after">{'after'}</span>
@@ -84,9 +152,9 @@ describe('try block with catch and pending', () => {
84
152
  }
85
153
 
86
154
  function ThrowingAfterAsync() @{
87
- let &[data] = trackAsync(() => Promise.resolve('hello'));
155
+ const data = trackAsync(() => Promise.resolve('hello'));
88
156
  throw new Error('error after await');
89
- <p>{data}</p>
157
+ <p>{data.value}</p>
90
158
  }
91
159
 
92
160
  render(App);
@@ -101,8 +169,8 @@ describe('try block with catch and pending', () => {
101
169
  it('catch block works when trackAsync rejects', async () => {
102
170
  function App() @{
103
171
  @try {
104
- let &[data] = trackAsync(() => Promise.reject(new Error('rejected')));
105
- <p>{data}</p>
172
+ const data = trackAsync(() => Promise.reject(new Error('rejected')));
173
+ <p>{data.value}</p>
106
174
  } @pending {
107
175
  <p>{'loading...'}</p>
108
176
  } @catch (err) {
@@ -139,17 +207,17 @@ describe('try block with catch and pending', () => {
139
207
  }
140
208
 
141
209
  function App() @{
142
- let &[version] = track(0);
210
+ const version = track(0);
143
211
  <>
144
212
  @try {
145
- let &[data] = trackAsync(() => createRequest(version));
146
- <p class="resolved">{data}</p>
213
+ const data = trackAsync(() => createRequest(version.value));
214
+ <p class="resolved">{data.value}</p>
147
215
  } @pending {
148
216
  <p class="pending">{'loading...'}</p>
149
217
  } @catch (err) {
150
218
  <p class="caught">{(err as Error).message}</p>
151
219
  }
152
- <button class="retry" onClick={() => version++}>{'Retry'}</button>
220
+ <button class="retry" onClick={() => version.value++}>{'Retry'}</button>
153
221
  </>
154
222
  }
155
223
 
@@ -203,13 +271,13 @@ describe('try block with catch and pending', () => {
203
271
  }
204
272
 
205
273
  function App() @{
206
- let &[version] = track(0);
274
+ const version = track(0);
207
275
  @try {
208
- let &[data] = trackAsync(() => {
209
- version;
210
- return createRequest(version);
276
+ const data = trackAsync(() => {
277
+ version.value;
278
+ return createRequest(version.value);
211
279
  });
212
- <p class="resolved">{data}</p>
280
+ <p class="resolved">{data.value}</p>
213
281
  } @pending {
214
282
  <p class="pending">{'loading...'}</p>
215
283
  } @catch (err, reset) {
@@ -218,7 +286,7 @@ describe('try block with catch and pending', () => {
218
286
  <button
219
287
  class="retry"
220
288
  onClick={() => {
221
- version++;
289
+ version.value++;
222
290
  reset();
223
291
  }}
224
292
  >{'Retry'}</button>
@@ -264,12 +332,12 @@ describe('try block', () => {
264
332
  'does not compile ref binds as async callbacks inside try/pending trackAsync branches',
265
333
  async () => {
266
334
  function App() @{
267
- let &[value, valueTracked] = track(1);
335
+ const value = track(1);
268
336
  @try {
269
- let &[loaded] = trackAsync(() => Promise.resolve(value + 1));
337
+ const loaded = trackAsync(() => Promise.resolve(value.value + 1));
270
338
  <>
271
- <input type="number" ref={bindValue(valueTracked)} />
272
- <span>{loaded}</span>
339
+ <input type="number" ref={bindValue(value)} />
340
+ <span>{loaded.value}</span>
273
341
  </>
274
342
  } @pending {
275
343
  <p>{'loading...'}</p>
@@ -298,9 +366,9 @@ describe('try block', () => {
298
366
  }
299
367
 
300
368
  function AsyncChild() @{
301
- let &[data] = trackAsync(() => Promise.resolve(['a', 'b', 'c']));
369
+ const data = trackAsync(() => Promise.resolve(['a', 'b', 'c']));
302
370
  <ul>
303
- @for (let item of data) {
371
+ @for (let item of data.value) {
304
372
  <li>{item}</li>
305
373
  }
306
374
  </ul>
@@ -321,21 +389,21 @@ describe('try block', () => {
321
389
  'does not crash when async component with tracked state is used inside try/pending',
322
390
  async () => {
323
391
  function App() @{
324
- let &[query, queryTracked] = track('');
392
+ const query = track('');
325
393
  @try {
326
- <FilteredList {queryTracked} />
394
+ <FilteredList {query} />
327
395
  } @pending {
328
396
  <p>{'loading...'}</p>
329
397
  }
330
398
  }
331
399
 
332
- function FilteredList({ queryTracked }: { queryTracked: Tracked<string> }) @{
333
- let &[items] = trackAsync(() => Promise.resolve(['apple', 'banana', 'cherry']));
334
- let &[filtered] = track(
335
- () => items.filter((item: string) => item.includes(queryTracked.value)),
400
+ function FilteredList({ query }: { query: Tracked<string> }) @{
401
+ const items = trackAsync(() => Promise.resolve(['apple', 'banana', 'cherry']));
402
+ const filtered = track(
403
+ () => items.value.filter((item: string) => item.includes(query.value)),
336
404
  );
337
405
  <ul>
338
- @for (let item of filtered) {
406
+ @for (let item of filtered.value) {
339
407
  <li>{item}</li>
340
408
  }
341
409
  </ul>
@@ -354,9 +422,9 @@ describe('try block', () => {
354
422
  it('if test condition stays synchronous once trackAsync has resolved', async () => {
355
423
  function App() @{
356
424
  @try {
357
- let &[items] = trackAsync(() => Promise.resolve(['apple', 'banana', 'cherry']));
425
+ const items = trackAsync(() => Promise.resolve(['apple', 'banana', 'cherry']));
358
426
 
359
- @if (items.includes('not-in-list')) {
427
+ @if (items.value.includes('not-in-list')) {
360
428
  <p>{'not-in-list is in the list!'}</p>
361
429
  } @else {
362
430
  <p>{'not-in-list is not in the list.'}</p>
@@ -387,17 +455,17 @@ describe('try block', () => {
387
455
  }
388
456
 
389
457
  function App() @{
390
- let &[show] = track(true);
458
+ const show = track(true);
391
459
  <>
392
- @if (show) {
460
+ @if (show.value) {
393
461
  @try {
394
- let &[data] = trackAsync(() => new Promise(() => {}));
395
- <p class="resolved">{data}</p>
462
+ const data = trackAsync(() => new Promise(() => {}));
463
+ <p class="resolved">{data.value}</p>
396
464
  } @pending {
397
465
  <PendingChild />
398
466
  }
399
467
  }
400
- <button class="toggle" onClick={() => (show = !show)}>{'toggle'}</button>
468
+ <button class="toggle" onClick={() => (show.value = !show.value)}>{'toggle'}</button>
401
469
  </>
402
470
  }
403
471
 
@@ -423,21 +491,21 @@ describe('try block', () => {
423
491
  it('destroying try block while in resolved state cleans up resolved branch', async () => {
424
492
  let resolved_effect_teardown_count = 0;
425
493
 
426
- function ResolvedChild(&{ data }: { data: string }) @{
494
+ function ResolvedChild({ data }: { data: Tracked<string> }) @{
427
495
  effect(() => {
428
496
  return () => {
429
497
  resolved_effect_teardown_count++;
430
498
  };
431
499
  });
432
- <p class="resolved">{data}</p>
500
+ <p class="resolved">{data.value}</p>
433
501
  }
434
502
 
435
503
  function App() @{
436
- let &[show] = track(true);
504
+ const show = track(true);
437
505
  <>
438
- @if (show) {
506
+ @if (show.value) {
439
507
  @try {
440
- let &[data] = trackAsync(() => Promise.resolve('hello'));
508
+ const data = trackAsync(() => Promise.resolve('hello'));
441
509
  <ResolvedChild {data} />
442
510
  } @pending {
443
511
  <p class="pending">{'loading...'}</p>
@@ -445,7 +513,7 @@ describe('try block', () => {
445
513
  <p class="caught">{(err as Error).message}</p>
446
514
  }
447
515
  }
448
- <button class="toggle" onClick={() => (show = !show)}>{'toggle'}</button>
516
+ <button class="toggle" onClick={() => (show.value = !show.value)}>{'toggle'}</button>
449
517
  </>
450
518
  }
451
519
 
@@ -482,19 +550,19 @@ describe('try block', () => {
482
550
  }
483
551
 
484
552
  function App() @{
485
- let &[show] = track(true);
553
+ const show = track(true);
486
554
  <>
487
- @if (show) {
555
+ @if (show.value) {
488
556
  @try {
489
- let &[data] = trackAsync(() => Promise.reject(new Error('fail')));
490
- <p class="resolved">{data}</p>
557
+ const data = trackAsync(() => Promise.reject(new Error('fail')));
558
+ <p class="resolved">{data.value}</p>
491
559
  } @pending {
492
560
  <p class="pending">{'loading...'}</p>
493
561
  } @catch (err) {
494
562
  <CatchChild error={err as Error} />
495
563
  }
496
564
  }
497
- <button class="toggle" onClick={() => (show = !show)}>{'toggle'}</button>
565
+ <button class="toggle" onClick={() => (show.value = !show.value)}>{'toggle'}</button>
498
566
  </>
499
567
  }
500
568
 
@@ -522,8 +590,8 @@ describe('try block', () => {
522
590
 
523
591
  function App() @{
524
592
  @try {
525
- let &[data] = trackAsync(() => new Promise(() => {}));
526
- <p class="resolved">{data}</p>
593
+ const data = trackAsync(() => new Promise(() => {}));
594
+ <p class="resolved">{data.value}</p>
527
595
  } @pending {
528
596
  <ThrowingPending />
529
597
  } @catch (err) {
@@ -558,8 +626,8 @@ describe('try block', () => {
558
626
 
559
627
  function Inner() @{
560
628
  @try {
561
- let &[data] = trackAsync(() => new Promise(() => {}));
562
- <p class="resolved">{data}</p>
629
+ const data = trackAsync(() => new Promise(() => {}));
630
+ <p class="resolved">{data.value}</p>
563
631
  } @pending {
564
632
  <ThrowingPending />
565
633
  }
@@ -586,19 +654,19 @@ describe('try block', () => {
586
654
 
587
655
  function App() @{
588
656
  @try {
589
- let &[name] = trackAsync(() => first_promise);
590
- let &[length] = trackAsync(() => {
657
+ const name = trackAsync(() => first_promise);
658
+ const length = trackAsync(() => {
591
659
  // Read name synchronously — throws ASYNC_DERIVED_READ_THROWN
592
660
  // while name is still pending, triggering the deferred mechanism.
593
- const n = name;
661
+ const n = name.value;
594
662
  return new Promise<number>((resolve) => {
595
663
  second_resolve = resolve;
596
664
  }).then((val) => n.length + val);
597
665
  });
598
666
  <p class="resolved">
599
- {name}
667
+ {name.value}
600
668
  {' has length '}
601
- {length}
669
+ {length.value}
602
670
  </p>
603
671
  } @pending {
604
672
  <p class="pending">{'loading...'}</p>
@@ -652,17 +720,17 @@ describe('try block', () => {
652
720
 
653
721
  function App() @{
654
722
  @try {
655
- let &[name] = trackAsync(() => first_promise);
656
- let &[length] = trackAsync(() => {
657
- const n = name;
723
+ const name = trackAsync(() => first_promise);
724
+ const length = trackAsync(() => {
725
+ const n = name.value;
658
726
  return new Promise<number>((resolve) => {
659
727
  second_resolve = resolve;
660
728
  }).then((val) => n.length + val);
661
729
  });
662
730
  <p class="resolved">
663
- {name}
731
+ {name.value}
664
732
  {' has length '}
665
- {length}
733
+ {length.value}
666
734
  </p>
667
735
  } @pending {
668
736
  <PendingTracker />
@@ -710,17 +778,17 @@ describe('try block', () => {
710
778
 
711
779
  function App() @{
712
780
  @try {
713
- let &[name] = trackAsync(() => first_promise);
714
- let &[length] = trackAsync(() => {
715
- const n = name;
781
+ const name = trackAsync(() => first_promise);
782
+ const length = trackAsync(() => {
783
+ const n = name.value;
716
784
  return new Promise<number>((resolve) => {
717
785
  second_resolve = resolve;
718
786
  }).then((val) => n.length + val);
719
787
  });
720
788
  <p class="resolved">
721
- {name}
789
+ {name.value}
722
790
  {' has length '}
723
- {length}
791
+ {length.value}
724
792
  </p>
725
793
  } @pending {
726
794
  <p class="pending">{'loading...'}</p>
@@ -765,17 +833,17 @@ describe('try block', () => {
765
833
 
766
834
  function App() @{
767
835
  @try {
768
- let &[name] = trackAsync(() => first_promise);
769
- let &[length] = trackAsync(() => {
770
- const n = name;
836
+ const name = trackAsync(() => first_promise);
837
+ const length = trackAsync(() => {
838
+ const n = name.value;
771
839
  return new Promise<number>((_, reject) => {
772
840
  second_reject = reject;
773
841
  });
774
842
  });
775
843
  <p class="resolved">
776
- {name}
844
+ {name.value}
777
845
  {' has length '}
778
- {length}
846
+ {length.value}
779
847
  </p>
780
848
  } @pending {
781
849
  <p class="pending">{'loading...'}</p>
@@ -816,8 +884,8 @@ describe('try block', () => {
816
884
 
817
885
  it('resolved try block without catch bubbles error to parent try/catch', async () => {
818
886
  function ThrowingChild() @{
819
- let &[data] = trackAsync(() => Promise.reject(new Error('async failed')));
820
- <p class="resolved">{data}</p>
887
+ const data = trackAsync(() => Promise.reject(new Error('async failed')));
888
+ <p class="resolved">{data.value}</p>
821
889
  }
822
890
 
823
891
  function App() @{
@@ -1469,8 +1537,8 @@ describe('sync error while async deriveds are pending', () => {
1469
1537
 
1470
1538
  function Inner() @{
1471
1539
  @try {
1472
- let &[data] = trackAsync(() => Promise.reject(new Error('async no catch')));
1473
- <p class="resolved">{data}</p>
1540
+ const data = trackAsync(() => Promise.reject(new Error('async no catch')));
1541
+ <p class="resolved">{data.value}</p>
1474
1542
  } @pending {
1475
1543
  <p class="inner-pending">{'loading...'}</p>
1476
1544
  }
@@ -1502,8 +1570,8 @@ describe('sync error while async deriveds are pending', () => {
1502
1570
 
1503
1571
  function Inner() @{
1504
1572
  @try {
1505
- let &[data] = trackAsync(() => user_promise);
1506
- <p class="resolved">{data}</p>
1573
+ const data = trackAsync(() => user_promise);
1574
+ <p class="resolved">{data.value}</p>
1507
1575
  } @pending {
1508
1576
  <p class="inner-pending">{'loading...'}</p>
1509
1577
  }
@@ -1590,8 +1658,8 @@ describe('sync error while async deriveds are pending', () => {
1590
1658
 
1591
1659
  function Inner() @{
1592
1660
  @try {
1593
- let &[data] = trackAsync(() => user_promise);
1594
- <p class="resolved">{data}</p>
1661
+ const data = trackAsync(() => user_promise);
1662
+ <p class="resolved">{data.value}</p>
1595
1663
  } @catch (err) {
1596
1664
  <p class="downstream-caught">{(err as Error).message}</p>
1597
1665
  }
@@ -1643,9 +1711,9 @@ describe('sync error while async deriveds are pending', () => {
1643
1711
 
1644
1712
  function Inner() @{
1645
1713
  @try {
1646
- let &[data] = trackAsync(() => user_promise);
1714
+ const data = trackAsync(() => user_promise);
1647
1715
  throw new Error('synchronous error');
1648
- <p class="resolved">{data}</p>
1716
+ <p class="resolved">{data.value}</p>
1649
1717
  } @catch (err) {
1650
1718
  <p class="downstream-caught">{(err as Error).message}</p>
1651
1719
  }
@@ -1698,9 +1766,9 @@ describe('sync error while async deriveds are pending', () => {
1698
1766
 
1699
1767
  function Inner() @{
1700
1768
  @try {
1701
- let &[data] = trackAsync(() => user_promise);
1769
+ const data = trackAsync(() => user_promise);
1702
1770
  throw new Error('synchronous error');
1703
- <p class="resolved">{data}</p>
1771
+ <p class="resolved">{data.value}</p>
1704
1772
  } @catch (err) {
1705
1773
  <p class="downstream-caught">{(err as Error).message}</p>
1706
1774
  }