ripple 0.2.151 → 0.2.153

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 (67) hide show
  1. package/README.md +3 -3
  2. package/package.json +5 -5
  3. package/src/compiler/phases/1-parse/index.js +1 -1
  4. package/src/compiler/phases/3-transform/client/index.js +37 -16
  5. package/src/compiler/phases/3-transform/server/index.js +43 -25
  6. package/src/runtime/internal/client/events.js +5 -1
  7. package/src/runtime/internal/client/index.js +2 -1
  8. package/src/runtime/internal/client/render.js +18 -15
  9. package/src/runtime/internal/client/runtime.js +78 -10
  10. package/src/runtime/internal/server/index.js +51 -11
  11. package/src/server/index.js +1 -1
  12. package/tests/client/array/array.derived.test.ripple +61 -33
  13. package/tests/client/array/array.iteration.test.ripple +3 -1
  14. package/tests/client/array/array.mutations.test.ripple +19 -15
  15. package/tests/client/array/array.static.test.ripple +115 -104
  16. package/tests/client/array/array.to-methods.test.ripple +3 -3
  17. package/tests/client/basic/basic.attributes.test.ripple +110 -57
  18. package/tests/client/basic/basic.collections.test.ripple +41 -22
  19. package/tests/client/basic/basic.errors.test.ripple +12 -6
  20. package/tests/client/basic/basic.events.test.ripple +51 -33
  21. package/tests/client/basic/basic.reactivity.test.ripple +120 -56
  22. package/tests/client/basic/basic.rendering.test.ripple +49 -19
  23. package/tests/client/basic/basic.styling.test.ripple +2 -2
  24. package/tests/client/basic/basic.utilities.test.ripple +1 -1
  25. package/tests/client/boundaries.test.ripple +70 -58
  26. package/tests/client/compiler/compiler.assignments.test.ripple +32 -4
  27. package/tests/client/compiler/compiler.attributes.test.ripple +46 -46
  28. package/tests/client/compiler/compiler.basic.test.ripple +18 -15
  29. package/tests/client/compiler/compiler.tracked-access.test.ripple +53 -42
  30. package/tests/client/compiler/compiler.typescript.test.ripple +1 -2
  31. package/tests/client/composite/composite.dynamic-components.test.ripple +6 -6
  32. package/tests/client/composite/composite.generics.test.ripple +39 -36
  33. package/tests/client/composite/composite.props.test.ripple +4 -3
  34. package/tests/client/composite/composite.reactivity.test.ripple +112 -27
  35. package/tests/client/composite/composite.render.test.ripple +9 -8
  36. package/tests/client/computed-properties.test.ripple +24 -24
  37. package/tests/client/context.test.ripple +11 -9
  38. package/tests/client/date.test.ripple +3 -1
  39. package/tests/client/dynamic-elements.test.ripple +103 -78
  40. package/tests/client/for.test.ripple +27 -17
  41. package/tests/client/head.test.ripple +42 -6
  42. package/tests/client/html.test.ripple +42 -32
  43. package/tests/client/input-value.test.ripple +4 -4
  44. package/tests/client/map.test.ripple +140 -141
  45. package/tests/client/media-query.test.ripple +31 -31
  46. package/tests/client/object.test.ripple +148 -112
  47. package/tests/client/portal.test.ripple +29 -15
  48. package/tests/client/ref.test.ripple +9 -3
  49. package/tests/client/set.test.ripple +111 -111
  50. package/tests/client/tracked-expression.test.ripple +16 -17
  51. package/tests/client/url/url.derived.test.ripple +19 -9
  52. package/tests/client/url/url.parsing.test.ripple +24 -8
  53. package/tests/client/url/url.partial-removal.test.ripple +12 -4
  54. package/tests/client/url/url.reactivity.test.ripple +63 -25
  55. package/tests/client/url/url.serialization.test.ripple +18 -6
  56. package/tests/client/url-search-params/url-search-params.derived.test.ripple +10 -6
  57. package/tests/client/url-search-params/url-search-params.iteration.test.ripple +3 -1
  58. package/tests/client/url-search-params/url-search-params.mutation.test.ripple +26 -14
  59. package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +3 -1
  60. package/tests/server/await.test.ripple +23 -22
  61. package/tests/server/basic.test.ripple +1 -1
  62. package/tests/server/compiler.test.ripple +3 -7
  63. package/tests/server/composite.test.ripple +38 -36
  64. package/tests/server/for.test.ripple +9 -5
  65. package/tests/server/if.test.ripple +1 -1
  66. package/tests/server/streaming-ssr.test.ripple +67 -0
  67. package/types/server.d.ts +5 -4
@@ -110,7 +110,9 @@ describe('TrackedURL > reactivity', () => {
110
110
  button.click();
111
111
  flushSync();
112
112
 
113
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://newdomain.com:9090/path');
113
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
114
+ 'https://newdomain.com:9090/path',
115
+ );
114
116
  expect(container.querySelectorAll('pre')[1].textContent).toBe('newdomain.com:9090');
115
117
  expect(container.querySelectorAll('pre')[2].textContent).toBe('newdomain.com');
116
118
  expect(container.querySelectorAll('pre')[3].textContent).toBe('9090');
@@ -155,14 +157,18 @@ describe('TrackedURL > reactivity', () => {
155
157
  const button = container.querySelector('button');
156
158
 
157
159
  // Initial state
158
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?foo=bar');
160
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
161
+ 'https://example.com/path?foo=bar',
162
+ );
159
163
  expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=bar');
160
164
 
161
165
  // Change search
162
166
  button.click();
163
167
  flushSync();
164
168
 
165
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?baz=qux');
169
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
170
+ 'https://example.com/path?baz=qux',
171
+ );
166
172
  expect(container.querySelectorAll('pre')[1].textContent).toBe('?baz=qux');
167
173
  });
168
174
 
@@ -180,14 +186,18 @@ describe('TrackedURL > reactivity', () => {
180
186
  const button = container.querySelector('button');
181
187
 
182
188
  // Initial state
183
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path#section1');
189
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
190
+ 'https://example.com/path#section1',
191
+ );
184
192
  expect(container.querySelectorAll('pre')[1].textContent).toBe('#section1');
185
193
 
186
194
  // Change hash
187
195
  button.click();
188
196
  flushSync();
189
197
 
190
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path#section2');
198
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
199
+ 'https://example.com/path#section2',
200
+ );
191
201
  expect(container.querySelectorAll('pre')[1].textContent).toBe('#section2');
192
202
  });
193
203
 
@@ -205,14 +215,18 @@ describe('TrackedURL > reactivity', () => {
205
215
  const button = container.querySelector('button');
206
216
 
207
217
  // Initial state
208
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://user:pass@example.com/path');
218
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
219
+ 'https://user:pass@example.com/path',
220
+ );
209
221
  expect(container.querySelectorAll('pre')[1].textContent).toBe('user');
210
222
 
211
223
  // Change username
212
224
  button.click();
213
225
  flushSync();
214
226
 
215
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://newuser:pass@example.com/path');
227
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
228
+ 'https://newuser:pass@example.com/path',
229
+ );
216
230
  expect(container.querySelectorAll('pre')[1].textContent).toBe('newuser');
217
231
  });
218
232
 
@@ -230,14 +244,18 @@ describe('TrackedURL > reactivity', () => {
230
244
  const button = container.querySelector('button');
231
245
 
232
246
  // Initial state
233
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://user:pass@example.com/path');
247
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
248
+ 'https://user:pass@example.com/path',
249
+ );
234
250
  expect(container.querySelectorAll('pre')[1].textContent).toBe('pass');
235
251
 
236
252
  // Change password
237
253
  button.click();
238
254
  flushSync();
239
255
 
240
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://user:newpass@example.com/path');
256
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
257
+ 'https://user:newpass@example.com/path',
258
+ );
241
259
  expect(container.querySelectorAll('pre')[1].textContent).toBe('newpass');
242
260
  });
243
261
 
@@ -245,7 +263,9 @@ describe('TrackedURL > reactivity', () => {
245
263
  component URLTest() {
246
264
  const url = new TrackedURL('https://example.com/path?foo=bar#section');
247
265
 
248
- <button onClick={() => url.href = 'https://newdomain.com:9090/newpath?baz=qux#newsection'}>{'Change Href'}</button>
266
+ <button onClick={() => url.href = 'https://newdomain.com:9090/newpath?baz=qux#newsection'}>
267
+ {'Change Href'}
268
+ </button>
249
269
  <pre>{url.href}</pre>
250
270
  <pre>{url.protocol}</pre>
251
271
  <pre>{url.hostname}</pre>
@@ -260,7 +280,9 @@ describe('TrackedURL > reactivity', () => {
260
280
  const button = container.querySelector('button');
261
281
 
262
282
  // Initial state
263
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?foo=bar#section');
283
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
284
+ 'https://example.com/path?foo=bar#section',
285
+ );
264
286
  expect(container.querySelectorAll('pre')[1].textContent).toBe('https:');
265
287
  expect(container.querySelectorAll('pre')[2].textContent).toBe('example.com');
266
288
  expect(container.querySelectorAll('pre')[3].textContent).toBe('');
@@ -272,7 +294,9 @@ describe('TrackedURL > reactivity', () => {
272
294
  button.click();
273
295
  flushSync();
274
296
 
275
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://newdomain.com:9090/newpath?baz=qux#newsection');
297
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
298
+ 'https://newdomain.com:9090/newpath?baz=qux#newsection',
299
+ );
276
300
  expect(container.querySelectorAll('pre')[1].textContent).toBe('https:');
277
301
  expect(container.querySelectorAll('pre')[2].textContent).toBe('newdomain.com');
278
302
  expect(container.querySelectorAll('pre')[3].textContent).toBe('9090');
@@ -331,7 +355,9 @@ describe('TrackedURL > reactivity', () => {
331
355
  const addButton = container.querySelectorAll('button')[1];
332
356
 
333
357
  // Initial state
334
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?foo=bar');
358
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
359
+ 'https://example.com/path?foo=bar',
360
+ );
335
361
  expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=bar');
336
362
  expect(container.querySelectorAll('pre')[2].textContent).toBe('bar');
337
363
 
@@ -339,7 +365,9 @@ describe('TrackedURL > reactivity', () => {
339
365
  updateButton.click();
340
366
  flushSync();
341
367
 
342
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?foo=updated');
368
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
369
+ 'https://example.com/path?foo=updated',
370
+ );
343
371
  expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=updated');
344
372
  expect(container.querySelectorAll('pre')[2].textContent).toBe('updated');
345
373
 
@@ -347,7 +375,9 @@ describe('TrackedURL > reactivity', () => {
347
375
  addButton.click();
348
376
  flushSync();
349
377
 
350
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?foo=updated&baz=qux');
378
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
379
+ 'https://example.com/path?foo=updated&baz=qux',
380
+ );
351
381
  expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=updated&baz=qux');
352
382
  });
353
383
 
@@ -390,14 +420,18 @@ describe('TrackedURL > reactivity', () => {
390
420
  component URLTest() {
391
421
  const url = new TrackedURL('https://example.com/path');
392
422
 
393
- <button onClick={() => {
394
- url.protocol = 'http:';
395
- url.hostname = 'newdomain.com';
396
- url.port = '8080';
397
- url.pathname = '/api';
398
- url.search = '?key=value';
399
- url.hash = '#section';
400
- }}>{'Change All'}</button>
423
+ <button
424
+ onClick={() => {
425
+ url.protocol = 'http:';
426
+ url.hostname = 'newdomain.com';
427
+ url.port = '8080';
428
+ url.pathname = '/api';
429
+ url.search = '?key=value';
430
+ url.hash = '#section';
431
+ }}
432
+ >
433
+ {'Change All'}
434
+ </button>
401
435
  <pre>{url.href}</pre>
402
436
  }
403
437
 
@@ -412,7 +446,9 @@ describe('TrackedURL > reactivity', () => {
412
446
  button.click();
413
447
  flushSync();
414
448
 
415
- expect(container.querySelector('pre').textContent).toBe('http://newdomain.com:8080/api?key=value#section');
449
+ expect(container.querySelector('pre').textContent).toBe(
450
+ 'http://newdomain.com:8080/api?key=value#section',
451
+ );
416
452
  });
417
453
 
418
454
  it('handles href change updates all properties and searchParams', () => {
@@ -420,7 +456,9 @@ describe('TrackedURL > reactivity', () => {
420
456
  const url = new TrackedURL('https://old.com/old?foo=bar#old');
421
457
  const params = url.searchParams;
422
458
 
423
- <button onClick={() => url.href = 'https://new.com:9090/new?baz=qux#new'}>{'Change Href'}</button>
459
+ <button onClick={() => url.href = 'https://new.com:9090/new?baz=qux#new'}>
460
+ {'Change Href'}
461
+ </button>
424
462
  <pre>{params.get('foo')}</pre>
425
463
  <pre>{params.get('baz')}</pre>
426
464
  <pre>{params.size}</pre>
@@ -14,13 +14,17 @@ describe('TrackedURL > serialization', () => {
14
14
  const button = container.querySelector('button');
15
15
 
16
16
  // Initial state
17
- expect(container.querySelector('pre').textContent).toBe('https://example.com/path?foo=bar#section');
17
+ expect(container.querySelector('pre').textContent).toBe(
18
+ 'https://example.com/path?foo=bar#section',
19
+ );
18
20
 
19
21
  // Change pathname
20
22
  button.click();
21
23
  flushSync();
22
24
 
23
- expect(container.querySelector('pre').textContent).toBe('https://example.com/newpath?foo=bar#section');
25
+ expect(container.querySelector('pre').textContent).toBe(
26
+ 'https://example.com/newpath?foo=bar#section',
27
+ );
24
28
  });
25
29
 
26
30
  it('handles toJSON method', () => {
@@ -37,14 +41,22 @@ describe('TrackedURL > serialization', () => {
37
41
  const button = container.querySelector('button');
38
42
 
39
43
  // Initial state
40
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path?foo=bar');
41
- expect(container.querySelectorAll('pre')[1].textContent).toBe('{"url":"https://example.com/path?foo=bar"}');
44
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
45
+ 'https://example.com/path?foo=bar',
46
+ );
47
+ expect(container.querySelectorAll('pre')[1].textContent).toBe(
48
+ '{"url":"https://example.com/path?foo=bar"}',
49
+ );
42
50
 
43
51
  // Change pathname
44
52
  button.click();
45
53
  flushSync();
46
54
 
47
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/api?foo=bar');
48
- expect(container.querySelectorAll('pre')[1].textContent).toBe('{"url":"https://example.com/api?foo=bar"}');
55
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
56
+ 'https://example.com/api?foo=bar',
57
+ );
58
+ expect(container.querySelectorAll('pre')[1].textContent).toBe(
59
+ '{"url":"https://example.com/api?foo=bar"}',
60
+ );
49
61
  });
50
62
  });
@@ -46,15 +46,19 @@ describe('TrackedURLSearchParams > derived', () => {
46
46
  component ParentTest() {
47
47
  const params = new TrackedURLSearchParams('count=0');
48
48
 
49
- <ChildA params={params} />
50
- <ChildB params={params} />
49
+ <ChildA {params} />
50
+ <ChildB {params} />
51
51
  }
52
52
 
53
53
  component ChildA({ params }: { params: TrackedURLSearchParams }) {
54
- <button onClick={() => {
55
- const current = parseInt(params.get('count') || '0', 10);
56
- params.set('count', String(current + 1));
57
- }}>{'increment'}</button>
54
+ <button
55
+ onClick={() => {
56
+ const current = parseInt(params.get('count') || '0', 10);
57
+ params.set('count', String(current + 1));
58
+ }}
59
+ >
60
+ {'increment'}
61
+ </button>
58
62
  }
59
63
 
60
64
  component ChildB({ params }: { params: TrackedURLSearchParams }) {
@@ -67,7 +67,9 @@ describe('TrackedURLSearchParams > iteration', () => {
67
67
  button.click();
68
68
  flushSync();
69
69
 
70
- expect(container.querySelector('pre').textContent).toBe('[["foo","bar"],["baz","qux"],["new","value"]]');
70
+ expect(container.querySelector('pre').textContent).toBe(
71
+ '[["foo","bar"],["baz","qux"],["new","value"]]',
72
+ );
71
73
  });
72
74
 
73
75
  it('handles Symbol.iterator with reactivity', () => {
@@ -243,10 +243,14 @@ describe('TrackedURLSearchParams > mutation', () => {
243
243
  const url = new TrackedURL('https://example.com?foo=bar&baz=qux');
244
244
  const params = url.searchParams;
245
245
 
246
- <button onClick={() => {
247
- params.delete('foo');
248
- params.delete('baz');
249
- }}>{'clear all'}</button>
246
+ <button
247
+ onClick={() => {
248
+ params.delete('foo');
249
+ params.delete('baz');
250
+ }}
251
+ >
252
+ {'clear all'}
253
+ </button>
250
254
  <pre>{url.href}</pre>
251
255
  <pre>{params.size}</pre>
252
256
  }
@@ -256,7 +260,9 @@ describe('TrackedURLSearchParams > mutation', () => {
256
260
  const button = container.querySelector('button');
257
261
 
258
262
  // Initial state
259
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/?foo=bar&baz=qux');
263
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
264
+ 'https://example.com/?foo=bar&baz=qux',
265
+ );
260
266
  expect(container.querySelectorAll('pre')[1].textContent).toBe('2');
261
267
 
262
268
  // Test clear all
@@ -271,14 +277,18 @@ describe('TrackedURLSearchParams > mutation', () => {
271
277
  component URLTest() {
272
278
  const params = new TrackedURLSearchParams();
273
279
 
274
- <button onClick={() => {
275
- params.append('a', '1');
276
- params.append('b', '2');
277
- params.set('a', '10');
278
- params.delete('b');
279
- params.append('c', '3');
280
- params.sort();
281
- }}>{'complex operations'}</button>
280
+ <button
281
+ onClick={() => {
282
+ params.append('a', '1');
283
+ params.append('b', '2');
284
+ params.set('a', '10');
285
+ params.delete('b');
286
+ params.append('c', '3');
287
+ params.sort();
288
+ }}
289
+ >
290
+ {'complex operations'}
291
+ </button>
282
292
  <pre>{params.toString()}</pre>
283
293
  <pre>{params.size}</pre>
284
294
  }
@@ -337,7 +347,9 @@ describe('TrackedURLSearchParams > mutation', () => {
337
347
  rippleButton.click();
338
348
  flushSync();
339
349
 
340
- expect(container.querySelectorAll('pre')[0].textContent).toBe('["javascript","typescript","ripple"]');
350
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
351
+ '["javascript","typescript","ripple"]',
352
+ );
341
353
  expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
342
354
  });
343
355
  });
@@ -23,7 +23,9 @@ describe('TrackedURLSearchParams > TrackedURL integration', () => {
23
23
  button.click();
24
24
  flushSync();
25
25
 
26
- expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/?foo=bar&baz=qux');
26
+ expect(container.querySelectorAll('pre')[0].textContent).toBe(
27
+ 'https://example.com/?foo=bar&baz=qux',
28
+ );
27
29
  expect(container.querySelectorAll('pre')[1].textContent).toBe('foo=bar&baz=qux');
28
30
  });
29
31
 
@@ -9,7 +9,7 @@ describe('await in control flow', () => {
9
9
  let data = track('loading');
10
10
 
11
11
  if (condition) {
12
- await new Promise(resolve => setTimeout(() => {
12
+ await new Promise((resolve) => setTimeout(() => {
13
13
  @data = 'loaded';
14
14
  resolve();
15
15
  }, 10));
@@ -28,7 +28,7 @@ describe('await in control flow', () => {
28
28
  let result = '';
29
29
 
30
30
  for (const item of items) {
31
- await new Promise(resolve => setTimeout(resolve, 5));
31
+ await new Promise((resolve) => setTimeout(resolve, 5));
32
32
  result += item;
33
33
  }
34
34
 
@@ -39,23 +39,24 @@ describe('await in control flow', () => {
39
39
  expect(body).toBe('<div>123</div>');
40
40
  });
41
41
 
42
- it('should handle await inside switch statement', async () => {
43
- component App() {
44
- let value = 'b';
45
-
46
- switch (value) {
47
- case 'a':
48
- <div>{'Case A'}</div>
49
- break;
50
- case 'b':
51
- await new Promise(resolve => setTimeout(resolve, 10));
52
- <div>{'Case B'}</div>
53
- break;
54
- default:
55
- <div>{'Default Case'}</div>
56
- }
57
- }
58
-
59
- const { body } = await render(App);
60
- expect(body).toBe('<div>Case B</div>');
61
- });});
42
+ it('should handle await inside switch statement', async () => {
43
+ component App() {
44
+ let value = 'b';
45
+
46
+ switch (value) {
47
+ case 'a':
48
+ <div>{'Case A'}</div>
49
+ break;
50
+ case 'b':
51
+ await new Promise((resolve) => setTimeout(resolve, 10));
52
+ <div>{'Case B'}</div>
53
+ break;
54
+ default:
55
+ <div>{'Default Case'}</div>
56
+ }
57
+ }
58
+
59
+ const { body } = await render(App);
60
+ expect(body).toBe('<div>Case B</div>');
61
+ });
62
+ });
@@ -12,4 +12,4 @@ describe('basic client', () => {
12
12
  expect(head).toBe('');
13
13
  expect(body).toBe('<div>Hello World</div>');
14
14
  });
15
- });
15
+ });
@@ -1,12 +1,9 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { compile } from 'ripple/compiler'
2
+ import { compile } from 'ripple/compiler';
3
3
 
4
4
  describe('compiler success tests', () => {
5
-
6
-
7
5
  it('compiles TSInstantiationExpression', () => {
8
- const source =
9
- `function makeBox<T>(value: T) {
6
+ const source = `function makeBox<T,>(value: T) {
10
7
  return { value };
11
8
  }
12
9
  const makeStringBox = makeBox<string>;
@@ -20,8 +17,7 @@ const errorMap = new ErrorMap();`;
20
17
  });
21
18
 
22
19
  it('compiles imported component with conditional async in SSR', () => {
23
- const source =
24
- `import { ChildComponent } from './Child.ripple';
20
+ const source = `import { ChildComponent } from './Child.ripple';
25
21
 
26
22
  export component App() {
27
23
  <div>
@@ -9,32 +9,36 @@ describe('generics', () => {
9
9
 
10
10
  // 7. Generic following optional chaining
11
11
  const maybe = {
12
- factory<T>() {
12
+ factory: function <T>() {
13
13
  return {
14
- make<U>() {
14
+ make: function <U>() {
15
15
  return 1;
16
- }
16
+ },
17
17
  };
18
- }
18
+ },
19
19
  };
20
20
  const g = maybe?.factory<number>()?.make<boolean>();
21
21
 
22
22
  // 8. Comparison operator (ensure '<' here NOT misparsed as generics)
23
23
  let x = 10, y = 20;
24
- const h = x < y ? 'lt' : 'ge';
24
+ const h =
25
+ x < y ? 'lt' : 'ge';
25
26
 
26
27
  // 9. Chained comparisons with intervening generics
27
28
  class Box<T> {
28
29
  value: T;
29
- constructor(value?: T) {
30
+
31
+ constructor(value: T) {
30
32
  this.value = value;
31
33
  }
34
+
32
35
  open<U>() {
33
36
  return new Box<U>();
34
37
  }
35
38
  }
36
39
  const limit = 100;
37
- const i = new Box<number>().value < limit ? 'ok' : 'no';
40
+ const i =
41
+ new Box<number>().value < limit ? 'ok' : 'no';
38
42
 
39
43
  // 10. JSX / Element should still work
40
44
  <div class="still-works">
@@ -59,13 +63,13 @@ describe('generics', () => {
59
63
  // 13. Multiple generic segments in chain
60
64
  function foo<T>() {
61
65
  return {
62
- bar<U>() {
66
+ bar: function <U>() {
63
67
  return {
64
- baz<V>() {
68
+ baz: function <V>() {
65
69
  return true;
66
- }
70
+ },
67
71
  };
68
- }
72
+ },
69
73
  };
70
74
  }
71
75
  const l = foo<number>().bar<string>().baz<boolean>();
@@ -77,9 +81,11 @@ describe('generics', () => {
77
81
  // 15. Generic in angle after "new" + trailing call
78
82
  class Wrapper<T> {
79
83
  value: T;
84
+
80
85
  constructor() {
81
86
  this.value = null as unknown as T;
82
87
  }
88
+
83
89
  unwrap<U>() {
84
90
  return null as unknown as U;
85
91
  }
@@ -90,11 +96,11 @@ describe('generics', () => {
90
96
  function getUnknown(): unknown {
91
97
  return new Map<string, number>([['a', 1]]);
92
98
  }
93
- getUnknown.factory = function<T>() {
99
+ getUnknown.factory = function <T>() {
94
100
  return {
95
- make<U>() {
101
+ make: function <U>() {
96
102
  return 2;
97
- }
103
+ },
98
104
  };
99
105
  };
100
106
  const raw = getUnknown();
@@ -103,14 +109,17 @@ describe('generics', () => {
103
109
  // 17. Generic with comma + trailing less-than comparison on next token
104
110
  class Pair<T1, T2> {
105
111
  first: T1;
112
+
106
113
  second: T2;
114
+
107
115
  constructor() {
108
116
  this.first = null as unknown as T1;
109
117
  this.second = null as unknown as T2;
110
118
  }
111
119
  }
112
120
  const p = new Pair<number, string>();
113
- const q = 1 < 2 ? p : null;
121
+ const q =
122
+ 1 < 2 ? p : null;
114
123
 
115
124
  // 18. Nested generics with line breaks resembling JSX indentation
116
125
  interface Node<T> {
@@ -121,16 +130,15 @@ describe('generics', () => {
121
130
  }
122
131
  class Graph<N, E> {
123
132
  nodes: N[];
133
+
124
134
  edges: E[];
135
+
125
136
  constructor() {
126
137
  this.nodes = [];
127
138
  this.edges = [];
128
139
  }
129
140
  }
130
- const r = new Graph<
131
- Node<string>,
132
- Edge<number>
133
- >();
141
+ const r = new Graph<Node<string>, Edge<number>>();
134
142
 
135
143
  // 19. Ternary containing generics in both branches
136
144
  let flag = true;
@@ -150,18 +158,17 @@ describe('generics', () => {
150
158
  const v = make<number>()(10);
151
159
 
152
160
  // 23. Generic followed by tagged template (ensure not confused with JSX)
153
- function tagFn<T>(strings: TemplateStringsArray, ...values: T[]) {
161
+ function tagFn<T>(strings: TemplateStringsArray, ...values) {
154
162
  return values[0];
155
163
  }
156
- const tagResult = tagFn<number>`value`;
164
+ const tagResult = tagFn`value`;
157
165
 
158
166
  // 24. Sequence mixing: (a < b) + generic call in same statement
159
167
  function compute<T>(x: T, y: T): T {
160
168
  return y;
161
169
  }
162
170
 
163
- const w = (x < y) && compute<number>(x, y);
164
-
171
+ const w = x < y && compute<number>(x, y);
165
172
 
166
173
  // Additional component focusing on edge crankers
167
174
 
@@ -172,37 +179,32 @@ describe('generics', () => {
172
179
  class Builder<Kind> {
173
180
  finalize<Result>() {
174
181
  return {
175
- result: null as unknown as Result
182
+ result: null as unknown as Result,
176
183
  };
177
184
  }
178
185
  }
179
186
  const builder = new Builder<Number>();
180
- const result = ((function(){ return builder; })() as Builder<Number>).finalize<boolean>();
187
+ const result = (function () {
188
+ return builder;
189
+ }() as Builder<Number>).finalize<boolean>();
181
190
 
182
191
  // 30. Angle bracket start of conditional expression line
183
192
  function adjust<T>(value: T): T {
184
193
  return value;
185
194
  }
186
195
  const val =
187
- new Wrapper<number>()
188
- .value < 100
189
- ? adjust<number>(10)
190
- : adjust<number>(20);
191
-
196
+ new Wrapper<number>().value < 100 ? adjust<number>(10) : adjust<number>(20);
192
197
 
193
198
  // 32. Generic with comments inside angle list
194
199
  class Mapper<Key, Value> {
195
200
  map: Map<Key, Value>;
201
+
196
202
  constructor() {
197
203
  this.map = new Map<Key, Value>();
198
204
  }
199
205
  }
200
- const gg = new Mapper<
201
- // key type
202
- string,
203
- /* value type */
204
- number
205
- >();
206
+ const gg = new Mapper<// key type
207
+ string /* value type */, number>();
206
208
 
207
209
  // 33. Map of generic instance as key
208
210
  const mm = new Map<TrackedArray<number>, TrackedArray<string>>();