ripple 0.3.71 → 0.3.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/package.json +3 -3
  3. package/src/jsx-runtime.d.ts +2 -8
  4. package/src/runtime/index-client.js +3 -13
  5. package/src/runtime/internal/client/blocks.js +3 -25
  6. package/src/runtime/internal/client/for.js +80 -5
  7. package/src/runtime/internal/client/index.js +0 -2
  8. package/src/runtime/internal/client/types.d.ts +0 -10
  9. package/tests/client/__snapshots__/computed-properties.test.tsrx.snap +8 -0
  10. package/tests/client/__snapshots__/for.test.tsrx.snap +22 -0
  11. package/tests/client/__snapshots__/html.test.tsrx.snap +4 -0
  12. package/tests/client/array/array.copy-within.test.tsrx +19 -19
  13. package/tests/client/array/array.derived.test.tsrx +97 -109
  14. package/tests/client/array/array.iteration.test.tsrx +28 -28
  15. package/tests/client/array/array.mutations.test.tsrx +68 -68
  16. package/tests/client/array/array.static.test.tsrx +82 -92
  17. package/tests/client/array/array.to-methods.test.tsrx +15 -15
  18. package/tests/client/async-suspend.test.tsrx +180 -179
  19. package/tests/client/basic/__snapshots__/basic.attributes.test.tsrx.snap +2 -0
  20. package/tests/client/basic/__snapshots__/basic.rendering.test.tsrx.snap +4 -0
  21. package/tests/client/basic/basic.attributes.test.tsrx +273 -317
  22. package/tests/client/basic/basic.collections.test.tsrx +59 -71
  23. package/tests/client/basic/basic.components.test.tsrx +196 -222
  24. package/tests/client/basic/basic.errors.test.tsrx +72 -78
  25. package/tests/client/basic/basic.events.test.tsrx +80 -85
  26. package/tests/client/basic/basic.get-set.test.tsrx +54 -64
  27. package/tests/client/basic/basic.hmr.test.tsrx +15 -19
  28. package/tests/client/basic/basic.reactivity.test.tsrx +121 -135
  29. package/tests/client/basic/basic.rendering.test.tsrx +273 -178
  30. package/tests/client/basic/basic.utilities.test.tsrx +8 -10
  31. package/tests/client/boundaries.test.tsrx +18 -18
  32. package/tests/client/compiler/compiler.assignments.test.tsrx +77 -76
  33. package/tests/client/compiler/compiler.attributes.test.tsrx +18 -14
  34. package/tests/client/compiler/compiler.basic.test.tsrx +364 -296
  35. package/tests/client/compiler/compiler.regex.test.tsrx +40 -44
  36. package/tests/client/compiler/compiler.tracked-access.test.tsrx +57 -38
  37. package/tests/client/compiler/compiler.try-in-function.test.tsrx +16 -16
  38. package/tests/client/compiler/compiler.typescript.test.tsrx +4 -3
  39. package/tests/client/composite/composite.dynamic-components.test.tsrx +41 -44
  40. package/tests/client/composite/composite.generics.test.tsrx +165 -167
  41. package/tests/client/composite/composite.props.test.tsrx +66 -74
  42. package/tests/client/composite/composite.reactivity.test.tsrx +132 -166
  43. package/tests/client/composite/composite.render.test.tsrx +92 -101
  44. package/tests/client/computed-properties.test.tsrx +14 -18
  45. package/tests/client/context.test.tsrx +14 -18
  46. package/tests/client/css/global-additional-cases.test.tsrx +491 -437
  47. package/tests/client/css/global-advanced-selectors.test.tsrx +169 -153
  48. package/tests/client/css/global-at-rules.test.tsrx +71 -66
  49. package/tests/client/css/global-basic.test.tsrx +105 -98
  50. package/tests/client/css/global-classes-ids.test.tsrx +128 -114
  51. package/tests/client/css/global-combinators.test.tsrx +83 -78
  52. package/tests/client/css/global-complex-nesting.test.tsrx +134 -120
  53. package/tests/client/css/global-edge-cases.test.tsrx +138 -120
  54. package/tests/client/css/global-keyframes.test.tsrx +108 -96
  55. package/tests/client/css/global-nested.test.tsrx +88 -78
  56. package/tests/client/css/global-pseudo.test.tsrx +104 -98
  57. package/tests/client/css/global-scoping.test.tsrx +145 -125
  58. package/tests/client/css/style-identifier.test.tsrx +62 -69
  59. package/tests/client/date.test.tsrx +83 -83
  60. package/tests/client/dynamic-elements.test.tsrx +227 -283
  61. package/tests/client/events.test.tsrx +252 -266
  62. package/tests/client/for.test.tsrx +120 -127
  63. package/tests/client/head.test.tsrx +40 -48
  64. package/tests/client/html.test.tsrx +37 -49
  65. package/tests/client/input-value.test.tsrx +1125 -1354
  66. package/tests/client/lazy-array.test.tsrx +10 -16
  67. package/tests/client/lazy-destructuring.test.tsrx +169 -221
  68. package/tests/client/map.test.tsrx +39 -41
  69. package/tests/client/media-query.test.tsrx +15 -19
  70. package/tests/client/object.test.tsrx +46 -56
  71. package/tests/client/portal.test.tsrx +31 -37
  72. package/tests/client/ref.test.tsrx +173 -193
  73. package/tests/client/return.test.tsrx +62 -37
  74. package/tests/client/set.test.tsrx +33 -33
  75. package/tests/client/svg.test.tsrx +195 -215
  76. package/tests/client/switch.test.tsrx +201 -191
  77. package/tests/client/track-async-hydration.test.tsrx +14 -18
  78. package/tests/client/tracked-index-access.test.tsrx +18 -28
  79. package/tests/client/try.test.tsrx +494 -619
  80. package/tests/client/tsx.test.tsrx +290 -371
  81. package/tests/client/typescript-generics.test.tsrx +121 -129
  82. package/tests/client/url/url.derived.test.tsrx +21 -25
  83. package/tests/client/url/url.parsing.test.tsrx +35 -35
  84. package/tests/client/url/url.partial-removal.test.tsrx +32 -32
  85. package/tests/client/url/url.reactivity.test.tsrx +68 -72
  86. package/tests/client/url/url.serialization.test.tsrx +8 -8
  87. package/tests/client/url-search-params/url-search-params.derived.test.tsrx +21 -27
  88. package/tests/client/url-search-params/url-search-params.initialization.test.tsrx +16 -16
  89. package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +37 -37
  90. package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +56 -60
  91. package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +32 -34
  92. package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +9 -9
  93. package/tests/client/url-search-params/url-search-params.tracked-url.test.tsrx +10 -10
  94. package/tests/hydration/compiled/client/basic.js +396 -325
  95. package/tests/hydration/compiled/client/composite.js +52 -44
  96. package/tests/hydration/compiled/client/for.js +734 -604
  97. package/tests/hydration/compiled/client/head.js +183 -103
  98. package/tests/hydration/compiled/client/html.js +93 -86
  99. package/tests/hydration/compiled/client/if-children.js +95 -71
  100. package/tests/hydration/compiled/client/if.js +113 -89
  101. package/tests/hydration/compiled/client/mixed-control-flow.js +225 -209
  102. package/tests/hydration/compiled/client/nested-control-flow.js +94 -98
  103. package/tests/hydration/compiled/client/reactivity.js +26 -24
  104. package/tests/hydration/compiled/client/return.js +8 -42
  105. package/tests/hydration/compiled/client/switch.js +208 -173
  106. package/tests/hydration/compiled/client/track-async-serialization.js +176 -128
  107. package/tests/hydration/compiled/client/try.js +29 -21
  108. package/tests/hydration/compiled/server/basic.js +210 -221
  109. package/tests/hydration/compiled/server/composite.js +13 -14
  110. package/tests/hydration/compiled/server/for.js +427 -444
  111. package/tests/hydration/compiled/server/head.js +199 -189
  112. package/tests/hydration/compiled/server/html.js +33 -41
  113. package/tests/hydration/compiled/server/if-children.js +114 -117
  114. package/tests/hydration/compiled/server/if.js +77 -83
  115. package/tests/hydration/compiled/server/mixed-control-flow.js +145 -150
  116. package/tests/hydration/compiled/server/nested-control-flow.js +10 -0
  117. package/tests/hydration/compiled/server/reactivity.js +24 -22
  118. package/tests/hydration/compiled/server/return.js +6 -18
  119. package/tests/hydration/compiled/server/switch.js +179 -176
  120. package/tests/hydration/compiled/server/track-async-serialization.js +88 -70
  121. package/tests/hydration/compiled/server/try.js +31 -35
  122. package/tests/hydration/components/basic.tsrx +216 -286
  123. package/tests/hydration/components/composite.tsrx +32 -42
  124. package/tests/hydration/components/events.tsrx +81 -101
  125. package/tests/hydration/components/for.tsrx +270 -336
  126. package/tests/hydration/components/head.tsrx +43 -39
  127. package/tests/hydration/components/hmr.tsrx +16 -22
  128. package/tests/hydration/components/html-in-template.tsrx +15 -21
  129. package/tests/hydration/components/html.tsrx +442 -526
  130. package/tests/hydration/components/if-children.tsrx +107 -125
  131. package/tests/hydration/components/if.tsrx +68 -90
  132. package/tests/hydration/components/mixed-control-flow.tsrx +65 -72
  133. package/tests/hydration/components/nested-control-flow.tsrx +202 -216
  134. package/tests/hydration/components/portal.tsrx +33 -41
  135. package/tests/hydration/components/reactivity.tsrx +26 -34
  136. package/tests/hydration/components/return.tsrx +4 -6
  137. package/tests/hydration/components/switch.tsrx +73 -78
  138. package/tests/hydration/components/track-async-serialization.tsrx +83 -93
  139. package/tests/hydration/components/try.tsrx +37 -51
  140. package/tests/hydration/switch.test.js +8 -8
  141. package/tests/server/await.test.tsrx +3 -3
  142. package/tests/server/basic.attributes.test.tsrx +120 -167
  143. package/tests/server/basic.components.test.tsrx +163 -197
  144. package/tests/server/basic.test.tsrx +298 -220
  145. package/tests/server/compiler.test.tsrx +142 -72
  146. package/tests/server/composite.props.test.tsrx +54 -58
  147. package/tests/server/composite.test.tsrx +165 -167
  148. package/tests/server/context.test.tsrx +13 -17
  149. package/tests/server/dynamic-elements.test.tsrx +103 -135
  150. package/tests/server/for.test.tsrx +115 -84
  151. package/tests/server/head.test.tsrx +31 -31
  152. package/tests/server/html-nesting-validation.test.tsrx +16 -8
  153. package/tests/server/if.test.tsrx +49 -59
  154. package/tests/server/lazy-destructuring.test.tsrx +288 -366
  155. package/tests/server/return.test.tsrx +58 -36
  156. package/tests/server/streaming-ssr.test.tsrx +4 -4
  157. package/tests/server/style-identifier.test.tsrx +58 -66
  158. package/tests/server/switch.test.tsrx +89 -97
  159. package/tests/server/track-async-serialization.test.tsrx +85 -103
  160. package/tests/server/try.test.tsrx +275 -360
  161. package/tests/utils/ref-types.test.js +72 -0
  162. package/tests/utils/vite-plugin-config.test.js +41 -74
  163. package/types/index.d.ts +1 -0
  164. package/src/runtime/internal/client/compat.js +0 -40
  165. package/tests/utils/compiler-compat-config.test.js +0 -38
@@ -1,76 +1,98 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { compile } from '@tsrx/ripple';
3
3
 
4
- const TSRX_RETURN_ERROR = 'Return statements are not allowed inside TSRX templates. Move the return before the TSRX return value, or use conditional rendering instead.';
5
-
6
- describe('returns in prohibited SSR scopes', () => {
7
- it('throws when return is used inside a TSRX fragment', () => {
4
+ describe('returns in restricted SSR scopes', () => {
5
+ it('allows returns inside regular functions declared in TSRX templates', () => {
8
6
  expect(
9
7
  () => compile(
10
8
  `
11
- function App() {
12
- return <>
13
- if (ready) {
14
- return;
9
+ function App() @{
10
+ function label() {
11
+ return 'ready';
15
12
  }
16
- <div>{'ready'}</div>
17
- </>;
13
+ <div>{label()}</div>
18
14
  }
19
15
  `,
20
16
  'test.tsrx',
21
17
  { mode: 'server' },
22
18
  ),
23
- ).toThrow(TSRX_RETURN_ERROR);
19
+ ).not.toThrow();
24
20
  });
25
21
 
26
- it('throws when return is used inside a TSRX element', () => {
22
+ it('compiles template directives inside templates', () => {
27
23
  expect(
28
24
  () => compile(
29
25
  `
30
- function App() {
31
- return <section>
32
- if (ready) {
33
- return null;
34
- }
35
- <div>{'ready'}</div>
36
- </section>;
37
- }
38
- `,
26
+ function App() @{
27
+ <>
28
+ @if (ready) {
29
+ <div>yielded</div>
30
+ }
31
+ <span>after</span>
32
+ </>
33
+ }
34
+ `,
39
35
  'test.tsrx',
40
36
  { mode: 'server' },
41
37
  ),
42
- ).toThrow(TSRX_RETURN_ERROR);
38
+ ).not.toThrow();
43
39
  });
40
+ });
44
41
 
45
- it('allows returns inside regular functions declared in TSRX templates', () => {
42
+ describe('function returns in SSR components', () => {
43
+ it('renders template directive branches alongside outer siblings', async () => {
44
+ function App() @{
45
+ const ready = true;
46
+ <>
47
+ @if (ready) {
48
+ <div class="yielded">yielded</div>
49
+ }
50
+ <span class="outer">outer</span>
51
+ </>
52
+ }
53
+
54
+ const { body } = await render(App);
55
+ expect(body).toBeHtml('<div class="yielded">yielded</div><span class="outer">outer</span>');
56
+ });
57
+
58
+ it('allows plain JavaScript control flow in setup when rendered output follows', () => {
46
59
  expect(
47
60
  () => compile(
48
61
  `
49
- function App() {
50
- return <>
51
- function label() {
52
- return 'ready';
53
- }
54
- <div>{label()}</div>
55
- </>;
56
- }
57
- `,
62
+ function App() @{
63
+ const items = [1, 2, 3];
64
+ for (const item of items) {
65
+ <div>{item}</div>
66
+ }
67
+ }
68
+ `,
58
69
  'test.tsrx',
59
70
  { mode: 'server' },
60
71
  ),
61
72
  ).not.toThrow();
62
73
  });
63
- });
64
74
 
65
- describe('function returns in SSR components', () => {
75
+ it('renders TSRX return arguments and skips later siblings', async () => {
76
+ function App() @{
77
+ const ready = true;
78
+ if (ready) {
79
+ return <div class="returned">returned</div>;
80
+ }
81
+ <span class="after">after</span>
82
+ }
83
+
84
+ const { body } = await render(App);
85
+ expect(body).toBeHtml('<div class="returned">returned</div>');
86
+ });
87
+
66
88
  it('allows guard returns before TSRX output', async () => {
67
- function App() {
89
+ function App() @{
68
90
  const ready = true;
69
91
  if (!ready) {
70
92
  return null;
71
93
  }
72
94
 
73
- return <><div>{'ready'}</div></>;
95
+ <div>{'ready'}</div>
74
96
  }
75
97
 
76
98
  const { body } = await render(App);
@@ -2,8 +2,8 @@ import { create_ssr_stream } from 'ripple/server';
2
2
 
3
3
  describe('create_ssr_stream', () => {
4
4
  it('renders SSR HTML into the injected sink and exposes a web stream', async () => {
5
- function App() {
6
- return <><div>{'Hello, streaming SSR!'}</div></>;
5
+ function App() @{
6
+ <div>{'Hello, streaming SSR!'}</div>
7
7
  }
8
8
 
9
9
  const { stream, sink } = create_ssr_stream();
@@ -16,8 +16,8 @@ describe('create_ssr_stream', () => {
16
16
  });
17
17
 
18
18
  it('closes the public stream when streaming finishes successfully', async () => {
19
- function App() {
20
- return <><p>{'stream closed'}</p></>;
19
+ function App() @{
20
+ <p>{'stream closed'}</p>
21
21
  }
22
22
 
23
23
  const { stream, sink } = create_ssr_stream();
@@ -10,18 +10,18 @@ const external_styles = <style>
10
10
  describe('style class maps (server)', () => {
11
11
  describe('basic usage with components', () => {
12
12
  it('passes scoped classes to a child component via a style expression', async () => {
13
- function Child({ className }: { className: string }) {
14
- return <><div class={className}>{'styled child'}</div></>;
13
+ function Child({ className }: { className: string }) @{
14
+ <div class={className}>{'styled child'}</div>
15
15
  }
16
16
 
17
- function Parent() {
17
+ function Parent() @{
18
18
  const styles = <style>
19
19
  .highlight {
20
20
  color: red;
21
21
  }
22
22
  </style>;
23
23
 
24
- return <><Child className={styles.highlight} /></>;
24
+ <Child className={styles.highlight} />
25
25
  }
26
26
 
27
27
  const { body } = await render(Parent);
@@ -36,14 +36,14 @@ describe('style class maps (server)', () => {
36
36
  });
37
37
 
38
38
  it('passes multiple style expression classes to a child component', async () => {
39
- function Child({ primary, secondary }: { primary: string; secondary: string }) {
40
- return <>
39
+ function Child({ primary, secondary }: { primary: string; secondary: string }) @{
40
+ <>
41
41
  <div class={primary}>{'primary'}</div>
42
42
  <span class={secondary}>{'secondary'}</span>
43
- </>;
43
+ </>
44
44
  }
45
45
 
46
- function Parent() {
46
+ function Parent() @{
47
47
  const styles = <style>
48
48
  .primary {
49
49
  color: blue;
@@ -53,7 +53,7 @@ describe('style class maps (server)', () => {
53
53
  }
54
54
  </style>;
55
55
 
56
- return <><Child primary={styles.primary} secondary={styles.secondary} /></>;
56
+ <Child primary={styles.primary} secondary={styles.secondary} />
57
57
  }
58
58
 
59
59
  const { body } = await render(Parent);
@@ -77,18 +77,18 @@ describe('style class maps (server)', () => {
77
77
 
78
78
  describe('parent styling applied to child', () => {
79
79
  it('allows parent to style child elements via a style expression prop', async () => {
80
- function Button({ extraClass }: { extraClass?: string }) {
81
- return <><button class={extraClass ?? ''}>{'Click me'}</button></>;
80
+ function Button({ extraClass }: { extraClass?: string }) @{
81
+ <button class={extraClass ?? ''}>{'Click me'}</button>
82
82
  }
83
83
 
84
- function App() {
84
+ function App() @{
85
85
  const styles = <style>
86
86
  .fancy {
87
87
  background: gold;
88
88
  }
89
89
  </style>;
90
90
 
91
- return <><Button extraClass={styles.fancy} /></>;
91
+ <Button extraClass={styles.fancy} />
92
92
  }
93
93
 
94
94
  const { body } = await render(App);
@@ -102,25 +102,25 @@ describe('style class maps (server)', () => {
102
102
  });
103
103
 
104
104
  it('child can combine its own classes with a parent style expression class', async () => {
105
- function Card({ className }: { className?: string }) {
106
- return <>
105
+ function Card({ className }: { className?: string }) @{
106
+ <>
107
107
  <div class={['card-base', className ?? '']}>{'card content'}</div>
108
108
  <style>
109
109
  .card-base {
110
110
  border: 1px solid black;
111
111
  }
112
112
  </style>
113
- </>;
113
+ </>
114
114
  }
115
115
 
116
- function App() {
116
+ function App() @{
117
117
  const styles = <style>
118
118
  .themed {
119
119
  background: purple;
120
120
  }
121
121
  </style>;
122
122
 
123
- return <><Card className={styles.themed} /></>;
123
+ <Card className={styles.themed} />
124
124
  }
125
125
 
126
126
  const { body } = await render(App);
@@ -134,11 +134,11 @@ describe('style class maps (server)', () => {
134
134
  });
135
135
 
136
136
  it('passes a standalone class even when it also appears in descendant context', async () => {
137
- function Child({ cls }: { cls: string }) {
138
- return <><span class={cls}>{'text'}</span></>;
137
+ function Child({ cls }: { cls: string }) @{
138
+ <span class={cls}>{'text'}</span>
139
139
  }
140
140
 
141
- function App() {
141
+ function App() @{
142
142
  const styles = <style>
143
143
  .dual {
144
144
  color: blue;
@@ -148,11 +148,9 @@ describe('style class maps (server)', () => {
148
148
  }
149
149
  </style>;
150
150
 
151
- return <>
152
- <div class="parent">
153
- <Child cls={styles.dual} />
154
- </div>
155
- </>;
151
+ <div class="parent">
152
+ <Child cls={styles.dual} />
153
+ </div>
156
154
  }
157
155
 
158
156
  const { body } = await render(App);
@@ -167,23 +165,21 @@ describe('style class maps (server)', () => {
167
165
  });
168
166
 
169
167
  it('passes scoped classes to a dynamic child component via a style expression', async () => {
170
- function Child({ cls }: { cls: string }) {
171
- return <><span class={cls}>{'text'}</span></>;
168
+ function Child({ cls }: { cls: string }) @{
169
+ <span class={cls}>{'text'}</span>
172
170
  }
173
171
 
174
- function Parent() {
172
+ function Parent() @{
175
173
  const styles = <style>
176
174
  .text {
177
175
  color: red;
178
176
  }
179
177
  </style>;
180
178
 
181
- return <>
182
- let dynamic = track(() => Child);
183
- <div class="wrapper">
184
- <@dynamic cls={styles.text} />
185
- </div>
186
- </>;
179
+ let dynamic = track(() => Child);
180
+ <div class="wrapper">
181
+ <@dynamic cls={styles.text} />
182
+ </div>
187
183
  }
188
184
 
189
185
  const { body } = await render(Parent);
@@ -197,12 +193,12 @@ describe('style class maps (server)', () => {
197
193
  });
198
194
 
199
195
  it('passes style expression classes declared outside the component', async () => {
200
- function Child({ cls }: { cls: string }) {
201
- return <><span class={cls}>{'text'}</span></>;
196
+ function Child({ cls }: { cls: string }) @{
197
+ <span class={cls}>{'text'}</span>
202
198
  }
203
199
 
204
- function Parent() {
205
- return <Child cls={external_styles.external} />;
200
+ function Parent() @{
201
+ <Child cls={external_styles.external} />
206
202
  }
207
203
 
208
204
  const { body, css } = await render(Parent);
@@ -219,8 +215,8 @@ describe('style class maps (server)', () => {
219
215
  });
220
216
 
221
217
  it('preserves caller scoped hash through wrapper children', async () => {
222
- function Wrapper({ children }) {
223
- return <>
218
+ function Wrapper({ children }) @{
219
+ <>
224
220
  <div class="green">
225
221
  {'Wrapper'}
226
222
  {children}
@@ -230,26 +226,24 @@ describe('style class maps (server)', () => {
230
226
  color: green;
231
227
  }
232
228
  </style>
233
- </>;
229
+ </>
234
230
  }
235
231
 
236
- function Child() {
237
- return <>
232
+ function Child() @{
233
+ <>
238
234
  <div class="red">{'Child'}</div>
239
235
  <style>
240
236
  .red {
241
237
  color: red;
242
238
  }
243
239
  </style>
244
- </>;
240
+ </>
245
241
  }
246
242
 
247
- function App() {
248
- return <>
249
- <Wrapper>
250
- <Child />
251
- </Wrapper>
252
- </>;
243
+ function App() @{
244
+ <Wrapper>
245
+ <Child />
246
+ </Wrapper>
253
247
  }
254
248
 
255
249
  const { body } = await render(App);
@@ -268,13 +262,13 @@ describe('style class maps (server)', () => {
268
262
  });
269
263
 
270
264
  it('applies caller scoped hash to slotted children through dynamic components', async () => {
271
- function Wrapper({ children }) {
272
- return <><section>{children}</section></>;
265
+ function Wrapper({ children }) @{
266
+ <section>{children}</section>
273
267
  }
274
268
 
275
- function App() {
276
- return <>
277
- const DynamicWrapper = track(() => Wrapper);
269
+ function App() @{
270
+ const DynamicWrapper = track(() => Wrapper);
271
+ <>
278
272
  <@DynamicWrapper>
279
273
  <div class="green">{'Slotted child'}</div>
280
274
  </@DynamicWrapper>
@@ -283,7 +277,7 @@ describe('style class maps (server)', () => {
283
277
  color: green;
284
278
  }
285
279
  </style>
286
- </>;
280
+ </>
287
281
  }
288
282
 
289
283
  const { body } = await render(App);
@@ -299,19 +293,17 @@ describe('style class maps (server)', () => {
299
293
  describe('server compiler output', () => {
300
294
  it('emits style class maps', () => {
301
295
  const source = `
302
- function Child({ cls }: { cls: string }) { return <>
296
+ function Child({ cls }: { cls: string }) @{
303
297
  <div class={cls}>{'text'}</div>
304
- </>; }
305
- export function App() {
298
+ }
299
+ export function App() @{
306
300
  const styles = <style>
307
301
  .highlight {
308
302
  color: red;
309
303
  }
310
304
  </style>;
311
305
 
312
- return <>
313
306
  <Child cls={styles.highlight} />
314
- </>;
315
307
  }`;
316
308
  const { code } = compile(source, 'test.tsrx', { mode: 'server' });
317
309
 
@@ -321,18 +313,18 @@ export function App() {
321
313
  });
322
314
 
323
315
  it('includes CSS hash in rendered HTML', async () => {
324
- function Child({ cls }: { cls: string }) {
325
- return <><div class={cls}>{'hello'}</div></>;
316
+ function Child({ cls }: { cls: string }) @{
317
+ <div class={cls}>{'hello'}</div>
326
318
  }
327
319
 
328
- function App() {
320
+ function App() @{
329
321
  const styles = <style>
330
322
  .styled {
331
323
  font-weight: bold;
332
324
  }
333
325
  </style>;
334
326
 
335
- return <><Child cls={styles.styled} /></>;
327
+ <Child cls={styles.styled} />
336
328
  }
337
329
 
338
330
  const { body, css } = await render(App);
@@ -1,131 +1,123 @@
1
1
  describe('SSR: switch statements', () => {
2
2
  it('renders simple switch with literal cases', async () => {
3
- function App() {
4
- return <>
5
- let value = 'b';
6
- switch (value) {
7
- case 'a':
8
- <div>{'Case A'}</div>
9
- break;
10
- case 'b':
11
- <div>{'Case B'}</div>
12
- break;
13
- case 'c':
14
- <div>{'Case C'}</div>
15
- break;
16
- default:
17
- <div>{'Default Case'}</div>
18
- }
19
- </>;
3
+ function App() @{
4
+ let value = 'b';
5
+ @switch (value) {
6
+ @case 'a': {
7
+ <div>Case A</div>
8
+ }
9
+ @case 'b': {
10
+ <div>Case B</div>
11
+ }
12
+ @case 'c': {
13
+ <div>{'Case C'}</div>
14
+ }
15
+ @default: {
16
+ <div>{'Default Case'}</div>
17
+ }
18
+ }
20
19
  }
21
20
 
22
21
  const { body } = await render(App);
23
22
  expect(body).toBeHtml('<div>Case B</div>');
24
23
  });
25
24
 
26
- it('renders a fall-through with an empty switch case', async () => {
27
- function App() {
28
- return <>
29
- let value = 'b';
30
- switch (value) {
31
- case 'a':
32
- <div>{'Case A'}</div>
33
- break;
34
- case 'b':
35
- case 'c':
36
- <div>{'Case B or C'}</div>
37
- break;
38
- default:
39
- <div>{'Default Case'}</div>
40
- }
41
- </>;
25
+ it('renders an empty switch case without falling through', async () => {
26
+ function App() @{
27
+ let value = 'b';
28
+ @switch (value) {
29
+ @case 'a': {
30
+ <div>Case A</div>
31
+ }
32
+ @case 'b': {
33
+ }
34
+ @case 'c': {
35
+ <div>Case B or C</div>
36
+ }
37
+ @default: {
38
+ <div>{'Default Case'}</div>
39
+ }
40
+ }
42
41
  }
43
42
 
44
43
  const { body } = await render(App);
45
- expect(body).toBeHtml('<div>Case B or C</div>');
44
+ expect(body).toBeHtml('');
46
45
  });
47
46
 
48
- it('renders a fall-through with a case that has elements', async () => {
49
- function App() {
50
- return <>
51
- let value = 'a';
52
- switch (value) {
53
- case 'a':
54
- <div>{'Case A'}</div>
55
- case 'b':
56
- <div>{'Case B'}</div>
57
- case 'c':
58
- <div>{'Case C'}</div>
59
- break;
60
- default:
61
- <div>{'Default Case'}</div>
62
- }
63
- </>;
47
+ it('renders a case with elements without falling through', async () => {
48
+ function App() @{
49
+ let value = 'a';
50
+ @switch (value) {
51
+ @case 'a': {
52
+ <div>Case A</div>
53
+ }
54
+ @case 'b': {
55
+ <div>Case B</div>
56
+ }
57
+ @case 'c': {
58
+ <div>{'Case C'}</div>
59
+ }
60
+ @default: {
61
+ <div>{'Default Case'}</div>
62
+ }
63
+ }
64
64
  }
65
65
 
66
66
  const { body } = await render(App);
67
- expect(body).toBeHtml('<div>Case A</div><div>Case B</div><div>Case C</div>');
67
+ expect(body).toBeHtml('<div>Case A</div>');
68
68
  });
69
69
 
70
- it('renders a fall-through with a default case in the middle', async () => {
71
- function App() {
72
- return <>
73
- let value = 'x';
74
- switch (value) {
75
- case 'a':
76
- <div>{'Case A'}</div>
77
- default:
78
- <div>{'Default Case'}</div>
79
- case 'b':
80
- <div>{'Case B'}</div>
81
- break;
82
- case 'c':
83
- <div>{'Case C'}</div>
84
- break;
85
- }
86
- </>;
70
+ it('renders a default case', async () => {
71
+ function App() @{
72
+ let value = 'x';
73
+ @switch (value) {
74
+ @case 'a': {
75
+ <div>Case A</div>
76
+ }
77
+ @default: {
78
+ <div>{'Default Case'}</div>
79
+ }
80
+ }
87
81
  }
88
82
 
89
83
  const { body } = await render(App);
90
- expect(body).toBeHtml('<div>Default Case</div><div>Case B</div>');
84
+ expect(body).toBeHtml('<div>Default Case</div>');
91
85
  });
92
86
 
93
- it('renders bare text nodes in switch fall-through cases without element wrappers', async () => {
94
- function App() {
95
- return <>
96
- let value = 'a';
97
- <div>
98
- <span>{'before'}</span>
99
- switch (value) {
100
- case 'a':
101
- {'Case A'}
102
- case 'b':
103
- {'Case B'}
87
+ it('renders bare text nodes in switch cases without falling through', async () => {
88
+ function App() @{
89
+ let value = 'a';
90
+ <div>
91
+ <span>{'before'}</span>
92
+ @switch (value) {
93
+ @case 'a': {
94
+ <>Case A</>
95
+ }
96
+ @case 'b': {
97
+ <>Case B</>
104
98
  }
105
- </div>
106
- </>;
99
+ }
100
+ </div>
107
101
  }
108
102
 
109
103
  const { body } = await render(App);
110
- expect(body).toBeHtml('<div><span>before</span>Case ACase B</div>');
104
+ expect(body).toBeHtml('<div><span>before</span>Case A</div>');
111
105
  });
112
106
 
113
107
  it('renders bare text nodes in switch cases without element wrappers', async () => {
114
- function App() {
115
- return <>
116
- let value = 'a';
117
- <div>
118
- <span>{'before'}</span>
119
- switch (value) {
120
- case 'a':
121
- {'Case A'}
122
- break;
123
- case 'b':
124
- {'Case B'}
125
- break;
108
+ function App() @{
109
+ let value = 'a';
110
+ <div>
111
+ <span>{'before'}</span>
112
+ @switch (value) {
113
+ @case 'a': {
114
+ <>Case A</>
126
115
  }
127
- </div>
128
- </>;
116
+ @case 'b': {
117
+ <>Case B</>
118
+ }
119
+ }
120
+ </div>
129
121
  }
130
122
 
131
123
  const { body } = await render(App);