ripple 0.3.6 → 0.3.8

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 (110) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/package.json +2 -2
  3. package/src/compiler/phases/1-parse/index.js +37 -194
  4. package/src/compiler/phases/2-analyze/index.js +290 -26
  5. package/src/compiler/phases/3-transform/client/index.js +54 -14
  6. package/src/compiler/phases/3-transform/server/index.js +19 -35
  7. package/src/compiler/types/index.d.ts +3 -1
  8. package/src/compiler/types/parse.d.ts +0 -8
  9. package/src/compiler/utils.js +10 -6
  10. package/src/runtime/internal/client/composite.js +2 -2
  11. package/src/runtime/internal/client/index.js +2 -0
  12. package/src/runtime/internal/client/runtime.js +95 -45
  13. package/src/runtime/internal/client/types.d.ts +10 -0
  14. package/src/runtime/internal/client/utils.js +12 -0
  15. package/src/runtime/internal/server/index.js +89 -17
  16. package/src/runtime/internal/server/types.d.ts +10 -0
  17. package/src/utils/ast.js +1 -1
  18. package/tests/client/array/array.copy-within.test.ripple +12 -12
  19. package/tests/client/array/array.derived.test.ripple +46 -46
  20. package/tests/client/array/array.iteration.test.ripple +10 -10
  21. package/tests/client/array/array.mutations.test.ripple +20 -20
  22. package/tests/client/array/array.to-methods.test.ripple +6 -6
  23. package/tests/client/async-suspend.test.ripple +5 -5
  24. package/tests/client/basic/basic.attributes.test.ripple +81 -81
  25. package/tests/client/basic/basic.collections.test.ripple +9 -9
  26. package/tests/client/basic/basic.components.test.ripple +28 -28
  27. package/tests/client/basic/basic.errors.test.ripple +18 -18
  28. package/tests/client/basic/basic.events.test.ripple +37 -37
  29. package/tests/client/basic/basic.get-set.test.ripple +6 -6
  30. package/tests/client/basic/basic.reactivity.test.ripple +68 -68
  31. package/tests/client/basic/basic.rendering.test.ripple +19 -19
  32. package/tests/client/basic/basic.utilities.test.ripple +3 -3
  33. package/tests/client/boundaries.test.ripple +12 -12
  34. package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +5 -5
  35. package/tests/client/compiler/compiler.assignments.test.ripple +19 -19
  36. package/tests/client/compiler/compiler.basic.test.ripple +44 -15
  37. package/tests/client/compiler/compiler.tracked-access.test.ripple +68 -2
  38. package/tests/client/composite/composite.dynamic-components.test.ripple +9 -9
  39. package/tests/client/composite/composite.props.test.ripple +11 -11
  40. package/tests/client/composite/composite.reactivity.test.ripple +43 -43
  41. package/tests/client/composite/composite.render.test.ripple +3 -3
  42. package/tests/client/computed-properties.test.ripple +4 -4
  43. package/tests/client/date.test.ripple +42 -42
  44. package/tests/client/dynamic-elements.test.ripple +42 -42
  45. package/tests/client/events.test.ripple +70 -70
  46. package/tests/client/for.test.ripple +25 -25
  47. package/tests/client/head.test.ripple +19 -19
  48. package/tests/client/html.test.ripple +3 -3
  49. package/tests/client/input-value.test.ripple +84 -84
  50. package/tests/client/lazy-destructuring.test.ripple +123 -14
  51. package/tests/client/map.test.ripple +16 -16
  52. package/tests/client/media-query.test.ripple +7 -7
  53. package/tests/client/portal.test.ripple +11 -11
  54. package/tests/client/ref.test.ripple +4 -4
  55. package/tests/client/return.test.ripple +52 -52
  56. package/tests/client/set.test.ripple +6 -6
  57. package/tests/client/svg.test.ripple +5 -5
  58. package/tests/client/switch.test.ripple +44 -44
  59. package/tests/client/try.test.ripple +5 -5
  60. package/tests/client/url/url.derived.test.ripple +6 -6
  61. package/tests/client/url-search-params/url-search-params.derived.test.ripple +8 -8
  62. package/tests/client/url-search-params/url-search-params.iteration.test.ripple +10 -10
  63. package/tests/client/url-search-params/url-search-params.mutation.test.ripple +10 -10
  64. package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +18 -18
  65. package/tests/client/url-search-params/url-search-params.serialization.test.ripple +2 -2
  66. package/tests/hydration/compiled/client/events.js +25 -25
  67. package/tests/hydration/compiled/client/for.js +70 -66
  68. package/tests/hydration/compiled/client/head.js +25 -25
  69. package/tests/hydration/compiled/client/hmr.js +2 -2
  70. package/tests/hydration/compiled/client/html.js +3 -3
  71. package/tests/hydration/compiled/client/if-children.js +24 -24
  72. package/tests/hydration/compiled/client/if.js +18 -18
  73. package/tests/hydration/compiled/client/mixed-control-flow.js +9 -9
  74. package/tests/hydration/compiled/client/portal.js +3 -3
  75. package/tests/hydration/compiled/client/reactivity.js +16 -16
  76. package/tests/hydration/compiled/client/return.js +40 -40
  77. package/tests/hydration/compiled/client/switch.js +12 -12
  78. package/tests/hydration/compiled/server/events.js +19 -19
  79. package/tests/hydration/compiled/server/for.js +41 -41
  80. package/tests/hydration/compiled/server/head.js +26 -26
  81. package/tests/hydration/compiled/server/hmr.js +2 -2
  82. package/tests/hydration/compiled/server/html.js +2 -2
  83. package/tests/hydration/compiled/server/if-children.js +16 -16
  84. package/tests/hydration/compiled/server/if.js +11 -11
  85. package/tests/hydration/compiled/server/mixed-control-flow.js +6 -6
  86. package/tests/hydration/compiled/server/portal.js +2 -2
  87. package/tests/hydration/compiled/server/reactivity.js +16 -16
  88. package/tests/hydration/compiled/server/return.js +25 -25
  89. package/tests/hydration/compiled/server/switch.js +8 -8
  90. package/tests/hydration/components/events.ripple +25 -25
  91. package/tests/hydration/components/for.ripple +66 -66
  92. package/tests/hydration/components/head.ripple +16 -16
  93. package/tests/hydration/components/hmr.ripple +2 -2
  94. package/tests/hydration/components/html.ripple +3 -3
  95. package/tests/hydration/components/if-children.ripple +24 -24
  96. package/tests/hydration/components/if.ripple +18 -18
  97. package/tests/hydration/components/mixed-control-flow.ripple +9 -9
  98. package/tests/hydration/components/portal.ripple +3 -3
  99. package/tests/hydration/components/reactivity.ripple +16 -16
  100. package/tests/hydration/components/return.ripple +40 -40
  101. package/tests/hydration/components/switch.ripple +20 -20
  102. package/tests/server/await.test.ripple +3 -3
  103. package/tests/server/basic.attributes.test.ripple +34 -34
  104. package/tests/server/basic.components.test.ripple +10 -10
  105. package/tests/server/basic.test.ripple +38 -40
  106. package/tests/server/composite.props.test.ripple +9 -9
  107. package/tests/server/dynamic-elements.test.ripple +13 -12
  108. package/tests/server/head.test.ripple +11 -11
  109. package/tests/server/lazy-destructuring.test.ripple +72 -0
  110. package/types/index.d.ts +7 -2
@@ -15,18 +15,18 @@ export component SwitchStatic() {
15
15
  }
16
16
 
17
17
  export component SwitchReactive() {
18
- let status = track<'a' | 'b' | 'c'>('a');
18
+ let &[status] = track<'a' | 'b' | 'c'>('a');
19
19
  <button
20
20
  class="toggle"
21
21
  onClick={() => {
22
- if (@status === 'a') @status = 'b';
23
- else if (@status === 'b') @status = 'c';
24
- else @status = 'a';
22
+ if (status === 'a') status = 'b';
23
+ else if (status === 'b') status = 'c';
24
+ else status = 'a';
25
25
  }}
26
26
  >
27
27
  {'Toggle'}
28
28
  </button>
29
- switch (@status) {
29
+ switch (status) {
30
30
  case 'a':
31
31
  <div class="case-a">{'Case A'}</div>
32
32
  break;
@@ -51,18 +51,18 @@ export component SwitchFallthrough() {
51
51
  }
52
52
 
53
53
  export component SwitchNumericLevels() {
54
- let level = track<1 | 2 | 3>(1);
54
+ let &[level] = track<1 | 2 | 3>(1);
55
55
  <button
56
56
  class="level-toggle"
57
57
  onClick={() => {
58
- if (@level === 1) @level = 2;
59
- else if (@level === 2) @level = 3;
60
- else @level = 1;
58
+ if (level === 1) level = 2;
59
+ else if (level === 2) level = 3;
60
+ else level = 1;
61
61
  }}
62
62
  >
63
63
  {'Toggle Level'}
64
64
  </button>
65
- switch (@level) {
65
+ switch (level) {
66
66
  case 1:
67
67
  <div class="level-1">{'Level 1'}</div>
68
68
  break;
@@ -76,18 +76,18 @@ export component SwitchNumericLevels() {
76
76
  }
77
77
 
78
78
  export component SwitchBlockScoped() {
79
- let level = track<1 | 2 | 3>(1);
79
+ let &[level] = track<1 | 2 | 3>(1);
80
80
  <button
81
81
  class="block-toggle"
82
82
  onClick={() => {
83
- if (@level === 1) @level = 2;
84
- else if (@level === 2) @level = 3;
85
- else @level = 1;
83
+ if (level === 1) level = 2;
84
+ else if (level === 2) level = 3;
85
+ else level = 1;
86
86
  }}
87
87
  >
88
88
  {'Toggle'}
89
89
  </button>
90
- switch (@level) {
90
+ switch (level) {
91
91
  case 1: {
92
92
  <div class="block-1">{'Block 1'}</div>
93
93
  break;
@@ -104,18 +104,18 @@ export component SwitchBlockScoped() {
104
104
  }
105
105
 
106
106
  export component SwitchNoBreak() {
107
- let level = track<1 | 2 | 3>(1);
107
+ let &[level] = track<1 | 2 | 3>(1);
108
108
  <button
109
109
  class="nobreak-toggle"
110
110
  onClick={() => {
111
- if (@level === 1) @level = 2;
112
- else if (@level === 2) @level = 3;
113
- else @level = 1;
111
+ if (level === 1) level = 2;
112
+ else if (level === 2) level = 3;
113
+ else level = 1;
114
114
  }}
115
115
  >
116
116
  {'Toggle'}
117
117
  </button>
118
- switch (@level) {
118
+ switch (level) {
119
119
  case 1: {
120
120
  <div class="nobreak-1">{'NoBreak 1'}</div>
121
121
  }
@@ -8,16 +8,16 @@ describe('await in control flow', () => {
8
8
  // it('should handle await inside if statement', async () => {
9
9
  // component App() {
10
10
  // let condition = true;
11
- // let data = track('loading');
11
+ // let &[data] = track('loading');
12
12
 
13
13
  // if (condition) {
14
14
  // await new Promise((resolve) => setTimeout(() => {
15
- // @data = 'loaded';
15
+ // data = 'loaded';
16
16
  // resolve();
17
17
  // }, 10));
18
18
  // }
19
19
 
20
- // <div>{@data}</div>
20
+ // <div>{data}</div>
21
21
  // }
22
22
 
23
23
  // const { body } = await render(App);
@@ -19,9 +19,9 @@ describe('basic server > attribute rendering', () => {
19
19
 
20
20
  it('render dynamic class attribute', async () => {
21
21
  component Basic() {
22
- let active = track(false);
22
+ let &[active] = track(false);
23
23
 
24
- <div class={@active ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
24
+ <div class={active ? 'active' : 'inactive'}>{'Dynamic Class'}</div>
25
25
 
26
26
  <style>
27
27
  .active {
@@ -89,9 +89,9 @@ describe('basic server > attribute rendering', () => {
89
89
 
90
90
  it('render dynamic class object', async () => {
91
91
  component Basic() {
92
- let active = track(false);
92
+ let &[active] = track(false);
93
93
 
94
- <div class={{ active: @active, inactive: !@active }}>{'Dynamic Class'}</div>
94
+ <div class={{ active: active, inactive: !active }}>{'Dynamic Class'}</div>
95
95
 
96
96
  <style>
97
97
  .active {
@@ -116,10 +116,10 @@ describe('basic server > attribute rendering', () => {
116
116
  'applies scoped ripple class to multiple elements with dynamic class expressions',
117
117
  async () => {
118
118
  component Basic() {
119
- let selected = track(1);
119
+ let &[selected] = track(1);
120
120
 
121
- <div class={@selected === 0 ? 'selected' : ''}>{`div 1`}</div>
122
- <div class={@selected === 0 ? 'selected' : ''}>{`div 2`}</div>
121
+ <div class={selected === 0 ? 'selected' : ''}>{`div 1`}</div>
122
+ <div class={selected === 0 ? 'selected' : ''}>{`div 2`}</div>
123
123
 
124
124
  <style>
125
125
  div {
@@ -147,9 +147,9 @@ describe('basic server > attribute rendering', () => {
147
147
 
148
148
  it('render dynamic id attribute', async () => {
149
149
  component Basic() {
150
- let count = track(0);
150
+ let &[count] = track(0);
151
151
 
152
- <div id={`item-${@count}`}>{'Dynamic ID'}</div>
152
+ <div id={`item-${count}`}>{'Dynamic ID'}</div>
153
153
  }
154
154
 
155
155
  const { body } = await render(Basic);
@@ -162,9 +162,9 @@ describe('basic server > attribute rendering', () => {
162
162
 
163
163
  it('render dynamic style attribute', async () => {
164
164
  component Basic() {
165
- let color = track('red');
165
+ let &[color] = track('red');
166
166
 
167
- <div style={`color: ${@color}; font-weight: bold;`}>{'Dynamic Style'}</div>
167
+ <div style={`color: ${color}; font-weight: bold;`}>{'Dynamic Style'}</div>
168
168
  }
169
169
 
170
170
  const { body } = await render(Basic);
@@ -178,9 +178,9 @@ describe('basic server > attribute rendering', () => {
178
178
 
179
179
  it('render style attribute as dynamic object', async () => {
180
180
  component Basic() {
181
- let color = track('red');
181
+ let &[color] = track('red');
182
182
 
183
- <div style={{ color: @color, fontWeight: 'bold' }}>{'Dynamic Style'}</div>
183
+ <div style={{ color: color, fontWeight: 'bold' }}>{'Dynamic Style'}</div>
184
184
  }
185
185
 
186
186
  const { body } = await render(Basic);
@@ -194,9 +194,9 @@ describe('basic server > attribute rendering', () => {
194
194
 
195
195
  it('render tracked variable as style attribute', async () => {
196
196
  component Basic() {
197
- let style = track({ color: 'red', fontWeight: 'bold' });
197
+ let &[style] = track({ color: 'red', fontWeight: 'bold' });
198
198
 
199
- <div {@style}>{'Dynamic Style'}</div>
199
+ <div {style}>{'Dynamic Style'}</div>
200
200
  }
201
201
 
202
202
  const { body } = await render(Basic);
@@ -277,10 +277,10 @@ describe('basic server > attribute rendering', () => {
277
277
 
278
278
  it('render dynamic boolean attributes as false', async () => {
279
279
  component Basic() {
280
- let disabled = track(false);
281
- let checked = track(false);
280
+ let &[disabled] = track(false);
281
+ let &[checked] = track(false);
282
282
 
283
- <input type="checkbox" {@disabled} {@checked} />
283
+ <input type="checkbox" {disabled} {checked} />
284
284
  }
285
285
 
286
286
  const { body } = await render(Basic);
@@ -312,10 +312,10 @@ describe('basic server > attribute rendering', () => {
312
312
 
313
313
  it('render dynamic boolean attributes as true', async () => {
314
314
  component Basic() {
315
- let disabled = track(true);
316
- let checked = track(true);
315
+ let &[disabled] = track(true);
316
+ let &[checked] = track(true);
317
317
 
318
- <input type="checkbox" {@disabled} {@checked} />
318
+ <input type="checkbox" {disabled} {checked} />
319
319
  }
320
320
 
321
321
  const { body } = await render(Basic);
@@ -347,10 +347,10 @@ describe('basic server > attribute rendering', () => {
347
347
 
348
348
  it('render multiple dynamic attributes', async () => {
349
349
  component Basic() {
350
- let theme = track('light');
351
- let size = track('medium');
350
+ let &[theme] = track('light');
351
+ let &[size] = track('medium');
352
352
 
353
- <div class={`theme-${@theme} size-${@size}`} data-theme={@theme} data-size={@size}>
353
+ <div class={`theme-${theme} size-${size}`} data-theme={theme} data-size={size}>
354
354
  {'Multiple Dynamic Attributes'}
355
355
  </div>
356
356
  }
@@ -367,12 +367,12 @@ describe('basic server > attribute rendering', () => {
367
367
 
368
368
  it('render conditional attributes', async () => {
369
369
  component Basic() {
370
- let showTitle = track(false);
371
- let showAria = track(false);
370
+ let &[showTitle] = track(false);
371
+ let &[showAria] = track(false);
372
372
 
373
373
  <div
374
- title={@showTitle ? 'This is a title' : undefined}
375
- aria-label={@showAria ? 'Accessible label' : undefined}
374
+ title={showTitle ? 'This is a title' : undefined}
375
+ aria-label={showAria ? 'Accessible label' : undefined}
376
376
  >
377
377
  {'Conditional Attributes'}
378
378
  </div>
@@ -389,14 +389,14 @@ describe('basic server > attribute rendering', () => {
389
389
 
390
390
  it('render spread attributes', async () => {
391
391
  component Basic() {
392
- let attrs = track<TestAttributes>(
392
+ let &[attrs] = track<TestAttributes>(
393
393
  {
394
394
  class: 'initial',
395
395
  id: 'test-1',
396
396
  },
397
397
  );
398
398
 
399
- <div {...@attrs}>{'Spread Attributes'}</div>
399
+ <div {...attrs}>{'Spread Attributes'}</div>
400
400
  }
401
401
 
402
402
  const { body } = await render(Basic);
@@ -411,14 +411,14 @@ describe('basic server > attribute rendering', () => {
411
411
 
412
412
  it('renders with reactive attributes with nested reactive attributes', async () => {
413
413
  component Basic() {
414
- let value = track('parent-class');
414
+ let &[value] = track('parent-class');
415
415
 
416
- <p class={@value}>{'Colored parent value'}</p>
416
+ <p class={value}>{'Colored parent value'}</p>
417
417
 
418
418
  <div>
419
- let nested = track('nested-class');
419
+ let &[nested] = track('nested-class');
420
420
 
421
- <p class={@nested}>{'Colored nested value'}</p>
421
+ <p class={nested}>{'Colored nested value'}</p>
422
422
  </div>
423
423
  }
424
424
 
@@ -107,15 +107,15 @@ describe('basic server > components & composition', () => {
107
107
  }
108
108
 
109
109
  component Basic() {
110
- let clicked = track(false);
110
+ let &[clicked] = track(false);
111
111
 
112
112
  <Card
113
113
  title="Test Card"
114
114
  content="This is a test card"
115
115
  buttonText="Click me"
116
- onAction={() => (@clicked = true)}
116
+ onAction={() => (clicked = true)}
117
117
  />
118
- <div class="status">{@clicked ? 'Clicked' : 'Not clicked'}</div>
118
+ <div class="status">{clicked ? 'Clicked' : 'Not clicked'}</div>
119
119
  }
120
120
 
121
121
  const { body } = await render(Basic);
@@ -139,19 +139,19 @@ describe('basic server > components & composition', () => {
139
139
  text: Tracked<string>;
140
140
  count: Tracked<number>;
141
141
  }>) {
142
- <div class="child-content">{props.@text}</div>
143
- <div class="child-count">{props.@count}</div>
142
+ <div class="child-content">{props.text.value}</div>
143
+ <div class="child-count">{props.count.value}</div>
144
144
  }
145
145
 
146
146
  component Basic() {
147
- let message = track('Hello');
148
- let number = track(1);
147
+ let &[message, messageTracked] = track('Hello');
148
+ let &[number, numberTracked] = track(1);
149
149
 
150
- <ChildComponent text={message} count={number} />
150
+ <ChildComponent text={messageTracked} count={numberTracked} />
151
151
  <button
152
152
  onClick={() => {
153
- @message = @message === 'Hello' ? 'Goodbye' : 'Hello';
154
- @number++;
153
+ message = message === 'Hello' ? 'Goodbye' : 'Hello';
154
+ number++;
155
155
  }}
156
156
  >
157
157
  {'Update Props'}
@@ -15,12 +15,12 @@ describe('basic client', () => {
15
15
 
16
16
  it('renders tracked state updates', async () => {
17
17
  component Counter() {
18
- const count = track(0);
18
+ let &[count] = track(0);
19
19
 
20
- @count++;
21
- @count = @count + 5;
20
+ count++;
21
+ count = count + 5;
22
22
 
23
- <div>{@count}</div>
23
+ <div>{count}</div>
24
24
  }
25
25
 
26
26
  const { body } = await render(Counter);
@@ -34,7 +34,7 @@ describe('basic client', () => {
34
34
  class: { test: boolean };
35
35
  }>) {
36
36
  <div {...rest}>{'Child Component'}</div>
37
- <div>{@count}</div>
37
+ <div>{count.value}</div>
38
38
  }
39
39
 
40
40
  component Parent() {
@@ -53,10 +53,10 @@ describe('basic client', () => {
53
53
  component ObjCounter() {
54
54
  const obj = { count: track(2) };
55
55
 
56
- obj.@count += 3;
57
- obj.@count = obj.@count + 1;
56
+ obj.count.value += 3;
57
+ obj.count.value = obj.count.value + 1;
58
58
 
59
- <div>{obj.@count}</div>
59
+ <div>{obj.count.value}</div>
60
60
  }
61
61
 
62
62
  const { body } = await render(ObjCounter);
@@ -66,11 +66,11 @@ describe('basic client', () => {
66
66
 
67
67
  it('renders spread props with tracked values', async () => {
68
68
  component SpreadProps() {
69
- const id = track('unique-id');
70
- const isActive = track(true);
71
- const styles = track({ color: 'red', fontSize: '16px' });
69
+ let &[id] = track('unique-id');
70
+ let &[isActive] = track(true);
71
+ let &[styles] = track({ color: 'red', fontSize: '16px' });
72
72
 
73
- <div {...{ id: @id, class: { active: @isActive }, style: @styles }}>{'Spread Props'}</div>
73
+ <div {...{ id: id, class: { active: isActive }, style: styles }}>{'Spread Props'}</div>
74
74
  }
75
75
 
76
76
  const { body } = await render(SpreadProps);
@@ -82,14 +82,14 @@ describe('basic client', () => {
82
82
 
83
83
  it('handles AssignExpressions with tracked values or properties correctly', async () => {
84
84
  component Assignments() {
85
- const count = track(0);
85
+ let &[count] = track(0);
86
86
  const obj = { value: track(5) };
87
87
 
88
- @count += 10;
89
- obj.@value *= 2;
88
+ count += 10;
89
+ obj.value.value *= 2;
90
90
 
91
- <div>{@count}</div>
92
- <div>{obj.@value}</div>
91
+ <div>{count}</div>
92
+ <div>{obj.value.value}</div>
93
93
  }
94
94
 
95
95
  const { body } = await render(Assignments);
@@ -99,16 +99,15 @@ describe('basic client', () => {
99
99
 
100
100
  it(`handles derived changes via tracked dependencies' changes`, async () => {
101
101
  component Derived() {
102
- let base = track(5);
103
- let multiplier = track(3);
104
- const derived = track(() => @base * @multiplier);
102
+ let &[base] = track(5);
103
+ let &[multiplier] = track(3);
104
+ let &[derived] = track(() => base * multiplier);
105
105
 
106
- <div>{@derived}</div>
106
+ <div>{derived}</div>
107
107
 
108
- @base += 2;
108
+ base += 2;
109
109
 
110
-
111
- <div>{@derived}</div>
110
+ <div>{derived}</div>
112
111
  }
113
112
 
114
113
  const { body } = await render(Derived);
@@ -118,17 +117,16 @@ describe('basic client', () => {
118
117
 
119
118
  it(`handles derived changes based on another derived's dependencies' changes`, async () => {
120
119
  component NestedDerived() {
121
- let a = track(2);
122
- let b = track(3);
123
- const sum = track(() => @a + @b);
124
- const product = track(() => @sum * 2);
125
-
126
- <div>{@product}</div>
120
+ let &[a] = track(2);
121
+ let &[b] = track(3);
122
+ let &[sum] = track(() => a + b);
123
+ let &[product] = track(() => sum * 2);
127
124
 
128
- @a = 4;
125
+ <div>{product}</div>
129
126
 
127
+ a = 4;
130
128
 
131
- <div>{@product}</div>
129
+ <div>{product}</div>
132
130
  }
133
131
 
134
132
  const { body } = await render(NestedDerived);
@@ -138,20 +136,20 @@ describe('basic client', () => {
138
136
 
139
137
  it('handles lexical scopes correctly', async () => {
140
138
  component LexicalScopes() {
141
- let x = track(1);
142
- <div>{@x}</div>
139
+ let &[x] = track(1);
140
+ <div>{x}</div>
143
141
 
144
142
  <div>
145
- let x = track(10);
146
- {@x}
143
+ let &[x] = track(10);
144
+ {x}
147
145
  </div>
148
146
 
149
147
  <div>
150
- let x = track(12);
151
- {@x}
148
+ let &[x] = track(12);
149
+ {x}
152
150
  <span>
153
- let x = track(15);
154
- {@x}
151
+ let &[x] = track(15);
152
+ {x}
155
153
  </span>
156
154
  </div>
157
155
  }
@@ -8,10 +8,10 @@ describe('composite > props', () => {
8
8
  }
9
9
 
10
10
  component App() {
11
- let foo = track(123);
11
+ let &[foo] = track(123);
12
12
 
13
13
  <Child />
14
- <Child {@foo} />
14
+ <Child {foo} />
15
15
  }
16
16
 
17
17
  const { body } = await render(App);
@@ -42,7 +42,7 @@ describe('composite > props', () => {
42
42
 
43
43
  it('correctly handles no props', async () => {
44
44
  component Child(props: { foo?: Tracked<number> }) {
45
- <div>{props.@foo}</div>
45
+ <div>{props.foo?.value}</div>
46
46
  }
47
47
 
48
48
  component App() {
@@ -65,10 +65,10 @@ describe('composite > props', () => {
65
65
  }
66
66
 
67
67
  component App() {
68
- let foo = track(123);
68
+ let &[foo] = track(123);
69
69
 
70
70
  <Child />
71
- <Child {@foo} />
71
+ <Child {foo} />
72
72
  }
73
73
 
74
74
  const { body } = await render(App);
@@ -81,7 +81,7 @@ describe('composite > props', () => {
81
81
  it('correctly retains prop accessors and reactivity when using rest props', async () => {
82
82
  component Button(props: Props) {
83
83
  const [children, rest] = trackSplit(props, ['children']);
84
- <button {...@rest}>
84
+ <button {...rest.value}>
85
85
  <@children />
86
86
  </button>
87
87
  <style>
@@ -96,9 +96,9 @@ describe('composite > props', () => {
96
96
 
97
97
  component Toggle(props: { pressed: Tracked<boolean> }) {
98
98
  const [pressed, rest] = trackSplit(props, ['pressed']);
99
- const onClick = () => (@pressed = !@pressed);
100
- <Button {...@rest} class={@pressed ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
101
- <Button class={@pressed ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
99
+ const onClick = () => (pressed.value = !pressed.value);
100
+ <Button {...rest.value} class={pressed.value ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
101
+ <Button class={pressed.value ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
102
102
  }
103
103
 
104
104
  component App() {
@@ -19,8 +19,9 @@ describe('server dynamic DOM elements', () => {
19
19
  it('renders static dynamic element from a plain object with a tracked property', async () => {
20
20
  component App() {
21
21
  let obj = { tag: track('div') };
22
+ let tag = obj.tag;
22
23
 
23
- <obj.@tag>{'Hello World'}</obj.@tag>
24
+ <@tag>{'Hello World'}</@tag>
24
25
  }
25
26
 
26
27
  const { body } = await render(App);
@@ -31,8 +32,9 @@ describe('server dynamic DOM elements', () => {
31
32
  it('renders static dynamic element from a tracked object with a tracked property', async () => {
32
33
  component App() {
33
34
  let obj = track({ tag: track('div') });
35
+ let tag = obj.value.tag;
34
36
 
35
- <@obj.@tag>{'Hello World'}</@obj.@tag>
37
+ <@tag>{'Hello World'}</@tag>
36
38
  }
37
39
 
38
40
  const { body } = await render(App);
@@ -45,8 +47,9 @@ describe('server dynamic DOM elements', () => {
45
47
  async () => {
46
48
  component App() {
47
49
  let obj = track({ tag: track('div') });
50
+ let tag = obj.value['tag'];
48
51
 
49
- <@obj.@['tag']>{'Hello World'}</@obj.@['tag']>
52
+ <@tag>{'Hello World'}</@tag>
50
53
  }
51
54
 
52
55
  const { body } = await render(App);
@@ -70,9 +73,9 @@ describe('server dynamic DOM elements', () => {
70
73
  it('handles dynamic element with attributes', async () => {
71
74
  component App() {
72
75
  let tag = track('div');
73
- let className = track('test-class');
76
+ let &[className] = track('test-class');
74
77
 
75
- <@tag class={@className} id="test" data-testid="dynamic-element">{'Content'}</@tag>
78
+ <@tag class={className} id="test" data-testid="dynamic-element">{'Content'}</@tag>
76
79
  }
77
80
  const { body } = await render(App);
78
81
  const { document } = parseHtml(body);
@@ -109,11 +112,9 @@ describe('server dynamic DOM elements', () => {
109
112
  it('handles dynamic element with class object', async () => {
110
113
  component App() {
111
114
  let tag = track('div');
112
- let active = track(true);
115
+ let &[active] = track(true);
113
116
 
114
- <@tag class={{ active: @active, 'dynamic-element': true }}>
115
- {'Element with class object'}
116
- </@tag>
117
+ <@tag class={{ active: active, 'dynamic-element': true }}>{'Element with class object'}</@tag>
117
118
  }
118
119
 
119
120
  const { body } = await render(App);
@@ -263,7 +264,7 @@ describe('server dynamic DOM elements', () => {
263
264
  }>) {
264
265
  const tag = track('button');
265
266
  const [rest] = trackSplit(props, []);
266
- <@tag {...@rest}>{@rest.class}</@tag>
267
+ <@tag {...rest.value}>{rest.value.class}</@tag>
267
268
 
268
269
  <style>
269
270
  .even {
@@ -276,8 +277,8 @@ describe('server dynamic DOM elements', () => {
276
277
  }
277
278
 
278
279
  component App() {
279
- const count = track(0);
280
- <DynamicButton class={@count % 2 ? 'even' : 'odd'} id={@count % 2 ? 'even' : 'odd'} />
280
+ let &[count] = track(0);
281
+ <DynamicButton class={count % 2 ? 'even' : 'odd'} id={count % 2 ? 'even' : 'odd'} />
281
282
  }
282
283
 
283
284
  const { body } = await render(App);