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
@@ -15,9 +15,9 @@ const errorMap = new ErrorMap();`;
15
15
 
16
16
  it('removes type assertions from function parameters and leaves default values', () => {
17
17
  const source = `
18
- function getString(e: string = 'test') {
19
- return e;
20
- }`;
18
+ function getString(e: string = 'test') {
19
+ return e;
20
+ }`;
21
21
 
22
22
  const result = compile(source, 'test.tsrx', { mode: 'server' });
23
23
 
@@ -31,11 +31,11 @@ beforeAll(() => {
31
31
  (global as any).count++;
32
32
  });
33
33
 
34
- function Test() { return <>
35
- let toggle: { value: boolean } | undefined;
36
- toggle!.value = false;
37
- toggle!.value++;
38
- </>; }`;
34
+ function Test() @{
35
+ let toggle: { value: boolean } | undefined;
36
+ toggle!.value = false;
37
+ toggle!.value++;
38
+ }`;
39
39
 
40
40
  const { code } = compile(source, 'test.tsrx', { mode: 'server' });
41
41
 
@@ -50,13 +50,13 @@ function Test() { return <>
50
50
  it(
51
51
  'compiles writes to unknown lazy array index 1 through lazy array helpers in SSR output',
52
52
  () => {
53
- const source = `function Child({ pair: &[first, second] }) { return <>
53
+ const source = `function Child({ pair: &[first, second] }) @{
54
54
  second = 10;
55
55
  <div>{first}</div>
56
- </>; }
57
- function App() { return <>
56
+ }
57
+ function App() @{
58
58
  <Child pair={[0, 1]} />
59
- </>; }`;
59
+ }`;
60
60
  const { code } = compile(source, 'test.tsrx', { mode: 'server' });
61
61
 
62
62
  expect(code).toContain('_$_.lazy_array_set(lazy, 10, 1)');
@@ -65,13 +65,13 @@ function App() { return <>
65
65
  );
66
66
 
67
67
  it('does not double-wrap member access on lazy array value bindings in SSR output', () => {
68
- const source = `function Child({ pair: &[first] }) { return <>
68
+ const source = `function Child({ pair: &[first] }) @{
69
69
  let value = first[0];
70
70
  <div>{value}</div>
71
- </>; }
72
- function App() { return <>
71
+ }
72
+ function App() @{
73
73
  <Child pair={[{ 0: 'x' }]} />
74
- </>; }`;
74
+ }`;
75
75
  const { code } = compile(source, 'test.tsrx', { mode: 'server' });
76
76
 
77
77
  expect(code).toContain('let value = _$_.lazy_array_get(lazy, 0)[0];');
@@ -80,13 +80,13 @@ function App() { return <>
80
80
 
81
81
  it('throws on indexed access through known tracked lazy destructures in SSR output', () => {
82
82
  const source = `import { track } from 'ripple';
83
- function App() { return <>
83
+ function App() @{
84
84
  let &[value, tracked_ref] = track({ 0: 'x' });
85
85
  let nested = value[0];
86
86
  tracked_ref[0] = { 0: 'y' };
87
87
  let next = value[0];
88
88
  <div>{nested}{next}</div>
89
- </>; }`;
89
+ }`;
90
90
 
91
91
  expect(() => compile(source, 'test.tsrx', { mode: 'server' })).toThrow(
92
92
  /Use \.value or &\[\] lazy destructuring/,
@@ -95,7 +95,7 @@ function App() { return <>
95
95
 
96
96
  it('throws on known tracked indexed access in SSR output', () => {
97
97
  const source = `import { track } from 'ripple';
98
- function App() { return <>
98
+ function App() @{
99
99
  let tracked = track(0);
100
100
  ++tracked[0];
101
101
  tracked[0]++;
@@ -103,7 +103,7 @@ function App() { return <>
103
103
  let value = tracked[0];
104
104
  let ref = tracked[1];
105
105
  <div>{value}</div>
106
- </>; }`;
106
+ }`;
107
107
 
108
108
  expect(() => compile(source, 'test.tsrx', { mode: 'server' })).toThrow(
109
109
  /Use \.value or &\[\] lazy destructuring/,
@@ -114,15 +114,15 @@ function App() { return <>
114
114
  'compiles indexed access on unknown lazy tracked refs through lazy array helpers in SSR output',
115
115
  () => {
116
116
  const source = `import { track } from 'ripple';
117
- function Child({ pair: &[value, tracked_ref] }) { return <>
117
+ function Child({ pair: &[value, tracked_ref] }) @{
118
118
  ++tracked_ref[0];
119
119
  tracked_ref[0]++;
120
120
  <div>{value}</div>
121
- </>; }
122
- function App() { return <>
121
+ }
122
+ function App() @{
123
123
  let tracked = track(0);
124
124
  <Child pair={tracked} />
125
- </>; }`;
125
+ }`;
126
126
  const { code } = compile(source, 'test.tsrx', { mode: 'server' });
127
127
 
128
128
  expect(code).toContain('_$_.lazy_array_get(lazy, 1)');
@@ -166,29 +166,29 @@ class PrintEvent implements BaseEvent {
166
166
 
167
167
  it('throws error for interpolating children as text in SSR mode', () => {
168
168
  const source = `
169
- export function Layout({ children }) { return <>
169
+ export function Layout({ children }) @{
170
170
  <div>{children}</div>
171
- </>; }`;
171
+ }`;
172
172
 
173
173
  expect(() => compile(source, 'test.tsrx', { mode: 'server' })).not.toThrow();
174
174
  });
175
175
 
176
176
  it('throws error for interpolating props.children as text in SSR mode', () => {
177
177
  const source = `
178
- export function Layout(props) { return <>
178
+ export function Layout(props) @{
179
179
  <div>{props.children}</div>
180
- </>; }`;
180
+ }`;
181
181
 
182
182
  expect(() => compile(source, 'test.tsrx', { mode: 'server' })).not.toThrow();
183
183
  });
184
184
 
185
- it('compiles indented direct double-quoted text children in SSR mode', () => {
185
+ it('compiles indented direct JSX text children in SSR mode', () => {
186
186
  const source = `
187
- export default function A() { return <>
187
+ export default function A() @{
188
188
  <div>
189
- "Hello"
189
+ Hello
190
190
  </div>
191
- </>; }`;
191
+ }`;
192
192
 
193
193
  const result = compile(source, 'test.tsrx', { mode: 'server' }).code;
194
194
 
@@ -196,11 +196,81 @@ export default function A() { return <>
196
196
  expect(result).not.toContain(`"Hello";`);
197
197
  });
198
198
 
199
+ it('does not merge adjacent call-containing children into stringified text in SSR output', () => {
200
+ const setup = `function child(label) {
201
+ <span>{label}</span>
202
+ }
203
+ function Constructed(label) {
204
+ return child(label);
205
+ }
206
+ const factory = child;
207
+ function identity(value) {
208
+ return value;
209
+ }
210
+ function empty() {
211
+ return null;
212
+ }
213
+ let assigned;
214
+ const lookup = { member: child('member') };
215
+ function getKey() {
216
+ return 'member';
217
+ }
218
+ function touch() {
219
+ return null;
220
+ }
221
+ function tag() {
222
+ return child('tagged');
223
+ }
224
+ const values = { member: 0 };`;
225
+
226
+ const cases = [
227
+ { name: 'call expression', expression: 'child(\'call\')' },
228
+ { name: 'new expression', expression: 'new Constructed(\'new\')' },
229
+ { name: 'chain expression', expression: 'factory?.(\'chain\')' },
230
+ { name: 'parenthesized expression', expression: '(child(\'parenthesized\'))' },
231
+ { name: 'TS as expression', expression: 'child(\'as\') as any' },
232
+ { name: 'TS non-null expression', expression: 'child(\'non-null\')!' },
233
+ { name: 'TS satisfies expression', expression: 'child(\'satisfies\') satisfies any' },
234
+ {
235
+ name: 'TS instantiation expression',
236
+ expression: 'identity<typeof child>(child)(\'instantiation\')',
237
+ },
238
+ { name: 'array expression', expression: '[child(\'array\')]' },
239
+ { name: 'assignment expression', expression: 'assigned = child(\'assignment\')' },
240
+ { name: 'binary expression', expression: 'empty() + \'\'' },
241
+ { name: 'logical expression', expression: 'true && child(\'logical\')' },
242
+ { name: 'conditional expression', expression: 'true ? child(\'conditional\') : \'\'' },
243
+ { name: 'member expression', expression: 'lookup[getKey()]' },
244
+ {
245
+ name: 'object expression',
246
+ expression: '{ [Symbol.for(\'ripple.element\')]: true, render() { return child(\'object\'); } }',
247
+ },
248
+ { name: 'sequence expression', expression: '(touch(), child(\'sequence\'))' },
249
+ { name: 'tagged template expression', expression: 'tag`tagged`' },
250
+ { name: 'template literal', expression: '`${empty()}`' },
251
+ { name: 'unary expression', expression: 'void empty()' },
252
+ { name: 'update expression', expression: 'values[getKey()]++' },
253
+ ];
254
+
255
+ for (const test_case of cases) {
256
+ const source = `${setup}
257
+ export function App() @{
258
+ <div>{'${test_case.name}:'}{${test_case.expression}}</div>
259
+ }`;
260
+
261
+ const { code } = compile(source, `${test_case.name}.tsrx`, { mode: 'server' });
262
+
263
+ if (code.includes('String(')) {
264
+ throw new Error(`${test_case.name} was merged into a stringified text expression:\n${code}`);
265
+ }
266
+ }
267
+ });
268
+
199
269
  it('decodes JSX-style entities before server text escaping', () => {
200
270
  const result = compile(
201
- `function App() { return <>
202
- <div>"Rock &amp; &quot;Roll&quot;"</div>
203
- </>; }`,
271
+ `function App() @{
272
+ <div>Rock &amp; &quot;Roll&quot;</div>
273
+ }`,
204
274
  '/src/App.tsrx',
205
275
  { mode: 'server' },
206
276
  );
@@ -210,10 +280,10 @@ export default function A() { return <>
210
280
 
211
281
  it('emits anonymous component expressions as arrows in SSR output', () => {
212
282
  const source = `
213
- const Inline = (props) => <>
214
- <div>{props.x}</div>
215
- </>
216
- `;
283
+ const Inline = (props) => @{
284
+ <div>{props.x}</div>
285
+ }
286
+ `;
217
287
  const result = compile(source, 'anonymous-component.tsrx', { mode: 'server' }).code;
218
288
 
219
289
  expect(result).toContain('const Inline = (props) => {');
@@ -225,9 +295,9 @@ const Inline = (props) => <>
225
295
 
226
296
  it('emits function-expression components as functions in SSR output', () => {
227
297
  const source = `
228
- const Inline = function(props) { return <>
298
+ const Inline = function(props) @{
229
299
  <div>{props.x}</div>
230
- </>; }
300
+ }
231
301
  `;
232
302
  const result = compile(source, 'anonymous-component.tsrx', { mode: 'server' }).code;
233
303
 
@@ -240,9 +310,9 @@ const Inline = function(props) { return <>
240
310
 
241
311
  it('throws error for calling children as a function in SSR mode', () => {
242
312
  const source = `
243
- export function Layout({ children }) { return <>
313
+ export function Layout({ children }) @{
244
314
  {children()}
245
- </>; }`;
315
+ }`;
246
316
 
247
317
  expect(() => compile(source, 'test.tsrx', { mode: 'server' })).toThrow(
248
318
  '`children` cannot be called like a regular function. Render it with `{children}` or `{props.children}` instead.',
@@ -251,9 +321,9 @@ export function Layout({ children }) { return <>
251
321
 
252
322
  it('throws error for calling props.children as a function in SSR mode', () => {
253
323
  const source = `
254
- export function Layout(props) { return <>
324
+ export function Layout(props) @{
255
325
  {props.children()}
256
- </>; }`;
326
+ }`;
257
327
 
258
328
  expect(() => compile(source, 'test.tsrx', { mode: 'server' })).toThrow(
259
329
  '`children` cannot be called like a regular function. Render it with `{children}` or `{props.children}` instead.',
@@ -262,17 +332,17 @@ export function Layout(props) { return <>
262
332
 
263
333
  it('merges explicit children prop with implicit children in SSR output', () => {
264
334
  const source = `
265
- function Card(props) { return <>
335
+ function Card(props) @{
266
336
  <div>{props.children}</div>
267
- </>; }
337
+ }
268
338
 
269
- export function App() { return <>
339
+ export function App() @{
270
340
  const fallback = 'fallback';
271
341
 
272
342
  <Card children={fallback}>
273
343
  <span>{'content'}</span>
274
344
  </Card>
275
- </>; }
345
+ }
276
346
  `;
277
347
 
278
348
  const result = compile(source, 'test.tsrx', { mode: 'server' }).code;
@@ -284,18 +354,18 @@ export function App() { return <>
284
354
 
285
355
  it('routes calls to functions with nested template returns through render_expression', () => {
286
356
  const source = `
287
- function App() { return <>
288
357
  function make(flag) {
289
358
  if (flag) {
290
- return <><span>{'nested'}</span></>;
359
+ return <span>{'nested'}</span>;
291
360
  }
292
361
 
293
362
  return null;
294
363
  }
295
364
 
296
- <div>{make(true)}</div>
297
- </>; }
298
- `;
365
+ function App() @{
366
+ <div>{make(true)}</div>
367
+ }
368
+ `;
299
369
 
300
370
  const result = compile(source, 'test.tsrx', { mode: 'server' }).code;
301
371
 
@@ -305,23 +375,23 @@ function App() { return <>
305
375
 
306
376
  it('does not treat nested function template returns as outer function returns', () => {
307
377
  const source = `
308
- function App() { return <>
309
378
  function make() {
310
- function nested() {
311
- return <><span>{'nested'}</span></>;
379
+ function nested() @{
380
+ <span>{'nested'}</span>
312
381
  }
313
382
 
314
383
  return nested;
315
384
  }
316
385
 
317
- <div>{make()}</div>
318
- </>; }
319
- `;
386
+ function App() @{
387
+ <div>{make()}</div>
388
+ }
389
+ `;
320
390
 
321
391
  const result = compile(source, 'test.tsrx', { mode: 'server' }).code;
322
392
 
323
- expect(result).toContain('_$_.output_push(_$_.escape(make()))');
324
- expect(result).not.toContain('_$_.render_expression(make())');
393
+ expect(result).toContain('_$_.render_expression(make())');
394
+ expect(result).not.toContain('_$_.render_tsrx_element(make())');
325
395
  });
326
396
  });
327
397
 
@@ -374,10 +444,10 @@ module server {
374
444
 
375
445
  import { loadUser as getUser } from server;
376
446
 
377
- export function App() { return <>
447
+ export function App() @{
378
448
  const user = getUser('1');
379
449
  <div>{user.id}</div>
380
- </>; }`;
450
+ }`;
381
451
 
382
452
  const result = compile(source, 'test.tsrx', { mode: 'server' });
383
453
  expect(result.code).toContain('const getUser = function (...args)');
@@ -442,15 +512,15 @@ module server {
442
512
 
443
513
  it('wraps children in normalize_children for explicit children prop passed to component', () => {
444
514
  const source = `
445
- function Card(props) { return <>
515
+ function Card(props) @{
446
516
  <div>{props.children}</div>
447
- </>; }
517
+ }
448
518
 
449
- export function App() { return <>
519
+ export function App() @{
450
520
  const content = 'hello';
451
521
 
452
522
  <Card children={content} />
453
- </>; }
523
+ }
454
524
  `;
455
525
 
456
526
  const result = compile(source, 'test.tsrx', { mode: 'server' }).code;
@@ -460,15 +530,15 @@ export function App() { return <>
460
530
 
461
531
  it('passes spread through to component when spread may contain children', () => {
462
532
  const source = `
463
- function Card(props) { return <>
533
+ function Card(props) @{
464
534
  <div>{props.children}</div>
465
- </>; }
535
+ }
466
536
 
467
- export function App() { return <>
537
+ export function App() @{
468
538
  const props = { children: 'hello' };
469
539
 
470
540
  <Card {...props} />
471
- </>; }
541
+ }
472
542
  `;
473
543
 
474
544
  const result = compile(source, 'test.tsrx', { mode: 'server' }).code;
@@ -3,16 +3,16 @@ import type { Tracked, Props } from 'ripple';
3
3
 
4
4
  describe('composite > props', () => {
5
5
  it('correctly handles default prop values', async () => {
6
- function Child({ foo = 456 }) {
7
- return <><div>{foo}</div></>;
6
+ function Child({ foo = 456 }) @{
7
+ <div>{foo}</div>
8
8
  }
9
9
 
10
- function App() {
11
- return <>
12
- let &[foo] = track(123);
10
+ function App() @{
11
+ let &[foo] = track(123);
12
+ <>
13
13
  <Child />
14
14
  <Child {foo} />
15
- </>;
15
+ </>
16
16
  }
17
17
 
18
18
  const { body } = await render(App);
@@ -23,16 +23,16 @@ describe('composite > props', () => {
23
23
  });
24
24
 
25
25
  it('correctly handles default prop values #2', async () => {
26
- function Child({ foo = 456 }) {
27
- return <><div>{foo}</div></>;
26
+ function Child({ foo = 456 }) @{
27
+ <div>{foo}</div>
28
28
  }
29
29
 
30
- function App() {
31
- return <>
32
- let foo = 123;
30
+ function App() @{
31
+ let foo = 123;
32
+ <>
33
33
  <Child />
34
34
  <Child {foo} />
35
- </>;
35
+ </>
36
36
  }
37
37
 
38
38
  const { body } = await render(App);
@@ -43,16 +43,18 @@ describe('composite > props', () => {
43
43
  });
44
44
 
45
45
  it('correctly handles no props', async () => {
46
- function Child(props: { foo?: Tracked<number> }) {
47
- return <><div>{props.foo?.value}</div></>;
46
+ function Child(props: { foo?: Tracked<number> }) @{
47
+ <div>
48
+ {props.foo?.value}
49
+ </div>
48
50
  }
49
51
 
50
- function App() {
51
- return <>
52
- let foo = track(123);
52
+ function App() @{
53
+ let foo = track(123);
54
+ <>
53
55
  <Child />
54
56
  <Child {foo} />
55
- </>;
57
+ </>
56
58
  }
57
59
 
58
60
  const { body } = await render(App);
@@ -63,16 +65,16 @@ describe('composite > props', () => {
63
65
  });
64
66
 
65
67
  it('correctly handles no props #2', async () => {
66
- function Child({ foo }: { foo?: number }) {
67
- return <><div>{foo}</div></>;
68
+ function Child({ foo }: { foo?: number }) @{
69
+ <div>{foo}</div>
68
70
  }
69
71
 
70
- function App() {
71
- return <>
72
- let &[foo] = track(123);
72
+ function App() @{
73
+ let &[foo] = track(123);
74
+ <>
73
75
  <Child />
74
76
  <Child {foo} />
75
- </>;
77
+ </>
76
78
  }
77
79
 
78
80
  const { body } = await render(App);
@@ -83,8 +85,8 @@ describe('composite > props', () => {
83
85
  });
84
86
 
85
87
  it('correctly retains prop accessors and reactivity when using rest props', async () => {
86
- function Button(&{ children, ...rest }: Props) {
87
- return <>
88
+ function Button(&{ children, ...rest }: Props) @{
89
+ <>
88
90
  <button {...rest}>{children}</button>
89
91
  <style>
90
92
  .on {
@@ -94,22 +96,20 @@ describe('composite > props', () => {
94
96
  color: red;
95
97
  }
96
98
  </style>
97
- </>;
99
+ </>
98
100
  }
99
101
 
100
- function Toggle(&{ pressed, ...rest }: { pressed: Tracked<boolean> }) {
101
- return <>
102
- const onClick = () => (pressed.value = !pressed.value);
102
+ function Toggle(&{ pressed, ...rest }: { pressed: Tracked<boolean> }) @{
103
+ const onClick = () => (pressed.value = !pressed.value);
104
+ <>
103
105
  <Button {...rest} class={pressed.value ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
104
106
  <Button class={pressed.value ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
105
- </>;
107
+ </>
106
108
  }
107
109
 
108
- function App() {
109
- return <>
110
- const pressed = track(true);
111
- <Toggle {pressed} />
112
- </>;
110
+ function App() @{
111
+ const pressed = track(true);
112
+ <Toggle {pressed} />
113
113
  }
114
114
 
115
115
  const { body } = await render(App);
@@ -132,30 +132,26 @@ describe('composite > props', () => {
132
132
  price: number;
133
133
  }
134
134
 
135
- function Product({ id, name, organizationName, description, imageUrl, price }: ProductInfo) {
136
- return <>
137
- <article class="no-padding">
138
- <img class="responsive small" src={imageUrl} alt={name} />
139
- <span>{id}</span>
140
- <h5>{name}</h5>
141
- <h3>{organizationName}</h3>
142
- <p>{description}</p>
143
- <price class="price">{price}</price>
144
- </article>
145
- </>;
135
+ function Product({ id, name, organizationName, description, imageUrl, price }: ProductInfo) @{
136
+ <article class="no-padding">
137
+ <img class="responsive small" src={imageUrl} alt={name} />
138
+ <span>{id}</span>
139
+ <h5>{name}</h5>
140
+ <h3>{organizationName}</h3>
141
+ <p>{description}</p>
142
+ <price class="price">{price}</price>
143
+ </article>
146
144
  }
147
145
 
148
- function App() {
149
- return <>
150
- <Product
151
- id="1"
152
- name="Product 1"
153
- organizationName="Org 1"
154
- description="Description 1"
155
- imageUrl="https://picsum.photos/300/200"
156
- price={15}
157
- />
158
- </>;
146
+ function App() @{
147
+ <Product
148
+ id="1"
149
+ name="Product 1"
150
+ organizationName="Org 1"
151
+ description="Description 1"
152
+ imageUrl="https://picsum.photos/300/200"
153
+ price={15}
154
+ />
159
155
  }
160
156
 
161
157
  const { body } = await render(App);