ripple 0.3.72 → 0.3.76

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 (172) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +4 -10
  4. package/src/runtime/dynamic-client.js +33 -0
  5. package/src/runtime/dynamic-server.js +80 -0
  6. package/src/runtime/index-client.js +5 -13
  7. package/src/runtime/index-server.js +2 -0
  8. package/src/runtime/internal/client/blocks.js +6 -27
  9. package/src/runtime/internal/client/composite.js +11 -6
  10. package/src/runtime/internal/client/for.js +80 -5
  11. package/src/runtime/internal/client/index.js +0 -2
  12. package/src/runtime/internal/client/render.js +5 -2
  13. package/src/runtime/internal/client/types.d.ts +0 -10
  14. package/src/runtime/internal/server/index.js +8 -1
  15. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  16. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  17. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  18. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  19. package/tests/client/array/array.derived.test.tsrx +97 -109
  20. package/tests/client/array/array.iteration.test.tsrx +28 -28
  21. package/tests/client/array/array.mutations.test.tsrx +68 -68
  22. package/tests/client/array/array.static.test.tsrx +82 -92
  23. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  24. package/tests/client/async-suspend.test.tsrx +180 -179
  25. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  26. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  27. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  28. package/tests/client/basic/basic.collections.test.tsrx +55 -61
  29. package/tests/client/basic/basic.components.test.tsrx +198 -220
  30. package/tests/client/basic/basic.errors.test.tsrx +70 -76
  31. package/tests/client/basic/basic.events.test.tsrx +80 -85
  32. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  33. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  34. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  35. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  36. package/tests/client/basic/basic.styling.test.tsrx +16 -14
  37. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  38. package/tests/client/boundaries.test.tsrx +18 -18
  39. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  40. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  41. package/tests/client/compiler/compiler.basic.test.tsrx +357 -288
  42. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  43. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  44. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  45. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  46. package/tests/client/composite/composite.dynamic-components.test.tsrx +62 -47
  47. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  48. package/tests/client/composite/composite.props.test.tsrx +66 -74
  49. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  50. package/tests/client/composite/composite.render.test.tsrx +92 -101
  51. package/tests/client/computed-properties.test.tsrx +14 -18
  52. package/tests/client/context.test.tsrx +14 -18
  53. package/tests/client/css/global-additional-cases.test.tsrx +493 -439
  54. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  55. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  56. package/tests/client/css/global-basic.test.tsrx +105 -98
  57. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  58. package/tests/client/css/global-combinators.test.tsrx +83 -78
  59. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  60. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  61. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  62. package/tests/client/css/global-nested.test.tsrx +88 -78
  63. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  64. package/tests/client/css/global-scoping.test.tsrx +145 -125
  65. package/tests/client/css/style-identifier.test.tsrx +65 -72
  66. package/tests/client/date.test.tsrx +83 -83
  67. package/tests/client/dynamic-elements.test.tsrx +318 -299
  68. package/tests/client/events.test.tsrx +252 -266
  69. package/tests/client/for.test.tsrx +120 -127
  70. package/tests/client/head.test.tsrx +74 -48
  71. package/tests/client/html.test.tsrx +37 -49
  72. package/tests/client/input-value.test.tsrx +1125 -1354
  73. package/tests/client/lazy-array.test.tsrx +10 -16
  74. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  75. package/tests/client/map.test.tsrx +39 -41
  76. package/tests/client/media-query.test.tsrx +15 -19
  77. package/tests/client/object.test.tsrx +46 -56
  78. package/tests/client/portal.test.tsrx +31 -37
  79. package/tests/client/ref.test.tsrx +173 -193
  80. package/tests/client/return.test.tsrx +62 -37
  81. package/tests/client/set.test.tsrx +33 -33
  82. package/tests/client/svg.test.tsrx +197 -216
  83. package/tests/client/switch.test.tsrx +201 -191
  84. package/tests/client/track-async-hydration.test.tsrx +14 -18
  85. package/tests/client/tracked-index-access.test.tsrx +18 -28
  86. package/tests/client/try.test.tsrx +494 -619
  87. package/tests/client/tsx.test.tsrx +286 -292
  88. package/tests/client/typescript-generics.test.tsrx +121 -129
  89. package/tests/client/url/url.derived.test.tsrx +21 -25
  90. package/tests/client/url/url.parsing.test.tsrx +35 -35
  91. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  92. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  93. package/tests/client/url/url.serialization.test.tsrx +8 -8
  94. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  95. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  96. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  97. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  98. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  99. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  100. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  101. package/tests/hydration/compiled/client/basic.js +390 -319
  102. package/tests/hydration/compiled/client/composite.js +52 -44
  103. package/tests/hydration/compiled/client/for.js +734 -604
  104. package/tests/hydration/compiled/client/head.js +183 -103
  105. package/tests/hydration/compiled/client/html.js +93 -86
  106. package/tests/hydration/compiled/client/if-children.js +95 -71
  107. package/tests/hydration/compiled/client/if.js +113 -89
  108. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  109. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  110. package/tests/hydration/compiled/client/reactivity.js +26 -24
  111. package/tests/hydration/compiled/client/return.js +8 -42
  112. package/tests/hydration/compiled/client/switch.js +208 -173
  113. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  114. package/tests/hydration/compiled/client/try.js +29 -21
  115. package/tests/hydration/compiled/server/basic.js +210 -221
  116. package/tests/hydration/compiled/server/composite.js +13 -14
  117. package/tests/hydration/compiled/server/for.js +427 -444
  118. package/tests/hydration/compiled/server/head.js +199 -189
  119. package/tests/hydration/compiled/server/html.js +33 -41
  120. package/tests/hydration/compiled/server/if-children.js +114 -117
  121. package/tests/hydration/compiled/server/if.js +77 -83
  122. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  123. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  124. package/tests/hydration/compiled/server/reactivity.js +24 -22
  125. package/tests/hydration/compiled/server/return.js +6 -18
  126. package/tests/hydration/compiled/server/switch.js +179 -176
  127. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  128. package/tests/hydration/compiled/server/try.js +31 -35
  129. package/tests/hydration/components/basic.tsrx +216 -258
  130. package/tests/hydration/components/composite.tsrx +32 -42
  131. package/tests/hydration/components/events.tsrx +81 -101
  132. package/tests/hydration/components/for.tsrx +270 -336
  133. package/tests/hydration/components/head.tsrx +43 -39
  134. package/tests/hydration/components/hmr.tsrx +16 -22
  135. package/tests/hydration/components/html-in-template.tsrx +15 -21
  136. package/tests/hydration/components/html.tsrx +442 -526
  137. package/tests/hydration/components/if-children.tsrx +107 -125
  138. package/tests/hydration/components/if.tsrx +68 -90
  139. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  140. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  141. package/tests/hydration/components/portal.tsrx +33 -41
  142. package/tests/hydration/components/reactivity.tsrx +26 -34
  143. package/tests/hydration/components/return.tsrx +4 -6
  144. package/tests/hydration/components/switch.tsrx +73 -78
  145. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  146. package/tests/hydration/components/try.tsrx +37 -51
  147. package/tests/hydration/switch.test.js +8 -8
  148. package/tests/server/await.test.tsrx +3 -3
  149. package/tests/server/basic.attributes.test.tsrx +117 -162
  150. package/tests/server/basic.components.test.tsrx +164 -194
  151. package/tests/server/basic.test.tsrx +299 -199
  152. package/tests/server/compiler.test.tsrx +142 -72
  153. package/tests/server/composite.props.test.tsrx +54 -58
  154. package/tests/server/composite.test.tsrx +165 -167
  155. package/tests/server/context.test.tsrx +13 -17
  156. package/tests/server/dynamic-elements.test.tsrx +147 -148
  157. package/tests/server/for.test.tsrx +115 -84
  158. package/tests/server/head.test.tsrx +54 -31
  159. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  160. package/tests/server/if.test.tsrx +49 -59
  161. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  162. package/tests/server/return.test.tsrx +58 -36
  163. package/tests/server/streaming-ssr.test.tsrx +4 -4
  164. package/tests/server/style-identifier.test.tsrx +61 -69
  165. package/tests/server/switch.test.tsrx +89 -97
  166. package/tests/server/track-async-serialization.test.tsrx +85 -103
  167. package/tests/server/try.test.tsrx +275 -360
  168. package/tests/utils/ref-types.test.js +72 -0
  169. package/tests/utils/vite-plugin-config.test.js +41 -74
  170. package/types/index.d.ts +29 -4
  171. package/src/runtime/internal/client/compat.js +0 -40
  172. package/tests/utils/compiler-compat-config.test.js +0 -38
@@ -1,19 +1,17 @@
1
- export function GuardReturnRenders() {
1
+ export function GuardReturnRenders() @{
2
2
  const ready = true;
3
3
  if (!ready) {
4
4
  return null;
5
5
  }
6
-
7
- return <><div class="ready">{'ready'}</div></>;
6
+ <div class="ready">{'ready'}</div>
8
7
  }
9
8
 
10
- export function GuardReturnNull() {
9
+ export function GuardReturnNull() @{
11
10
  const ready = false;
12
11
  if (!ready) {
13
12
  return null;
14
13
  }
15
-
16
- return <><div class="ready">{'ready'}</div></>;
14
+ <div class="ready">{'ready'}</div>
17
15
  }
18
16
 
19
17
  export function StringReturn() {
@@ -1,24 +1,23 @@
1
1
  import { track } from 'ripple';
2
2
 
3
- export function SwitchStatic() {
4
- return <>
5
- const status: string = 'success';
6
- switch (status) {
7
- case 'success':
8
- <div class="status-success">{'Success'}</div>
9
- break;
10
- case 'error':
11
- <div class="status-error">{'Error'}</div>
12
- break;
13
- default:
14
- <div class="status-unknown">{'Unknown'}</div>
3
+ export function SwitchStatic() @{
4
+ const status: string = 'success';
5
+ @switch (status) {
6
+ @case 'success': {
7
+ <div class="status-success">{'Success'}</div>
15
8
  }
16
- </>;
9
+ @case 'error': {
10
+ <div class="status-error">{'Error'}</div>
11
+ }
12
+ @default: {
13
+ <div class="status-unknown">{'Unknown'}</div>
14
+ }
15
+ }
17
16
  }
18
17
 
19
- export function SwitchReactive() {
20
- return <>
21
- let &[status] = track<'a' | 'b' | 'c'>('a');
18
+ export function SwitchReactive() @{
19
+ let &[status] = track<'a' | 'b' | 'c'>('a');
20
+ <>
22
21
  <button
23
22
  class="toggle"
24
23
  onClick={() => {
@@ -26,39 +25,38 @@ export function SwitchReactive() {
26
25
  else if (status === 'b') status = 'c';
27
26
  else status = 'a';
28
27
  }}
29
- >
30
- {'Toggle'}
31
- </button>
32
- switch (status) {
33
- case 'a':
34
- <div class="case-a">{'Case A'}</div>
35
- break;
36
- case 'b':
37
- <div class="case-b">{'Case B'}</div>
38
- break;
39
- default:
28
+ >{'Toggle'}</button>
29
+ @switch (status) {
30
+ @case 'a': {
31
+ <div class="case-a">Case A</div>
32
+ }
33
+ @case 'b': {
34
+ <div class="case-b">Case B</div>
35
+ }
36
+ @default: {
40
37
  <div class="case-c">{'Case C'}</div>
38
+ }
41
39
  }
42
- </>;
40
+ </>
43
41
  }
44
42
 
45
- export function SwitchFallthrough() {
46
- return <>
47
- const val: number = 1;
48
- switch (val) {
49
- case 1:
50
- case 2:
51
- <div class="case-1-2">{'1 or 2'}</div>
52
- break;
53
- default:
54
- <div class="case-other">{'Other'}</div>
43
+ export function SwitchFallthrough() @{
44
+ const val: number = 1;
45
+ @switch (val) {
46
+ @case 1: {
47
+ }
48
+ @case 2: {
49
+ <div class="case-1-2">{'1 or 2'}</div>
50
+ }
51
+ @default: {
52
+ <div class="case-other">{'Other'}</div>
55
53
  }
56
- </>;
54
+ }
57
55
  }
58
56
 
59
- export function SwitchNumericLevels() {
60
- return <>
61
- let &[level] = track<1 | 2 | 3>(1);
57
+ export function SwitchNumericLevels() @{
58
+ let &[level] = track<1 | 2 | 3>(1);
59
+ <>
62
60
  <button
63
61
  class="level-toggle"
64
62
  onClick={() => {
@@ -66,26 +64,24 @@ export function SwitchNumericLevels() {
66
64
  else if (level === 2) level = 3;
67
65
  else level = 1;
68
66
  }}
69
- >
70
- {'Toggle Level'}
71
- </button>
72
- switch (level) {
73
- case 1:
67
+ >{'Toggle Level'}</button>
68
+ @switch (level) {
69
+ @case 1: {
74
70
  <div class="level-1">{'Level 1'}</div>
75
- break;
76
- case 2:
71
+ }
72
+ @case 2: {
77
73
  <div class="level-2">{'Level 2'}</div>
78
- break;
79
- case 3:
74
+ }
75
+ @case 3: {
80
76
  <div class="level-3">{'Level 3'}</div>
81
- break;
77
+ }
82
78
  }
83
- </>;
79
+ </>
84
80
  }
85
81
 
86
- export function SwitchBlockScoped() {
87
- return <>
88
- let &[level] = track<1 | 2 | 3>(1);
82
+ export function SwitchBlockScoped() @{
83
+ let &[level] = track<1 | 2 | 3>(1);
84
+ <>
89
85
  <button
90
86
  class="block-toggle"
91
87
  onClick={() => {
@@ -93,26 +89,24 @@ export function SwitchBlockScoped() {
93
89
  else if (level === 2) level = 3;
94
90
  else level = 1;
95
91
  }}
96
- >
97
- {'Toggle'}
98
- </button>
99
- switch (level) {
100
- case 1:
92
+ >{'Toggle'}</button>
93
+ @switch (level) {
94
+ @case 1: {
101
95
  <div class="block-1">{'Block 1'}</div>
102
- break;
103
- case 2:
96
+ }
97
+ @case 2: {
104
98
  <div class="block-2">{'Block 2'}</div>
105
- break;
106
- case 3:
99
+ }
100
+ @case 3: {
107
101
  <div class="block-3">{'Block 3'}</div>
108
- break;
102
+ }
109
103
  }
110
- </>;
104
+ </>
111
105
  }
112
106
 
113
- export function SwitchNoBreak() {
114
- return <>
115
- let &[level] = track<1 | 2 | 3>(1);
107
+ export function SwitchNoBreak() @{
108
+ let &[level] = track<1 | 2 | 3>(1);
109
+ <>
116
110
  <button
117
111
  class="nobreak-toggle"
118
112
  onClick={() => {
@@ -120,16 +114,17 @@ export function SwitchNoBreak() {
120
114
  else if (level === 2) level = 3;
121
115
  else level = 1;
122
116
  }}
123
- >
124
- {'Toggle'}
125
- </button>
126
- switch (level) {
127
- case 1:
117
+ >{'Toggle'}</button>
118
+ @switch (level) {
119
+ @case 1: {
128
120
  <div class="nobreak-1">{'NoBreak 1'}</div>
129
- case 2:
121
+ }
122
+ @case 2: {
130
123
  <div class="nobreak-2">{'NoBreak 2'}</div>
131
- case 3:
124
+ }
125
+ @case 3: {
132
126
  <div class="nobreak-3">{'NoBreak 3'}</div>
127
+ }
133
128
  }
134
- </>;
129
+ </>
135
130
  }
@@ -8,127 +8,117 @@ module server {
8
8
 
9
9
  import { formatValue } from server;
10
10
 
11
- export function AsyncWithServerCall() {
12
- return <>
13
- let &[count] = track(0);
11
+ function ServerCallResult({ count }: { count: { value: number } }) @{
12
+ let &[data] = trackAsync(() => formatValue(count.value));
13
+ <p class="result">{data}</p>
14
+ }
15
+
16
+ export function AsyncWithServerCall() @{
17
+ let &[count, count_ref] = track(0);
18
+ <>
14
19
  <button
15
20
  class="increment"
16
21
  onClick={() => {
17
22
  count++;
18
23
  }}
19
- >
20
- {'increment'}
21
- </button>
22
- try {
23
- let &[data] = trackAsync(() => formatValue(count));
24
- <p class="result">{data}</p>
25
- } pending {
24
+ >{'increment'}</button>
25
+ @try {
26
+ <ServerCallResult count={count_ref} />
27
+ } @pending {
26
28
  <p class="loading">{'loading...'}</p>
27
29
  }
28
- </>;
30
+ </>
29
31
  }
30
32
 
31
- export function AsyncSimpleValue() {
32
- return <>
33
- try {
34
- let &[data] = trackAsync(() => Promise.resolve('hydrated value'));
35
- <p class="result">{data}</p>
36
- } pending {
37
- <p class="loading">{'loading...'}</p>
38
- }
39
- </>;
33
+ export function AsyncSimpleValue() @{
34
+ @try {
35
+ let &[data] = trackAsync(() => Promise.resolve('hydrated value'));
36
+ <p class="result">{data}</p>
37
+ } @pending {
38
+ <p class="loading">{'loading...'}</p>
39
+ }
40
40
  }
41
41
 
42
- export function AsyncNumericValue() {
43
- return <>
44
- try {
45
- let &[count] = trackAsync(() => Promise.resolve(42));
46
- <span class="count">{count}</span>
47
- } pending {
48
- <span class="pending">{'...'}</span>
49
- }
50
- </>;
42
+ export function AsyncNumericValue() @{
43
+ @try {
44
+ let &[count] = trackAsync(() => Promise.resolve(42));
45
+ <span class="count">{count}</span>
46
+ } @pending {
47
+ <span class="pending">{'...'}</span>
48
+ }
51
49
  }
52
50
 
53
- export function AsyncObjectValue() {
54
- return <>
55
- try {
56
- let &[user] = trackAsync(() => Promise.resolve({ name: 'Alice', age: 30 }));
57
- <div class="user">
58
- <span class="name">{user.name}</span>
59
- <span class="age">{user.age}</span>
60
- </div>
61
- } pending {
62
- <div class="loading">{'loading user...'}</div>
63
- }
64
- </>;
51
+ export function AsyncObjectValue() @{
52
+ @try {
53
+ let &[user] = trackAsync(() => Promise.resolve({ name: 'Alice', age: 30 }));
54
+ <div class="user">
55
+ <span class="name">{user.name}</span>
56
+ <span class="age">{user.age}</span>
57
+ </div>
58
+ } @pending {
59
+ <div class="loading">{'loading user...'}</div>
60
+ }
65
61
  }
66
62
 
67
- export function AsyncMultipleValues() {
68
- return <>
69
- try {
70
- let &[first] = trackAsync(() => Promise.resolve('alpha'));
71
- let &[second] = trackAsync(() => Promise.resolve('beta'));
72
- <div class="multi">
73
- <span class="first">{first}</span>
74
- <span class="second">{second}</span>
75
- </div>
76
- } pending {
77
- <div class="loading">{'loading...'}</div>
78
- }
79
- </>;
63
+ export function AsyncMultipleValues() @{
64
+ @try {
65
+ let &[first] = trackAsync(() => Promise.resolve('alpha'));
66
+ let &[second] = trackAsync(() => Promise.resolve('beta'));
67
+ <div class="multi">
68
+ <span class="first">{first}</span>
69
+ <span class="second">{second}</span>
70
+ </div>
71
+ } @pending {
72
+ <div class="loading">{'loading...'}</div>
73
+ }
80
74
  }
81
75
 
82
- export function AsyncWithCatch() {
83
- return <>
84
- try {
85
- let &[data] = trackAsync(() => Promise.reject(new Error('fetch failed')));
86
- <p class="result">{data}</p>
87
- } pending {
88
- <p class="loading">{'loading...'}</p>
89
- } catch (e) {
90
- <p class="error">{(e as Error).message}</p>
91
- }
92
- </>;
76
+ export function AsyncWithCatch() @{
77
+ @try {
78
+ let &[data] = trackAsync(() => Promise.reject(new Error('fetch failed')));
79
+ <p class="result">{data}</p>
80
+ } @pending {
81
+ <p class="loading">{'loading...'}</p>
82
+ } @catch (e) {
83
+ <p class="error">{(e as Error).message}</p>
84
+ }
93
85
  }
94
86
 
95
- export function ChildWithError() {
96
- return <>
97
- try {
98
- let &[data] = trackAsync(() => Promise.reject(new Error('child error')));
99
- <p class="result">{data}</p>
100
- } pending {
101
- <p class="pending">{'loading...'}</p>
102
- }
103
- </>;
87
+ export function ChildWithError() @{
88
+ @try {
89
+ let &[data] = trackAsync(() => Promise.reject(new Error('child error')));
90
+ <p class="result">{data}</p>
91
+ } @pending {
92
+ <p class="pending">{'loading...'}</p>
93
+ }
104
94
  }
105
95
 
106
- export function ParentWithCatch() {
107
- return <>
108
- try {
109
- <ChildWithError />
110
- } catch (e) {
111
- <p class="parent-error">{(e as Error).message}</p>
112
- }
113
- </>;
96
+ export function ParentWithCatch() @{
97
+ @try {
98
+ <ChildWithError />
99
+ } @catch (e) {
100
+ <p class="parent-error">{(e as Error).message}</p>
101
+ }
102
+ }
103
+
104
+ function ReactiveDependencyResult({ count }: { count: { value: number } }) @{
105
+ let &[data] = trackAsync(() => Promise.resolve(`count-${count.value}`));
106
+ <p class="result">{data}</p>
114
107
  }
115
108
 
116
- export function AsyncWithReactiveDependency() {
117
- return <>
118
- let &[count] = track(0);
109
+ export function AsyncWithReactiveDependency() @{
110
+ let &[count, count_ref] = track(0);
111
+ <>
119
112
  <button
120
113
  class="increment"
121
114
  onClick={() => {
122
115
  count++;
123
116
  }}
124
- >
125
- {'increment'}
126
- </button>
127
- try {
128
- let &[data] = trackAsync(() => Promise.resolve(`count-${count}`));
129
- <p class="result">{data}</p>
130
- } pending {
117
+ >{'increment'}</button>
118
+ @try {
119
+ <ReactiveDependencyResult count={count_ref} />
120
+ } @pending {
131
121
  <p class="loading">{'loading...'}</p>
132
122
  }
133
- </>;
123
+ </>
134
124
  }
@@ -1,74 +1,60 @@
1
1
  import { trackAsync } from 'ripple';
2
2
 
3
- export function RootPending() {
4
- return <><p class="root-pending">{'root loading...'}</p></>;
3
+ export function RootPending() @{
4
+ <p class="root-pending">{'root loading...'}</p>
5
5
  }
6
6
 
7
- export function RootCatch({ error, reset }: { error: Error; reset: () => void }) {
8
- return <>
9
- <section class="root-catch">
10
- <p class="root-error">{error.message}</p>
11
- <button class="root-reset" onClick={reset}>{'retry'}</button>
12
- </section>
13
- </>;
7
+ export function RootCatch({ error, reset }: { error: Error; reset: () => void }) @{
8
+ <section class="root-catch">
9
+ <p class="root-error">{error.message}</p>
10
+ <button class="root-reset" onClick={reset}>{'retry'}</button>
11
+ </section>
14
12
  }
15
13
 
16
- export function RootThrows() {
17
- return <>
18
- throw new Error('root exploded');
19
- <p>{'should not render'}</p>
20
- </>;
14
+ export function RootThrows() @{
15
+ throw new Error('root exploded');
16
+ <p>{'should not render'}</p>
21
17
  }
22
18
 
23
- export function RootAsyncDirect() {
24
- return <>
25
- let &[value] = trackAsync(() => Promise.resolve('root async value'));
26
- <p class="root-async-value">{value}</p>
27
- </>;
19
+ export function RootAsyncDirect() @{
20
+ let &[value] = trackAsync(() => Promise.resolve('root async value'));
21
+ <p class="root-async-value">{value}</p>
28
22
  }
29
23
 
30
- export function RootAsyncRejects() {
31
- return <>
32
- let &[value] = trackAsync(() => Promise.reject(new Error('root async failed')));
33
- <p class="root-async-value">{value}</p>
34
- </>;
24
+ export function RootAsyncRejects() @{
25
+ let &[value] = trackAsync(() => Promise.reject(new Error('root async failed')));
26
+ <p class="root-async-value">{value}</p>
35
27
  }
36
28
 
37
- export function AsyncListInTryPending() {
38
- return <>
39
- try {
40
- <AsyncList />
41
- } pending {
42
- <p class="loading">{'loading...'}</p>
43
- }
44
- </>;
29
+ export function AsyncListInTryPending() @{
30
+ @try {
31
+ <AsyncList />
32
+ } @pending {
33
+ <p class="loading">{'loading...'}</p>
34
+ }
45
35
  }
46
36
 
47
- function AsyncList() {
48
- return <>
49
- let &[items] = trackAsync(() => Promise.resolve(['alpha', 'beta', 'gamma']));
50
- <ul class="items">
51
- for (let item of items) {
52
- <li>{item}</li>
53
- }
54
- </ul>
55
- </>;
37
+ function AsyncList() @{
38
+ let &[items] = trackAsync(() => Promise.resolve(['alpha', 'beta', 'gamma']));
39
+ <ul class="items">
40
+ @for (let item of items) {
41
+ <li>{item}</li>
42
+ }
43
+ </ul>
56
44
  }
57
45
 
58
- export function AsyncTryWithLeadingSibling() {
59
- return <>
46
+ export function AsyncTryWithLeadingSibling() @{
47
+ <>
60
48
  <div class="before">{'before'}</div>
61
- try {
49
+ @try {
62
50
  <AsyncContent />
63
- } pending {
51
+ } @pending {
64
52
  <div class="loading">{'loading async content'}</div>
65
53
  }
66
- </>;
54
+ </>
67
55
  }
68
56
 
69
- function AsyncContent() {
70
- return <>
71
- let &[value] = trackAsync(() => Promise.resolve('ready'));
72
- <div class="resolved">{value}</div>
73
- </>;
57
+ function AsyncContent() @{
58
+ let &[value] = trackAsync(() => Promise.resolve('ready'));
59
+ <div class="resolved">{value}</div>
74
60
  }
@@ -35,9 +35,9 @@ describe('hydration > switch blocks', () => {
35
35
  expect(container.querySelector('.case-a')?.textContent).toBe('Case A');
36
36
  });
37
37
 
38
- it('hydrates switch block with fallthrough', async () => {
38
+ it('hydrates switch block with an isolated empty case', async () => {
39
39
  await hydrateComponent(ServerComponents.SwitchFallthrough, ClientComponents.SwitchFallthrough);
40
- expect(container.querySelector('.case-1-2')?.textContent).toBe('1 or 2');
40
+ expect(container.querySelector('.case-1-2')).toBeNull();
41
41
  });
42
42
 
43
43
  it('hydrates reactive switch block with numeric cases', async () => {
@@ -65,11 +65,11 @@ describe('hydration > switch blocks', () => {
65
65
  expect(container.querySelector('.level-1')?.textContent).toBe('Level 1');
66
66
  });
67
67
 
68
- it('hydrates switch block with block-scoped cases and break', async () => {
68
+ it('hydrates switch block with isolated block-scoped cases', async () => {
69
69
  await hydrateComponent(ServerComponents.SwitchBlockScoped, ClientComponents.SwitchBlockScoped);
70
70
  const button = container.querySelector('.block-toggle');
71
71
 
72
- // Each case should render exclusively with break
72
+ // Each case renders exclusively without requiring a break statement.
73
73
  expect(container.querySelector('.block-1')?.textContent).toBe('Block 1');
74
74
  expect(container.querySelector('.block-2')).toBeNull();
75
75
  expect(container.querySelector('.block-3')).toBeNull();
@@ -86,19 +86,19 @@ describe('hydration > switch blocks', () => {
86
86
  expect(container.querySelector('.block-3')?.textContent).toBe('Block 3');
87
87
  });
88
88
 
89
- it('hydrates switch block without break statements (fallthrough)', async () => {
89
+ it('hydrates switch block without fallthrough', async () => {
90
90
  await hydrateComponent(ServerComponents.SwitchNoBreak, ClientComponents.SwitchNoBreak);
91
91
  const button = container.querySelector('.nobreak-toggle');
92
92
 
93
93
  expect(container.querySelector('.nobreak-1')?.textContent).toBe('NoBreak 1');
94
- expect(container.querySelector('.nobreak-2')?.textContent).toBe('NoBreak 2');
95
- expect(container.querySelector('.nobreak-3')?.textContent).toBe('NoBreak 3');
94
+ expect(container.querySelector('.nobreak-2')).toBeNull();
95
+ expect(container.querySelector('.nobreak-3')).toBeNull();
96
96
 
97
97
  button?.click();
98
98
  flushSync();
99
99
  expect(container.querySelector('.nobreak-1')).toBeNull();
100
100
  expect(container.querySelector('.nobreak-2')?.textContent).toBe('NoBreak 2');
101
- expect(container.querySelector('.nobreak-3')?.textContent).toBe('NoBreak 3');
101
+ expect(container.querySelector('.nobreak-3')).toBeNull();
102
102
 
103
103
  button?.click();
104
104
  flushSync();
@@ -6,7 +6,7 @@ describe('await in control flow', () => {
6
6
  });
7
7
 
8
8
  // it('should handle await inside if statement', async () => {
9
- // function App() { return <>
9
+ // function App() @{
10
10
  // let condition = true;
11
11
  // let &[data] = track('loading');
12
12
 
@@ -25,7 +25,7 @@ describe('await in control flow', () => {
25
25
  // });
26
26
 
27
27
  // it('should handle await inside for...of loop', async () => {
28
- // function App() { return <>
28
+ // function App() @{
29
29
  // const items = [1, 2, 3];
30
30
  // let result = '';
31
31
 
@@ -42,7 +42,7 @@ describe('await in control flow', () => {
42
42
  // });
43
43
 
44
44
  // it('should handle await inside switch statement', async () => {
45
- // function App() { return <>
45
+ // function App() @{
46
46
  // let value = 'b';
47
47
 
48
48
  // switch (value) {