ripple 0.3.12 → 0.3.13

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 (190) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +8 -2
  3. package/src/compiler/phases/1-parse/index.js +73 -30
  4. package/src/compiler/phases/2-analyze/index.js +28 -58
  5. package/src/compiler/phases/3-transform/client/index.js +127 -164
  6. package/src/compiler/phases/3-transform/segments.js +4 -8
  7. package/src/compiler/phases/3-transform/server/index.js +210 -360
  8. package/src/compiler/types/import.d.ts +0 -12
  9. package/src/compiler/types/index.d.ts +12 -5
  10. package/src/compiler/types/parse.d.ts +2 -0
  11. package/src/compiler/utils.js +39 -44
  12. package/src/helpers.d.ts +2 -0
  13. package/src/runtime/index-client.js +15 -13
  14. package/src/runtime/index-server.js +18 -11
  15. package/src/runtime/internal/client/blocks.js +19 -23
  16. package/src/runtime/internal/client/constants.js +20 -9
  17. package/src/runtime/internal/client/index.js +14 -4
  18. package/src/runtime/internal/client/runtime.js +435 -173
  19. package/src/runtime/internal/client/try.js +334 -156
  20. package/src/runtime/internal/client/types.d.ts +26 -0
  21. package/src/runtime/internal/server/blocks.js +183 -0
  22. package/src/runtime/internal/server/constants.js +7 -0
  23. package/src/runtime/internal/server/index.js +780 -148
  24. package/src/runtime/internal/server/types.d.ts +35 -0
  25. package/src/server/index.js +1 -1
  26. package/src/utils/async.js +35 -0
  27. package/src/utils/builders.js +3 -1
  28. package/tests/client/__snapshots__/computed-properties.test.rsrx.snap +49 -0
  29. package/tests/client/__snapshots__/for.test.rsrx.snap +319 -0
  30. package/tests/client/__snapshots__/html.test.rsrx.snap +40 -0
  31. package/tests/client/_etc.test.rsrx +7 -0
  32. package/tests/client/array/{array.static.test.ripple → array.static.test.rsrx} +18 -20
  33. package/tests/client/async-suspend.test.rsrx +662 -0
  34. package/tests/client/basic/__snapshots__/basic.attributes.test.rsrx.snap +60 -0
  35. package/tests/client/basic/__snapshots__/basic.rendering.test.rsrx.snap +59 -0
  36. package/tests/client/basic/{basic.errors.test.ripple → basic.errors.test.rsrx} +2 -2
  37. package/tests/client/compiler/__snapshots__/compiler.assignments.test.rsrx.snap +12 -0
  38. package/tests/client/compiler/__snapshots__/compiler.typescript.test.rsrx.snap +46 -0
  39. package/tests/client/compiler/{compiler.try-in-function.test.ripple → compiler.try-in-function.test.rsrx} +8 -6
  40. package/tests/client/composite/__snapshots__/composite.render.test.rsrx.snap +37 -0
  41. package/tests/client/{function-overload.test.ripple → function-overload.test.rsrx} +1 -1
  42. package/tests/client/try.test.rsrx +1702 -0
  43. package/tests/hydration/build-components.js +5 -3
  44. package/tests/hydration/compiled/client/head.js +11 -11
  45. package/tests/hydration/compiled/client/mixed-control-flow.js +55 -70
  46. package/tests/hydration/compiled/client/nested-control-flow.js +72 -88
  47. package/tests/hydration/compiled/client/try.js +42 -54
  48. package/tests/hydration/compiled/server/basic.js +491 -369
  49. package/tests/hydration/compiled/server/composite.js +153 -128
  50. package/tests/hydration/compiled/server/events.js +166 -145
  51. package/tests/hydration/compiled/server/for.js +821 -677
  52. package/tests/hydration/compiled/server/head.js +200 -165
  53. package/tests/hydration/compiled/server/hmr.js +62 -54
  54. package/tests/hydration/compiled/server/html-in-template.js +64 -55
  55. package/tests/hydration/compiled/server/html.js +1477 -1360
  56. package/tests/hydration/compiled/server/if-children.js +448 -408
  57. package/tests/hydration/compiled/server/if.js +204 -171
  58. package/tests/hydration/compiled/server/mixed-control-flow.js +237 -195
  59. package/tests/hydration/compiled/server/nested-control-flow.js +533 -467
  60. package/tests/hydration/compiled/server/portal.js +94 -107
  61. package/tests/hydration/compiled/server/reactivity.js +87 -64
  62. package/tests/hydration/compiled/server/return.js +1424 -1174
  63. package/tests/hydration/compiled/server/switch.js +268 -238
  64. package/tests/hydration/compiled/server/try.js +98 -87
  65. package/tests/hydration/components/{mixed-control-flow.ripple → mixed-control-flow.rsrx} +2 -2
  66. package/tests/hydration/components/{try.ripple → try.rsrx} +4 -2
  67. package/tests/hydration/mixed-control-flow.test.js +14 -0
  68. package/tests/hydration/nested-control-flow.test.js +50 -48
  69. package/tests/hydration/try.test.js +25 -0
  70. package/tests/server/__snapshots__/compiler.test.ripple.snap +0 -32
  71. package/tests/server/__snapshots__/compiler.test.rsrx.snap +95 -0
  72. package/tests/server/{compiler.test.ripple → compiler.test.rsrx} +0 -17
  73. package/tests/server/{html-nesting-validation.test.ripple → html-nesting-validation.test.rsrx} +3 -3
  74. package/tests/server/streaming-ssr.test.rsrx +115 -0
  75. package/tests/server/try.test.rsrx +503 -0
  76. package/tests/utils/compiler-compat-config.test.js +3 -3
  77. package/tests/utils/vite-plugin-config.test.js +1 -1
  78. package/tests/utils/vite-plugin-hmr.test.js +5 -5
  79. package/tsconfig.json +2 -0
  80. package/types/index.d.ts +13 -23
  81. package/types/server.d.ts +43 -16
  82. package/tests/client/_etc.test.ripple +0 -5
  83. package/tests/client/async-suspend.test.ripple +0 -94
  84. package/tests/client/try.test.ripple +0 -196
  85. package/tests/server/streaming-ssr.test.ripple +0 -68
  86. package/tests/server/try.test.ripple +0 -82
  87. /package/tests/client/array/{array.copy-within.test.ripple → array.copy-within.test.rsrx} +0 -0
  88. /package/tests/client/array/{array.derived.test.ripple → array.derived.test.rsrx} +0 -0
  89. /package/tests/client/array/{array.iteration.test.ripple → array.iteration.test.rsrx} +0 -0
  90. /package/tests/client/array/{array.mutations.test.ripple → array.mutations.test.rsrx} +0 -0
  91. /package/tests/client/array/{array.to-methods.test.ripple → array.to-methods.test.rsrx} +0 -0
  92. /package/tests/client/basic/{basic.attributes.test.ripple → basic.attributes.test.rsrx} +0 -0
  93. /package/tests/client/basic/{basic.collections.test.ripple → basic.collections.test.rsrx} +0 -0
  94. /package/tests/client/basic/{basic.components.test.ripple → basic.components.test.rsrx} +0 -0
  95. /package/tests/client/basic/{basic.events.test.ripple → basic.events.test.rsrx} +0 -0
  96. /package/tests/client/basic/{basic.get-set.test.ripple → basic.get-set.test.rsrx} +0 -0
  97. /package/tests/client/basic/{basic.hmr.test.ripple → basic.hmr.test.rsrx} +0 -0
  98. /package/tests/client/basic/{basic.reactivity.test.ripple → basic.reactivity.test.rsrx} +0 -0
  99. /package/tests/client/basic/{basic.rendering.test.ripple → basic.rendering.test.rsrx} +0 -0
  100. /package/tests/client/basic/{basic.styling.test.ripple → basic.styling.test.rsrx} +0 -0
  101. /package/tests/client/basic/{basic.utilities.test.ripple → basic.utilities.test.rsrx} +0 -0
  102. /package/tests/client/{boundaries.test.ripple → boundaries.test.rsrx} +0 -0
  103. /package/tests/client/compiler/{compiler.assignments.test.ripple → compiler.assignments.test.rsrx} +0 -0
  104. /package/tests/client/compiler/{compiler.attributes.test.ripple → compiler.attributes.test.rsrx} +0 -0
  105. /package/tests/client/compiler/{compiler.basic.test.ripple → compiler.basic.test.rsrx} +0 -0
  106. /package/tests/client/compiler/{compiler.regex.test.ripple → compiler.regex.test.rsrx} +0 -0
  107. /package/tests/client/compiler/{compiler.tracked-access.test.ripple → compiler.tracked-access.test.rsrx} +0 -0
  108. /package/tests/client/compiler/{compiler.typescript.test.ripple → compiler.typescript.test.rsrx} +0 -0
  109. /package/tests/client/composite/{composite.dynamic-components.test.ripple → composite.dynamic-components.test.rsrx} +0 -0
  110. /package/tests/client/composite/{composite.generics.test.ripple → composite.generics.test.rsrx} +0 -0
  111. /package/tests/client/composite/{composite.props.test.ripple → composite.props.test.rsrx} +0 -0
  112. /package/tests/client/composite/{composite.reactivity.test.ripple → composite.reactivity.test.rsrx} +0 -0
  113. /package/tests/client/composite/{composite.render.test.ripple → composite.render.test.rsrx} +0 -0
  114. /package/tests/client/{computed-properties.test.ripple → computed-properties.test.rsrx} +0 -0
  115. /package/tests/client/{context.test.ripple → context.test.rsrx} +0 -0
  116. /package/tests/client/css/{global-additional-cases.test.ripple → global-additional-cases.test.rsrx} +0 -0
  117. /package/tests/client/css/{global-advanced-selectors.test.ripple → global-advanced-selectors.test.rsrx} +0 -0
  118. /package/tests/client/css/{global-at-rules.test.ripple → global-at-rules.test.rsrx} +0 -0
  119. /package/tests/client/css/{global-basic.test.ripple → global-basic.test.rsrx} +0 -0
  120. /package/tests/client/css/{global-classes-ids.test.ripple → global-classes-ids.test.rsrx} +0 -0
  121. /package/tests/client/css/{global-combinators.test.ripple → global-combinators.test.rsrx} +0 -0
  122. /package/tests/client/css/{global-complex-nesting.test.ripple → global-complex-nesting.test.rsrx} +0 -0
  123. /package/tests/client/css/{global-edge-cases.test.ripple → global-edge-cases.test.rsrx} +0 -0
  124. /package/tests/client/css/{global-keyframes.test.ripple → global-keyframes.test.rsrx} +0 -0
  125. /package/tests/client/css/{global-nested.test.ripple → global-nested.test.rsrx} +0 -0
  126. /package/tests/client/css/{global-pseudo.test.ripple → global-pseudo.test.rsrx} +0 -0
  127. /package/tests/client/css/{global-scoping.test.ripple → global-scoping.test.rsrx} +0 -0
  128. /package/tests/client/css/{style-identifier.test.ripple → style-identifier.test.rsrx} +0 -0
  129. /package/tests/client/{date.test.ripple → date.test.rsrx} +0 -0
  130. /package/tests/client/{dynamic-elements.test.ripple → dynamic-elements.test.rsrx} +0 -0
  131. /package/tests/client/{events.test.ripple → events.test.rsrx} +0 -0
  132. /package/tests/client/{for.test.ripple → for.test.rsrx} +0 -0
  133. /package/tests/client/{function-overload-import.ripple → function-overload-import.rsrx} +0 -0
  134. /package/tests/client/{head.test.ripple → head.test.rsrx} +0 -0
  135. /package/tests/client/{html.test.ripple → html.test.rsrx} +0 -0
  136. /package/tests/client/{input-value.test.ripple → input-value.test.rsrx} +0 -0
  137. /package/tests/client/{lazy-destructuring.test.ripple → lazy-destructuring.test.rsrx} +0 -0
  138. /package/tests/client/{map.test.ripple → map.test.rsrx} +0 -0
  139. /package/tests/client/{media-query.test.ripple → media-query.test.rsrx} +0 -0
  140. /package/tests/client/{object.test.ripple → object.test.rsrx} +0 -0
  141. /package/tests/client/{portal.test.ripple → portal.test.rsrx} +0 -0
  142. /package/tests/client/{ref.test.ripple → ref.test.rsrx} +0 -0
  143. /package/tests/client/{return.test.ripple → return.test.rsrx} +0 -0
  144. /package/tests/client/{set.test.ripple → set.test.rsrx} +0 -0
  145. /package/tests/client/{svg.test.ripple → svg.test.rsrx} +0 -0
  146. /package/tests/client/{switch.test.ripple → switch.test.rsrx} +0 -0
  147. /package/tests/client/{tsx.test.ripple → tsx.test.rsrx} +0 -0
  148. /package/tests/client/{typescript-generics.test.ripple → typescript-generics.test.rsrx} +0 -0
  149. /package/tests/client/url/{url.derived.test.ripple → url.derived.test.rsrx} +0 -0
  150. /package/tests/client/url/{url.parsing.test.ripple → url.parsing.test.rsrx} +0 -0
  151. /package/tests/client/url/{url.partial-removal.test.ripple → url.partial-removal.test.rsrx} +0 -0
  152. /package/tests/client/url/{url.reactivity.test.ripple → url.reactivity.test.rsrx} +0 -0
  153. /package/tests/client/url/{url.serialization.test.ripple → url.serialization.test.rsrx} +0 -0
  154. /package/tests/client/url-search-params/{url-search-params.derived.test.ripple → url-search-params.derived.test.rsrx} +0 -0
  155. /package/tests/client/url-search-params/{url-search-params.initialization.test.ripple → url-search-params.initialization.test.rsrx} +0 -0
  156. /package/tests/client/url-search-params/{url-search-params.iteration.test.ripple → url-search-params.iteration.test.rsrx} +0 -0
  157. /package/tests/client/url-search-params/{url-search-params.mutation.test.ripple → url-search-params.mutation.test.rsrx} +0 -0
  158. /package/tests/client/url-search-params/{url-search-params.retrieval.test.ripple → url-search-params.retrieval.test.rsrx} +0 -0
  159. /package/tests/client/url-search-params/{url-search-params.serialization.test.ripple → url-search-params.serialization.test.rsrx} +0 -0
  160. /package/tests/client/url-search-params/{url-search-params.tracked-url.test.ripple → url-search-params.tracked-url.test.rsrx} +0 -0
  161. /package/tests/hydration/components/{basic.ripple → basic.rsrx} +0 -0
  162. /package/tests/hydration/components/{composite.ripple → composite.rsrx} +0 -0
  163. /package/tests/hydration/components/{events.ripple → events.rsrx} +0 -0
  164. /package/tests/hydration/components/{for.ripple → for.rsrx} +0 -0
  165. /package/tests/hydration/components/{head.ripple → head.rsrx} +0 -0
  166. /package/tests/hydration/components/{hmr.ripple → hmr.rsrx} +0 -0
  167. /package/tests/hydration/components/{html-in-template.ripple → html-in-template.rsrx} +0 -0
  168. /package/tests/hydration/components/{html.ripple → html.rsrx} +0 -0
  169. /package/tests/hydration/components/{if-children.ripple → if-children.rsrx} +0 -0
  170. /package/tests/hydration/components/{if.ripple → if.rsrx} +0 -0
  171. /package/tests/hydration/components/{nested-control-flow.ripple → nested-control-flow.rsrx} +0 -0
  172. /package/tests/hydration/components/{portal.ripple → portal.rsrx} +0 -0
  173. /package/tests/hydration/components/{reactivity.ripple → reactivity.rsrx} +0 -0
  174. /package/tests/hydration/components/{return.ripple → return.rsrx} +0 -0
  175. /package/tests/hydration/components/{switch.ripple → switch.rsrx} +0 -0
  176. /package/tests/server/{await.test.ripple → await.test.rsrx} +0 -0
  177. /package/tests/server/{basic.attributes.test.ripple → basic.attributes.test.rsrx} +0 -0
  178. /package/tests/server/{basic.components.test.ripple → basic.components.test.rsrx} +0 -0
  179. /package/tests/server/{basic.test.ripple → basic.test.rsrx} +0 -0
  180. /package/tests/server/{composite.props.test.ripple → composite.props.test.rsrx} +0 -0
  181. /package/tests/server/{composite.test.ripple → composite.test.rsrx} +0 -0
  182. /package/tests/server/{context.test.ripple → context.test.rsrx} +0 -0
  183. /package/tests/server/{dynamic-elements.test.ripple → dynamic-elements.test.rsrx} +0 -0
  184. /package/tests/server/{for.test.ripple → for.test.rsrx} +0 -0
  185. /package/tests/server/{head.test.ripple → head.test.rsrx} +0 -0
  186. /package/tests/server/{if.test.ripple → if.test.rsrx} +0 -0
  187. /package/tests/server/{lazy-destructuring.test.ripple → lazy-destructuring.test.rsrx} +0 -0
  188. /package/tests/server/{return.test.ripple → return.test.rsrx} +0 -0
  189. /package/tests/server/{style-identifier.test.ripple → style-identifier.test.rsrx} +0 -0
  190. /package/tests/server/{switch.test.ripple → switch.test.rsrx} +0 -0
@@ -1,140 +1,151 @@
1
1
  // @ts-nocheck
2
2
  import * as _$_ from 'ripple/internal/server';
3
3
 
4
- export async function AsyncListInTryPending(__output) {
5
- return _$_.async(async () => {
6
- _$_.push_component();
7
- __output.push('<!--[-->');
4
+ import { trackAsync } from 'ripple/server';
8
5
 
9
- var __pending_pos = __output.body.length;
6
+ export function AsyncListInTryPending() {
7
+ _$_.push_component();
10
8
 
11
- __output.push('<p');
12
- __output.push(' class="loading"');
13
- __output.push('>');
9
+ _$_.try_block(
10
+ () => {
11
+ _$_.output_push('<!--[-->');
14
12
 
15
- {
16
- __output.push('loading...');
17
- }
13
+ _$_.regular_block(() => {
14
+ {
15
+ const comp = AsyncList;
16
+ const args = [{}];
18
17
 
19
- __output.push('</p>');
18
+ comp(...args);
19
+ }
20
+ });
20
21
 
21
- await _$_.async(async () => {
22
- __output.body = __output.body.slice(0, __pending_pos);
22
+ _$_.output_push('<!--]-->');
23
+ },
24
+ null,
25
+ () => {
26
+ _$_.output_push('<!--[-->');
23
27
 
24
- {
25
- const comp = AsyncList;
26
- const args = [__output, {}];
28
+ _$_.regular_block(() => {
29
+ _$_.output_push('<p');
30
+ _$_.output_push(' class="loading"');
31
+ _$_.output_push('>');
27
32
 
28
- await comp(...args);
29
- }
30
- });
33
+ {
34
+ _$_.output_push('loading...');
35
+ }
31
36
 
32
- __output.push('<!--]-->');
33
- _$_.pop_component();
34
- });
35
- }
37
+ _$_.output_push('</p>');
38
+ });
36
39
 
37
- AsyncListInTryPending.async = true;
40
+ _$_.output_push('<!--]-->');
41
+ }
42
+ );
38
43
 
39
- async function AsyncList(__output) {
40
- return _$_.async(async () => {
41
- _$_.push_component();
44
+ _$_.pop_component();
45
+ }
42
46
 
43
- let items = await Promise.resolve(['alpha', 'beta', 'gamma']);
47
+ function AsyncList() {
48
+ _$_.push_component();
44
49
 
45
- if (_$_.aborted()) return;
50
+ let lazy = _$_.track_async(() => Promise.resolve(['alpha', 'beta', 'gamma']));
46
51
 
47
- __output.push('<ul');
48
- __output.push(' class="items"');
49
- __output.push('>');
52
+ _$_.regular_block(() => {
53
+ _$_.output_push('<ul');
54
+ _$_.output_push(' class="items"');
55
+ _$_.output_push('>');
50
56
 
51
57
  {
52
- __output.push('<!--[-->');
58
+ _$_.output_push('<!--[-->');
53
59
 
54
- for (let item of items) {
55
- __output.push('<li');
56
- __output.push('>');
60
+ for (let item of _$_.get(lazy)) {
61
+ _$_.output_push('<li');
62
+ _$_.output_push('>');
57
63
 
58
64
  {
59
- __output.push(_$_.escape(item));
65
+ _$_.output_push(_$_.escape(item));
60
66
  }
61
67
 
62
- __output.push('</li>');
68
+ _$_.output_push('</li>');
63
69
  }
64
70
 
65
- __output.push('<!--]-->');
71
+ _$_.output_push('<!--]-->');
66
72
  }
67
73
 
68
- __output.push('</ul>');
69
- _$_.pop_component();
74
+ _$_.output_push('</ul>');
70
75
  });
76
+
77
+ _$_.pop_component();
71
78
  }
72
79
 
73
- AsyncList.async = true;
80
+ export function AsyncTryWithLeadingSibling() {
81
+ _$_.push_component();
74
82
 
75
- export async function AsyncTryWithLeadingSibling(__output) {
76
- return _$_.async(async () => {
77
- _$_.push_component();
78
- __output.push('<div');
79
- __output.push(' class="before"');
80
- __output.push('>');
83
+ _$_.regular_block(() => {
84
+ _$_.output_push('<div');
85
+ _$_.output_push(' class="before"');
86
+ _$_.output_push('>');
81
87
 
82
88
  {
83
- __output.push('before');
89
+ _$_.output_push('before');
84
90
  }
85
91
 
86
- __output.push('</div>');
87
- __output.push('<!--[-->');
88
-
89
- var __pending_pos_1 = __output.body.length;
92
+ _$_.output_push('</div>');
93
+ });
90
94
 
91
- __output.push('<div');
92
- __output.push(' class="loading"');
93
- __output.push('>');
95
+ _$_.try_block(
96
+ () => {
97
+ _$_.output_push('<!--[-->');
94
98
 
95
- {
96
- __output.push('loading async content');
97
- }
99
+ _$_.regular_block(() => {
100
+ {
101
+ const comp = AsyncContent;
102
+ const args = [{}];
98
103
 
99
- __output.push('</div>');
104
+ comp(...args);
105
+ }
106
+ });
100
107
 
101
- await _$_.async(async () => {
102
- __output.body = __output.body.slice(0, __pending_pos_1);
108
+ _$_.output_push('<!--]-->');
109
+ },
110
+ null,
111
+ () => {
112
+ _$_.output_push('<!--[-->');
103
113
 
104
- {
105
- const comp = AsyncContent;
106
- const args = [__output, {}];
114
+ _$_.regular_block(() => {
115
+ _$_.output_push('<div');
116
+ _$_.output_push(' class="loading"');
117
+ _$_.output_push('>');
107
118
 
108
- await comp(...args);
109
- }
110
- });
119
+ {
120
+ _$_.output_push('loading async content');
121
+ }
111
122
 
112
- __output.push('<!--]-->');
113
- _$_.pop_component();
114
- });
115
- }
123
+ _$_.output_push('</div>');
124
+ });
116
125
 
117
- AsyncTryWithLeadingSibling.async = true;
126
+ _$_.output_push('<!--]-->');
127
+ }
128
+ );
118
129
 
119
- async function AsyncContent(__output) {
120
- return _$_.async(async () => {
121
- _$_.push_component();
130
+ _$_.pop_component();
131
+ }
122
132
 
123
- let value = await Promise.resolve('ready');
133
+ function AsyncContent() {
134
+ _$_.push_component();
124
135
 
125
- if (_$_.aborted()) return;
136
+ let lazy_1 = _$_.track_async(() => Promise.resolve('ready'));
126
137
 
127
- __output.push('<div');
128
- __output.push(' class="resolved"');
129
- __output.push('>');
138
+ _$_.regular_block(() => {
139
+ _$_.output_push('<div');
140
+ _$_.output_push(' class="resolved"');
141
+ _$_.output_push('>');
130
142
 
131
143
  {
132
- __output.push(_$_.escape(value));
144
+ _$_.output_push(_$_.escape(_$_.get(lazy_1)));
133
145
  }
134
146
 
135
- __output.push('</div>');
136
- _$_.pop_component();
147
+ _$_.output_push('</div>');
137
148
  });
138
- }
139
149
 
140
- AsyncContent.async = true;
150
+ _$_.pop_component();
151
+ }
@@ -1,4 +1,4 @@
1
- import { track } from 'ripple';
1
+ import { track, trackAsync } from 'ripple';
2
2
 
3
3
  export component MixedControlFlowStatic() {
4
4
  const rows = [
@@ -109,6 +109,6 @@ export component MixedControlFlowAsyncPending() {
109
109
  }
110
110
 
111
111
  component AsyncRow({ label }: { label: string }) {
112
- let value = await Promise.resolve(label);
112
+ let &[value] = trackAsync(() => Promise.resolve(label));
113
113
  <div class="resolved-row">{value}</div>
114
114
  }
@@ -1,3 +1,5 @@
1
+ import { trackAsync } from 'ripple';
2
+
1
3
  export component AsyncListInTryPending() {
2
4
  try {
3
5
  <AsyncList />
@@ -7,7 +9,7 @@ export component AsyncListInTryPending() {
7
9
  }
8
10
 
9
11
  component AsyncList() {
10
- let items = await Promise.resolve(['alpha', 'beta', 'gamma']);
12
+ let &[items] = trackAsync(() => Promise.resolve(['alpha', 'beta', 'gamma']));
11
13
 
12
14
  <ul class="items">
13
15
  for (let item of items) {
@@ -26,6 +28,6 @@ export component AsyncTryWithLeadingSibling() {
26
28
  }
27
29
 
28
30
  component AsyncContent() {
29
- let value = await Promise.resolve('ready');
31
+ let &[value] = trackAsync(() => Promise.resolve('ready'));
30
32
  <div class="resolved">{value}</div>
31
33
  }
@@ -54,6 +54,20 @@ describe('hydration > mixed control flow blocks', () => {
54
54
  );
55
55
  });
56
56
 
57
+ it('hydrates async try with resolved server content in mixed control flow', async () => {
58
+ await hydrateComponent(
59
+ ServerComponents.MixedControlFlowAsyncPending,
60
+ ClientComponents.MixedControlFlowAsyncPending,
61
+ );
62
+
63
+ // Server resolves trackAsync fully, so resolved content is in the SSR HTML
64
+ expect(container.querySelector('.before')?.textContent).toBe('before');
65
+ expect(container.querySelector('.resolved-row')?.textContent).toBe('row-1');
66
+ expect(container.querySelector('.pending-row')).toBeNull();
67
+ });
68
+ });
69
+
70
+ describe.skip('streaming ssr > mixed control flow async pending', () => {
57
71
  it('hydrates async pending path in mixed control flow without losing leading structure', async () => {
58
72
  await hydrateComponent(
59
73
  ServerComponents.MixedControlFlowAsyncPending,
@@ -99,18 +99,10 @@ describe('hydration > nested control flow (granular)', () => {
99
99
 
100
100
  // ── switch + try (no for/if — baseline for try cursor behaviour) ─────────────
101
101
  describe('switch + try', () => {
102
- it('shows pending fallback immediately after hydration', async () => {
103
- await hydrateComponent(ServerComponents.SwitchTry, ClientComponents.SwitchTry);
104
-
105
- // Server rendered the pending content; client should retain it during hydration
106
- expect(container.querySelector('.pending-a')?.textContent).toBe('A pending');
107
- });
108
-
109
- it('shows resolved content after async settles', async () => {
102
+ it('hydrates resolved content from server', async () => {
110
103
  await hydrateComponent(ServerComponents.SwitchTry, ClientComponents.SwitchTry);
111
104
 
112
- // After the promise resolves the pending fallback should be replaced
113
- await Promise.resolve();
105
+ // Server resolves trackAsync fully, so resolved content is in the SSR HTML
114
106
  expect(container.querySelector('.resolved-a')?.textContent).toBe('A resolved');
115
107
  expect(container.querySelector('.pending-a')).toBeNull();
116
108
  });
@@ -118,18 +110,9 @@ describe('hydration > nested control flow (granular)', () => {
118
110
 
119
111
  // ── for + switch + try (no if) ────────────────────────────────────────────────
120
112
  describe('for + switch + try', () => {
121
- it('shows pending fallback for each item immediately after hydration', async () => {
122
- await hydrateComponent(ServerComponents.ForSwitchTry, ClientComponents.ForSwitchTry);
123
-
124
- // Server rendered pending fallbacks for both items
125
- const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
126
- expect(pending).toEqual(['pending 1', 'pending 2']);
127
- });
128
-
129
- it('shows resolved content for each item after async settles', async () => {
113
+ it('hydrates resolved content for each item from server', async () => {
130
114
  await hydrateComponent(ServerComponents.ForSwitchTry, ClientComponents.ForSwitchTry);
131
115
 
132
- await Promise.resolve();
133
116
  const items = Array.from(container.querySelectorAll('.item')).map((n) => n.textContent);
134
117
  expect(items).toEqual(['A-1', 'B-2']);
135
118
  });
@@ -137,18 +120,9 @@ describe('hydration > nested control flow (granular)', () => {
137
120
 
138
121
  // ── for + if + try (no switch) ────────────────────────────────────────────────
139
122
  describe('for + if + try', () => {
140
- it('shows pending fallback for each item immediately after hydration', async () => {
141
- await hydrateComponent(ServerComponents.ForIfTry, ClientComponents.ForIfTry);
142
-
143
- // Server rendered pending fallbacks for both items
144
- const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
145
- expect(pending).toEqual(['pending 1', 'pending 2']);
146
- });
147
-
148
- it('shows resolved content for each item after async settles', async () => {
123
+ it('hydrates resolved content for each item from server', async () => {
149
124
  await hydrateComponent(ServerComponents.ForIfTry, ClientComponents.ForIfTry);
150
125
 
151
- await Promise.resolve();
152
126
  const items = Array.from(container.querySelectorAll('.item')).map((n) => n.textContent);
153
127
  expect(items).toEqual(['item-1', 'item-2']);
154
128
  });
@@ -156,48 +130,76 @@ describe('hydration > nested control flow (granular)', () => {
156
130
 
157
131
  // ── for + if + switch + try ───────────────────────────────────────────────────
158
132
  describe('for + if + switch + try', () => {
159
- it('shows pending fallback for single-item for+if+switch+try immediately after hydration', async () => {
133
+ it('hydrates resolved content for single-item for+if+switch+try', async () => {
160
134
  await hydrateComponent(
161
135
  ServerComponents.ForIfSwitchTrySingle,
162
136
  ClientComponents.ForIfSwitchTrySingle,
163
137
  );
164
138
 
165
- const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
166
- expect(pending).toEqual(['pending 1']);
139
+ const items = Array.from(container.querySelectorAll('.item')).map((n) => n.textContent);
140
+ expect(items).toEqual(['A-1']);
167
141
  });
168
142
 
169
- it('shows resolved content for single-item for+if+switch+try after async settles', async () => {
143
+ it('hydrates resolved content for two-item for+if+switch+try (cursor must advance correctly between items)', async () => {
170
144
  await hydrateComponent(
171
- ServerComponents.ForIfSwitchTrySingle,
172
- ClientComponents.ForIfSwitchTrySingle,
145
+ ServerComponents.ForIfSwitchTryMulti,
146
+ ClientComponents.ForIfSwitchTryMulti,
173
147
  );
174
148
 
175
- await Promise.resolve();
176
149
  const items = Array.from(container.querySelectorAll('.item')).map((n) => n.textContent);
177
- expect(items).toEqual(['A-1']);
150
+ expect(items).toEqual(['A-1', 'B-2']);
151
+ expect(container.querySelector('.item-1.kind-a')).not.toBeNull();
152
+ expect(container.querySelector('.item-2.kind-b')).not.toBeNull();
178
153
  });
154
+ });
155
+ });
179
156
 
180
- it('shows pending fallback for two-item for+if+switch+try immediately after hydration', async () => {
157
+ describe.skip('streaming ssr > nested control flow with try/pending', () => {
158
+ describe('switch + try', () => {
159
+ it('shows pending fallback immediately after hydration', async () => {
160
+ await hydrateComponent(ServerComponents.SwitchTry, ClientComponents.SwitchTry);
161
+
162
+ expect(container.querySelector('.pending-a')?.textContent).toBe('A pending');
163
+ });
164
+ });
165
+
166
+ describe('for + switch + try', () => {
167
+ it('shows pending fallback for each item immediately after hydration', async () => {
168
+ await hydrateComponent(ServerComponents.ForSwitchTry, ClientComponents.ForSwitchTry);
169
+
170
+ const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
171
+ expect(pending).toEqual(['pending 1', 'pending 2']);
172
+ });
173
+ });
174
+
175
+ describe('for + if + try', () => {
176
+ it('shows pending fallback for each item immediately after hydration', async () => {
177
+ await hydrateComponent(ServerComponents.ForIfTry, ClientComponents.ForIfTry);
178
+
179
+ const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
180
+ expect(pending).toEqual(['pending 1', 'pending 2']);
181
+ });
182
+ });
183
+
184
+ describe('for + if + switch + try', () => {
185
+ it('shows pending fallback for single-item for+if+switch+try immediately after hydration', async () => {
181
186
  await hydrateComponent(
182
- ServerComponents.ForIfSwitchTryMulti,
183
- ClientComponents.ForIfSwitchTryMulti,
187
+ ServerComponents.ForIfSwitchTrySingle,
188
+ ClientComponents.ForIfSwitchTrySingle,
184
189
  );
185
190
 
186
191
  const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
187
- expect(pending).toEqual(['pending 1', 'pending 2']);
192
+ expect(pending).toEqual(['pending 1']);
188
193
  });
189
194
 
190
- it('shows resolved content for two-item for+if+switch+try after async settles (cursor must advance correctly between items)', async () => {
195
+ it('shows pending fallback for two-item for+if+switch+try immediately after hydration', async () => {
191
196
  await hydrateComponent(
192
197
  ServerComponents.ForIfSwitchTryMulti,
193
198
  ClientComponents.ForIfSwitchTryMulti,
194
199
  );
195
200
 
196
- await Promise.resolve();
197
- const items = Array.from(container.querySelectorAll('.item')).map((n) => n.textContent);
198
- expect(items).toEqual(['A-1', 'B-2']);
199
- expect(container.querySelector('.item-1.kind-a')).not.toBeNull();
200
- expect(container.querySelector('.item-2.kind-b')).not.toBeNull();
201
+ const pending = Array.from(container.querySelectorAll('.pending')).map((n) => n.textContent);
202
+ expect(pending).toEqual(['pending 1', 'pending 2']);
201
203
  });
202
204
  });
203
205
  });
@@ -6,6 +6,31 @@ import * as ServerComponents from './compiled/server/try.js';
6
6
  import * as ClientComponents from './compiled/client/try.js';
7
7
 
8
8
  describe('hydration > try blocks (async)', () => {
9
+ it('hydrates async try with resolved server content', async () => {
10
+ await hydrateComponent(
11
+ ServerComponents.AsyncListInTryPending,
12
+ ClientComponents.AsyncListInTryPending,
13
+ );
14
+
15
+ // Server resolves trackAsync fully, so the resolved list is in the SSR HTML
16
+ const items = Array.from(container.querySelectorAll('.items li')).map((n) => n.textContent);
17
+ expect(items).toEqual(['alpha', 'beta', 'gamma']);
18
+ expect(container.querySelector('.loading')).toBeNull();
19
+ });
20
+
21
+ it('hydrates async try with leading sibling and resolved content', async () => {
22
+ await hydrateComponent(
23
+ ServerComponents.AsyncTryWithLeadingSibling,
24
+ ClientComponents.AsyncTryWithLeadingSibling,
25
+ );
26
+
27
+ expect(container.querySelector('.before')?.textContent).toBe('before');
28
+ expect(container.querySelector('.resolved')?.textContent).toBe('ready');
29
+ expect(container.querySelector('.loading')).toBeNull();
30
+ });
31
+ });
32
+
33
+ describe.skip('streaming ssr > try blocks (async pending)', () => {
9
34
  it('hydrates async try/pending and retains pending fallback', async () => {
10
35
  await hydrateComponent(
11
36
  ServerComponents.AsyncListInTryPending,
@@ -64,38 +64,6 @@ const ErrorMap = (Map);
64
64
  const errorMap = new ErrorMap();"
65
65
  `;
66
66
 
67
- exports[`compiler typescript tests > compiles imported component with conditional async in SSR 1`] = `
68
- "import * as _$_ from 'ripple/internal/server';
69
-
70
- import { ChildComponent } from './Child.ripple';
71
-
72
- export async function App(__output) {
73
- return _$_.async(async () => {
74
- _$_.push_component();
75
- __output.push('<div');
76
- __output.push('>');
77
-
78
- {
79
- {
80
- const comp = ChildComponent;
81
- const args = [__output, { message: "hello" }];
82
-
83
- if (comp?.async) {
84
- await comp(...args);
85
- } else if (comp) {
86
- comp(...args);
87
- }
88
- }
89
- }
90
-
91
- __output.push('</div>');
92
- _$_.pop_component();
93
- });
94
- }
95
-
96
- App.async = true;"
97
- `;
98
-
99
67
  exports[`compiler typescript tests > removes class TypeScript syntax from JS output 1`] = `
100
68
  "import * as _$_ from 'ripple/internal/server';
101
69
 
@@ -0,0 +1,95 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`compiler server block tests > compiles server block with with only supported types 1`] = `
4
+ "import * as _$_ from 'ripple/internal/server';
5
+
6
+ export const _$_server_$_ = (() => {
7
+ var _$_server_$_ = {};
8
+
9
+ function something() {
10
+ return 'unexported function';
11
+ }
12
+
13
+ _$_server_$_.fetchUser = async function fetchUser(id) {
14
+ const response = await fetch(\`/api/user/\${id}\`);
15
+ const data = await response.json();
16
+
17
+ return data;
18
+ };
19
+
20
+ const fetchUserAlias = fetchUser;
21
+ const AliasForFetchUserAlias = fetchUserAlias;
22
+
23
+ {
24
+ _$_server_$_.AnotherAlias = AliasForFetchUserAlias;
25
+ }
26
+
27
+ {
28
+ _$_server_$_.func = function test() {
29
+ return 'test';
30
+ };
31
+ }
32
+
33
+ {
34
+ _$_server_$_.func2 = function () {
35
+ return 'test';
36
+ };
37
+ }
38
+
39
+ {
40
+ _$_server_$_.func3 = () => {
41
+ return 'test';
42
+ };
43
+ }
44
+
45
+ {
46
+ _$_server_$_.fetchUserAlias = fetchUserAlias;
47
+ _$_server_$_.AliasForFetchUserAlias = AliasForFetchUserAlias;
48
+ }
49
+
50
+ return _$_server_$_;
51
+ })();"
52
+ `;
53
+
54
+ exports[`compiler typescript tests > compiles TSInstantiationExpression 1`] = `
55
+ "import * as _$_ from 'ripple/internal/server';
56
+
57
+ function makeBox(value) {
58
+ return { value };
59
+ }
60
+
61
+ const makeStringBox = (makeBox);
62
+ const stringBox = makeStringBox('abc');
63
+ const ErrorMap = (Map);
64
+ const errorMap = new ErrorMap();"
65
+ `;
66
+
67
+ exports[`compiler typescript tests > removes class TypeScript syntax from JS output 1`] = `
68
+ "import * as _$_ from 'ripple/internal/server';
69
+
70
+ class PrintEvent {
71
+ text;
72
+
73
+ constructor(text) {
74
+ this.text = text;
75
+ }
76
+ }"
77
+ `;
78
+
79
+ exports[`compiler typescript tests > removes class extends type arguments from JS output 1`] = `
80
+ "import * as _$_ from 'ripple/internal/server';
81
+
82
+ class StringMap extends Map {
83
+ constructor() {
84
+ super();
85
+ }
86
+ }"
87
+ `;
88
+
89
+ exports[`compiler typescript tests > removes type assertions from function parameters and leaves default values 1`] = `
90
+ "import * as _$_ from 'ripple/internal/server';
91
+
92
+ function getString(e = 'test') {
93
+ return e;
94
+ }"
95
+ `;
@@ -13,23 +13,6 @@ const errorMap = new ErrorMap();`;
13
13
  expect(result.js.code).toMatchSnapshot();
14
14
  });
15
15
 
16
- it('compiles imported component with conditional async in SSR', () => {
17
- const source = `import { ChildComponent } from './Child.ripple';
18
-
19
- export component App() {
20
- <div>
21
- <ChildComponent message="hello" />
22
- </div>
23
- }`;
24
-
25
- const result = compile(source, 'test.ripple', { mode: 'server' });
26
-
27
- // Should use if-statement instead of ternary to avoid parser issues
28
- expect(result.js.code).toContain('if (comp?.async)');
29
- expect(result.js.code).toContain('await comp(...args)');
30
- expect(result.js.code).toMatchSnapshot();
31
- });
32
-
33
16
  it('removes type assertions from function parameters and leaves default values', () => {
34
17
  const source = `
35
18
  function getString(e: string = 'test') {
@@ -1,17 +1,17 @@
1
1
  import type { MockInstance } from 'vitest';
2
- import { push_element, pop_element, reset_element_state } from 'ripple/internal/server';
2
+ import { push_element, pop_element, reset_state } from 'ripple/internal/server';
3
3
 
4
4
  describe('HTML nesting validation', () => {
5
5
  let consoleErrorSpy: MockInstance<typeof console.error>;
6
6
 
7
7
  beforeEach(() => {
8
- reset_element_state();
8
+ reset_state();
9
9
  consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
10
10
  });
11
11
 
12
12
  afterEach(() => {
13
13
  consoleErrorSpy.mockRestore();
14
- reset_element_state();
14
+ reset_state();
15
15
  });
16
16
 
17
17
  describe('push_element and pop_element runtime', () => {