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
@@ -1,4 +1,4 @@
1
- import type { DynamicProps, PropsWithExtras, TSRXElement } from 'ripple';
1
+ import type { Component, DynamicProps, PropsWithExtras, TSRXElement } from 'ripple';
2
2
  import { createRefKey, track } from 'ripple';
3
3
 
4
4
  describe('server dynamic DOM elements', () => {
@@ -13,6 +13,26 @@ describe('server dynamic DOM elements', () => {
13
13
  expect(body).toBeHtml('<div>Hello World</div>');
14
14
  });
15
15
 
16
+ it('renders a component held in a plain tracked assigned after creation', async () => {
17
+ function Child() @{
18
+ <p>{'I am the child'}</p>
19
+ }
20
+
21
+ function App() @{
22
+ // track(Child) would make a derived that calls the component, so an
23
+ // empty tracked receives the component through `.value` instead.
24
+ const Body = track<Component>();
25
+ Body.value = Child;
26
+ <div>
27
+ <{Body.value} />
28
+ </div>
29
+ }
30
+
31
+ const { body } = await render(App);
32
+
33
+ expect(body).toBeHtml('<div><p>I am the child</p></div>');
34
+ });
35
+
16
36
  it('renders static dynamic element from a plain object with a tracked property', async () => {
17
37
  function App() @{
18
38
  let obj = { tag: track('div') };
@@ -85,8 +105,8 @@ describe('server dynamic DOM elements', () => {
85
105
  it('handles dynamic element with attributes', async () => {
86
106
  function App() @{
87
107
  let tag = track('div');
88
- let &[className] = track('test-class');
89
- <{tag} class={className} id="test" data-testid="dynamic-element">{'Content'}</{tag}>
108
+ const className = track('test-class');
109
+ <{tag} class={className.value} id="test" data-testid="dynamic-element">{'Content'}</{tag}>
90
110
  }
91
111
  const { body } = await render(App);
92
112
  const { document } = parseHtml(body);
@@ -122,9 +142,9 @@ describe('server dynamic DOM elements', () => {
122
142
  it('handles dynamic element with class object', async () => {
123
143
  function App() @{
124
144
  let tag = track('div');
125
- let &[active] = track(true);
145
+ const active = track(true);
126
146
  <{tag}
127
- class={{ active: active, 'dynamic-element': true }}
147
+ class={{ active: active.value, 'dynamic-element': true }}
128
148
  >{'Element with class object'}</{tag}>
129
149
  }
130
150
 
@@ -259,7 +279,7 @@ describe('server dynamic DOM elements', () => {
259
279
  });
260
280
 
261
281
  it('handles spread attributes with class and CSS scoping', async () => {
262
- function DynamicButton(&{ ...rest }: PropsWithExtras<{
282
+ function DynamicButton({ ...rest }: PropsWithExtras<{
263
283
  class: string;
264
284
  id: string;
265
285
  }>) @{
@@ -278,8 +298,11 @@ describe('server dynamic DOM elements', () => {
278
298
  }
279
299
 
280
300
  function App() @{
281
- let &[count] = track(0);
282
- <DynamicButton class={count % 2 ? 'even' : 'odd'} id={count % 2 ? 'even' : 'odd'} />
301
+ const count = track(0);
302
+ <DynamicButton
303
+ class={count.value % 2 ? 'even' : 'odd'}
304
+ id={count.value % 2 ? 'even' : 'odd'}
305
+ />
283
306
  }
284
307
 
285
308
  const { body } = await render(App);
@@ -202,4 +202,98 @@ describe('for statements in SSR', () => {
202
202
  ),
203
203
  ).toThrow('Continue statements are not allowed inside TSRX template for...of loops');
204
204
  });
205
+
206
+ it('renders the loop from a function that returns its template', async () => {
207
+ function Plain({ items }) {
208
+ return <ul>
209
+ @for (const item of items) {
210
+ <li>{item.text}</li>
211
+ }
212
+ </ul>;
213
+ }
214
+
215
+ function Indexed({ items }) {
216
+ return <ul>
217
+ @for (const item of items; index i) {
218
+ <li>{i + ': ' + item.text}</li>
219
+ }
220
+ </ul>;
221
+ }
222
+
223
+ function Keyed({ items }) {
224
+ return <ul>
225
+ @for (const item of items; key item.id) {
226
+ <li>{item.text}</li>
227
+ }
228
+ </ul>;
229
+ }
230
+
231
+ const Arrow = ({ items }) => <ul>
232
+ @for (const item of items; index i) {
233
+ <li>{i + ': ' + item.text}</li>
234
+ }
235
+ </ul>;
236
+
237
+ function App() @{
238
+ const items = [
239
+ { id: 1, text: 'a' },
240
+ { id: 2, text: 'b' },
241
+ ];
242
+ <>
243
+ <Plain {items} />
244
+ <Indexed {items} />
245
+ <Keyed {items} />
246
+ <Arrow {items} />
247
+ </>
248
+ }
249
+
250
+ const { body } = await render(App);
251
+ expect(body).toBeHtml(
252
+ '<ul><li>a</li><li>b</li></ul>' + '<ul><li>0: a</li><li>1: b</li></ul>' +
253
+ '<ul><li>a</li><li>b</li></ul>' +
254
+ '<ul><li>0: a</li><li>1: b</li></ul>',
255
+ );
256
+ });
257
+
258
+ it('renders the loop from a template held in a variable', async () => {
259
+ function Indexed({ items }) {
260
+ const list = <ul>
261
+ @for (const item of items; index i) {
262
+ <li>{i + ': ' + item.text}</li>
263
+ }
264
+ </ul>;
265
+ return list;
266
+ }
267
+
268
+ function App() @{
269
+ const items = [
270
+ { id: 1, text: 'a' },
271
+ { id: 2, text: 'b' },
272
+ ];
273
+ <Indexed {items} />
274
+ }
275
+
276
+ const { body } = await render(App);
277
+ expect(body).toBeHtml('<ul><li>0: a</li><li>1: b</li></ul>');
278
+ });
279
+
280
+ it('renders a bare `@for` held in a variable through an expression', async () => {
281
+ function Returned({ items }) {
282
+ const yo = @for (const item of items; index i; key item.id) {
283
+ <li>{i + ': ' + item.text}</li>
284
+ };
285
+ return <ul>{yo}</ul>;
286
+ }
287
+
288
+ function App() @{
289
+ const items = [
290
+ { id: 1, text: 'a' },
291
+ { id: 2, text: 'b' },
292
+ ];
293
+ <Returned {items} />
294
+ }
295
+
296
+ const { body } = await render(App);
297
+ expect(body).toBeHtml('<ul><li>0: a</li><li>1: b</li></ul>');
298
+ });
205
299
  });
@@ -20,13 +20,13 @@ describe('head elements', () => {
20
20
 
21
21
  it('renders reactive title element', async () => {
22
22
  function App() @{
23
- let &[title] = track('Initial Title');
23
+ const title = track('Initial Title');
24
24
  <>
25
25
  <head>
26
- <title>{title}</title>
26
+ <title>{title.value}</title>
27
27
  </head>
28
28
  <div>
29
- <span>{title}</span>
29
+ <span>{title.value}</span>
30
30
  </div>
31
31
  </>
32
32
  }
@@ -40,9 +40,9 @@ describe('head elements', () => {
40
40
 
41
41
  it('renders title with template literal', async () => {
42
42
  function App() @{
43
- let &[name] = track('World');
43
+ const name = track('World');
44
44
  <head>
45
- <title>{`Hello ${name}!`}</title>
45
+ <title>{`Hello ${name.value}!`}</title>
46
46
  </head>
47
47
  }
48
48
 
@@ -54,14 +54,14 @@ describe('head elements', () => {
54
54
 
55
55
  it('renders title with computed value', async () => {
56
56
  function App() @{
57
- let &[count] = track(0);
57
+ const count = track(0);
58
58
  let prefix = 'Count: ';
59
59
  <>
60
60
  <head>
61
- <title>{prefix + count}</title>
61
+ <title>{prefix + count.value}</title>
62
62
  </head>
63
63
  <div>
64
- <span>{count}</span>
64
+ <span>{count.value}</span>
65
65
  </div>
66
66
  </>
67
67
  }
@@ -130,11 +130,11 @@ describe('head elements', () => {
130
130
 
131
131
  it('renders title with conditional content', async () => {
132
132
  function App() @{
133
- let &[showPrefix] = track(true);
134
- let &[title] = track('Main Page');
133
+ const showPrefix = track(true);
134
+ const title = track('Main Page');
135
135
  <head>
136
136
  <title>
137
- {showPrefix ? 'App - ' + title : title}
137
+ {showPrefix.value ? 'App - ' + title.value : title.value}
138
138
  </title>
139
139
  </head>
140
140
  }
@@ -144,7 +144,7 @@ describe('sibling-scoped style blocks (server)', () => {
144
144
  });
145
145
 
146
146
  it('merges the scope classes into a spread', async () => {
147
- function Button(&{ ...rest }: { id: string; class?: string }) @{
147
+ function Button({ ...rest }: { id: string; class?: string }) @{
148
148
  <>
149
149
  <style>
150
150
  button {
@@ -177,7 +177,7 @@ describe('sibling-scoped style blocks (server)', () => {
177
177
 
178
178
  describe('spreads with an imported theme (server)', () => {
179
179
  it('merges the scope classes of a static class into the spread once', async () => {
180
- function Card(&{ ...rest }: { class?: string }) @{
180
+ function Card({ ...rest }: { class?: string }) @{
181
181
  <>
182
182
  <style apply={importedTheme}>
183
183
  .box {
@@ -37,6 +37,17 @@ function recordingSink() {
37
37
 
38
38
  const SLOT_OPEN_RE = /<!--\[\?(\d+)-->/;
39
39
 
40
+ /**
41
+ * Settled units stream once the current task's microtasks have drained, so
42
+ * units settling together share one chunk: wait a macrotask for the flush.
43
+ */
44
+ async function flushed(): Promise<void> {
45
+ // the first macrotask lets the settle microtasks schedule the flush, the
46
+ // second lets that flush run
47
+ await new Promise((resolve) => setImmediate(resolve));
48
+ await new Promise((resolve) => setImmediate(resolve));
49
+ }
50
+
40
51
  /**
41
52
  * Applies streamed chunks the way the inline swap runtime would: collects
42
53
  * chunk templates, then repeatedly replaces `<!--[?N-->…<!--]-->` slots
@@ -160,8 +171,8 @@ describe('streaming try/pending boundaries', () => {
160
171
  const d = deferred<string>();
161
172
 
162
173
  function Content() @{
163
- let &[data] = trackAsync(() => d.promise);
164
- <p>{data}</p>
174
+ const data = trackAsync(() => d.promise);
175
+ <p>{data.value}</p>
165
176
  }
166
177
 
167
178
  function App() @{
@@ -218,8 +229,8 @@ describe('streaming try/pending boundaries', () => {
218
229
  const d = deferred<string>();
219
230
 
220
231
  function Content() @{
221
- let &[data] = trackAsync(() => d.promise);
222
- <p>{data}</p>
232
+ const data = trackAsync(() => d.promise);
233
+ <p>{data.value}</p>
223
234
  }
224
235
 
225
236
  function App() @{
@@ -250,8 +261,8 @@ describe('streaming try/pending boundaries', () => {
250
261
  const d = deferred<string>();
251
262
 
252
263
  function Content() @{
253
- let &[data] = trackAsync(() => d.promise);
254
- <p>{data}</p>
264
+ const data = trackAsync(() => d.promise);
265
+ <p>{data.value}</p>
255
266
  }
256
267
 
257
268
  function App() @{
@@ -286,8 +297,8 @@ describe('streaming try/pending boundaries', () => {
286
297
  const d = deferred<string>();
287
298
 
288
299
  function Content() @{
289
- let &[data] = trackAsync(() => d.promise);
290
- <p>{data}</p>
300
+ const data = trackAsync(() => d.promise);
301
+ <p>{data.value}</p>
291
302
  }
292
303
 
293
304
  function App() @{
@@ -329,13 +340,13 @@ describe('streaming try/pending boundaries', () => {
329
340
  describe('streaming nested and sibling boundaries', () => {
330
341
  function makeNestedApp(d_outer: Deferred<string>, d_inner: Deferred<string>) {
331
342
  function OuterData() @{
332
- let &[data] = trackAsync(() => d_outer.promise);
333
- <p class="outer">{data}</p>
343
+ const data = trackAsync(() => d_outer.promise);
344
+ <p class="outer">{data.value}</p>
334
345
  }
335
346
 
336
347
  function InnerData() @{
337
- let &[data] = trackAsync(() => d_inner.promise);
338
- <p class="inner">{data}</p>
348
+ const data = trackAsync(() => d_inner.promise);
349
+ <p class="inner">{data.value}</p>
339
350
  }
340
351
 
341
352
  function App() @{
@@ -396,9 +407,7 @@ describe('streaming nested and sibling boundaries', () => {
396
407
  const result = render(App, { stream: sink });
397
408
 
398
409
  d_outer.resolve('outer-done');
399
- await d_outer.promise;
400
- await Promise.resolve();
401
- await Promise.resolve();
410
+ await flushed();
402
411
 
403
412
  expect(chunks).toHaveLength(2);
404
413
  const parent_chunk = chunks[1];
@@ -420,13 +429,13 @@ describe('streaming nested and sibling boundaries', () => {
420
429
  const d_second = deferred<string>();
421
430
 
422
431
  function First() @{
423
- let &[data] = trackAsync(() => d_first.promise);
424
- <p>{'first: ' + data}</p>
432
+ const data = trackAsync(() => d_first.promise);
433
+ <p>{'first: ' + data.value}</p>
425
434
  }
426
435
 
427
436
  function Second() @{
428
- let &[data] = trackAsync(() => d_second.promise);
429
- <p>{'second: ' + data}</p>
437
+ const data = trackAsync(() => d_second.promise);
438
+ <p>{'second: ' + data.value}</p>
430
439
  }
431
440
 
432
441
  function App() @{
@@ -448,9 +457,7 @@ describe('streaming nested and sibling boundaries', () => {
448
457
  const result = render(App, { stream: sink });
449
458
 
450
459
  d_second.resolve('B');
451
- await d_second.promise;
452
- await Promise.resolve();
453
- await Promise.resolve();
460
+ await flushed();
454
461
 
455
462
  expect(chunks).toHaveLength(2);
456
463
  expect(chunks[1]).toContain('second: B');
@@ -468,16 +475,16 @@ describe('streaming nested and sibling boundaries', () => {
468
475
  async () => {
469
476
  function makeApp(ds: Deferred<string>[]) {
470
477
  function A() @{
471
- let &[data] = trackAsync(() => ds[0].promise);
472
- <p>{'A:' + data}</p>
478
+ const data = trackAsync(() => ds[0].promise);
479
+ <p>{'A:' + data.value}</p>
473
480
  }
474
481
  function B() @{
475
- let &[data] = trackAsync(() => ds[1].promise);
476
- <p>{'B:' + data}</p>
482
+ const data = trackAsync(() => ds[1].promise);
483
+ <p>{'B:' + data.value}</p>
477
484
  }
478
485
  function C() @{
479
- let &[data] = trackAsync(() => ds[2].promise);
480
- <p>{'C:' + data}</p>
486
+ const data = trackAsync(() => ds[2].promise);
487
+ <p>{'C:' + data.value}</p>
481
488
  }
482
489
 
483
490
  function App() @{
@@ -540,8 +547,8 @@ describe('streaming root boundary', () => {
540
547
  const d = deferred<string>();
541
548
 
542
549
  function App() @{
543
- let &[data] = trackAsync(() => d.promise);
544
- <p>{'app: ' + data}</p>
550
+ const data = trackAsync(() => d.promise);
551
+ <p>{'app: ' + data.value}</p>
545
552
  }
546
553
 
547
554
  function RootPending() @{
@@ -568,8 +575,8 @@ describe('streaming with a document template', () => {
568
575
  const d = deferred<string>();
569
576
 
570
577
  function Content() @{
571
- let &[data] = trackAsync(() => d.promise);
572
- <p>{data}</p>
578
+ const data = trackAsync(() => d.promise);
579
+ <p>{data.value}</p>
573
580
  }
574
581
 
575
582
  function App() @{
@@ -612,14 +619,14 @@ describe('streaming head content', () => {
612
619
  const d = deferred<string>();
613
620
 
614
621
  function LateHead() @{
615
- let &[data] = trackAsync(() => d.promise);
622
+ const data = trackAsync(() => d.promise);
616
623
  <>
617
- @if (data) {
624
+ @if (data.value) {
618
625
  <>
619
626
  <head>
620
- <title>{'title:' + data}</title>
627
+ <title>{'title:' + data.value}</title>
621
628
  </head>
622
- <p class="has-head">{data}</p>
629
+ <p class="has-head">{data.value}</p>
623
630
  </>
624
631
  }
625
632
  </>
@@ -670,18 +677,18 @@ describe('streaming CSS', () => {
670
677
  }
671
678
 
672
679
  function GateOne() @{
673
- let &[ready] = trackAsync(() => d_gate.promise);
680
+ const ready = trackAsync(() => d_gate.promise);
674
681
  <>
675
- @if (ready) {
682
+ @if (ready.value) {
676
683
  <LateStyled />
677
684
  }
678
685
  </>
679
686
  }
680
687
 
681
688
  function GateTwo() @{
682
- let &[ready] = trackAsync(() => d_gate2.promise);
689
+ const ready = trackAsync(() => d_gate2.promise);
683
690
  <>
684
- @if (ready) {
691
+ @if (ready.value) {
685
692
  <LateStyled />
686
693
  }
687
694
  </>
@@ -716,9 +723,7 @@ describe('streaming CSS', () => {
716
723
  expect(chunks[0]).not.toContain('.late-styled');
717
724
 
718
725
  d_gate.resolve(true);
719
- await d_gate.promise;
720
- await Promise.resolve();
721
- await Promise.resolve();
726
+ await flushed();
722
727
 
723
728
  expect(chunks).toHaveLength(2);
724
729
  // the chunk carries the style it needs, ahead of its template