ripple 0.2.215 → 0.3.0

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 (157) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/package.json +16 -7
  3. package/src/compiler/errors.js +1 -1
  4. package/src/compiler/identifier-utils.js +2 -0
  5. package/src/compiler/index.d.ts +2 -6
  6. package/src/compiler/phases/1-parse/index.js +171 -233
  7. package/src/compiler/phases/2-analyze/index.js +216 -16
  8. package/src/compiler/phases/2-analyze/prune.js +2 -2
  9. package/src/compiler/phases/3-transform/client/index.js +326 -94
  10. package/src/compiler/phases/3-transform/segments.js +43 -15
  11. package/src/compiler/phases/3-transform/server/index.js +71 -21
  12. package/src/compiler/scope.js +31 -12
  13. package/src/compiler/source-map-utils.js +4 -6
  14. package/src/compiler/types/acorn.d.ts +11 -0
  15. package/src/compiler/types/estree-jsx.d.ts +11 -0
  16. package/src/compiler/types/estree.d.ts +11 -0
  17. package/src/compiler/types/import.d.ts +32 -18
  18. package/src/compiler/types/index.d.ts +75 -23
  19. package/src/compiler/types/parse.d.ts +7 -10
  20. package/src/compiler/utils.js +48 -0
  21. package/src/runtime/array.js +53 -22
  22. package/src/runtime/date.js +15 -5
  23. package/src/runtime/index-client.js +41 -7
  24. package/src/runtime/index-server.js +7 -7
  25. package/src/runtime/internal/client/bindings.js +2 -2
  26. package/src/runtime/internal/client/blocks.js +40 -1
  27. package/src/runtime/internal/client/context.js +8 -0
  28. package/src/runtime/internal/client/for.js +3 -3
  29. package/src/runtime/internal/client/index.js +32 -5
  30. package/src/runtime/internal/client/render.js +20 -8
  31. package/src/runtime/internal/client/runtime.js +9 -7
  32. package/src/runtime/internal/client/template.js +1 -1
  33. package/src/runtime/internal/client/try.js +15 -22
  34. package/src/runtime/internal/client/utils.js +1 -1
  35. package/src/runtime/internal/server/context.js +8 -0
  36. package/src/runtime/internal/server/index.js +99 -6
  37. package/src/runtime/map.js +7 -7
  38. package/src/runtime/media-query.js +10 -1
  39. package/src/runtime/object.js +6 -6
  40. package/src/runtime/proxy.js +6 -6
  41. package/src/runtime/set.js +11 -11
  42. package/src/runtime/url-search-params.js +13 -2
  43. package/src/runtime/url.js +15 -5
  44. package/src/utils/builders.js +13 -3
  45. package/tests/client/array/array.copy-within.test.ripple +11 -11
  46. package/tests/client/array/array.derived.test.ripple +42 -42
  47. package/tests/client/array/array.iteration.test.ripple +12 -12
  48. package/tests/client/array/array.mutations.test.ripple +25 -25
  49. package/tests/client/array/array.static.test.ripple +103 -106
  50. package/tests/client/array/array.to-methods.test.ripple +8 -8
  51. package/tests/client/async-suspend.test.ripple +94 -0
  52. package/tests/client/basic/basic.attributes.test.ripple +31 -31
  53. package/tests/client/basic/basic.collections.test.ripple +7 -7
  54. package/tests/client/basic/basic.components.test.ripple +48 -10
  55. package/tests/client/basic/basic.errors.test.ripple +111 -30
  56. package/tests/client/basic/basic.events.test.ripple +11 -11
  57. package/tests/client/basic/basic.get-set.test.ripple +18 -18
  58. package/tests/client/basic/basic.reactivity.test.ripple +47 -42
  59. package/tests/client/basic/basic.rendering.test.ripple +7 -7
  60. package/tests/client/basic/basic.utilities.test.ripple +4 -4
  61. package/tests/client/boundaries.test.ripple +7 -7
  62. package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +2 -2
  63. package/tests/client/compiler/compiler.assignments.test.ripple +21 -21
  64. package/tests/client/compiler/compiler.basic.test.ripple +223 -82
  65. package/tests/client/compiler/compiler.tracked-access.test.ripple +8 -9
  66. package/tests/client/composite/composite.dynamic-components.test.ripple +8 -8
  67. package/tests/client/composite/composite.generics.test.ripple +4 -4
  68. package/tests/client/composite/composite.props.test.ripple +9 -9
  69. package/tests/client/composite/composite.reactivity.test.ripple +32 -26
  70. package/tests/client/composite/composite.render.test.ripple +13 -4
  71. package/tests/client/computed-properties.test.ripple +3 -3
  72. package/tests/client/context.test.ripple +3 -3
  73. package/tests/client/css/global-additional-cases.test.ripple +4 -4
  74. package/tests/client/css/style-identifier.test.ripple +49 -41
  75. package/tests/client/date.test.ripple +40 -40
  76. package/tests/client/dynamic-elements.test.ripple +165 -30
  77. package/tests/client/events.test.ripple +25 -25
  78. package/tests/client/for.test.ripple +76 -8
  79. package/tests/client/function-overload.test.ripple +0 -1
  80. package/tests/client/head.test.ripple +7 -7
  81. package/tests/client/html.test.ripple +2 -2
  82. package/tests/client/input-value.test.ripple +174 -176
  83. package/tests/client/map.test.ripple +21 -21
  84. package/tests/client/media-query.test.ripple +4 -4
  85. package/tests/client/object.test.ripple +12 -12
  86. package/tests/client/portal.test.ripple +4 -4
  87. package/tests/client/ref.test.ripple +5 -5
  88. package/tests/client/return.test.ripple +17 -17
  89. package/tests/client/set.test.ripple +16 -16
  90. package/tests/client/svg.test.ripple +6 -7
  91. package/tests/client/switch.test.ripple +10 -10
  92. package/tests/client/tracked-expression.test.ripple +1 -3
  93. package/tests/client/try.test.ripple +56 -4
  94. package/tests/client/url/url.derived.test.ripple +10 -9
  95. package/tests/client/url/url.parsing.test.ripple +10 -10
  96. package/tests/client/url/url.partial-removal.test.ripple +10 -10
  97. package/tests/client/url/url.reactivity.test.ripple +17 -17
  98. package/tests/client/url/url.serialization.test.ripple +4 -4
  99. package/tests/client/url-search-params/url-search-params.derived.test.ripple +11 -10
  100. package/tests/client/url-search-params/url-search-params.initialization.test.ripple +5 -7
  101. package/tests/client/url-search-params/url-search-params.iteration.test.ripple +13 -13
  102. package/tests/client/url-search-params/url-search-params.mutation.test.ripple +19 -19
  103. package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +17 -17
  104. package/tests/client/url-search-params/url-search-params.serialization.test.ripple +5 -5
  105. package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +5 -5
  106. package/tests/hydration/compiled/client/events.js +8 -11
  107. package/tests/hydration/compiled/client/for.js +20 -23
  108. package/tests/hydration/compiled/client/head.js +17 -19
  109. package/tests/hydration/compiled/client/hmr.js +84 -0
  110. package/tests/hydration/compiled/client/html.js +1 -15
  111. package/tests/hydration/compiled/client/if-children.js +7 -9
  112. package/tests/hydration/compiled/client/if.js +5 -7
  113. package/tests/hydration/compiled/client/mixed-control-flow.js +3 -5
  114. package/tests/hydration/compiled/client/portal.js +1 -1
  115. package/tests/hydration/compiled/client/reactivity.js +9 -11
  116. package/tests/hydration/compiled/client/return.js +11 -13
  117. package/tests/hydration/compiled/client/switch.js +4 -6
  118. package/tests/hydration/compiled/server/basic.js +0 -1
  119. package/tests/hydration/compiled/server/composite.js +0 -3
  120. package/tests/hydration/compiled/server/events.js +8 -12
  121. package/tests/hydration/compiled/server/for.js +20 -23
  122. package/tests/hydration/compiled/server/head.js +17 -19
  123. package/tests/hydration/compiled/server/hmr.js +107 -0
  124. package/tests/hydration/compiled/server/html.js +1 -35
  125. package/tests/hydration/compiled/server/if-children.js +7 -11
  126. package/tests/hydration/compiled/server/if.js +5 -7
  127. package/tests/hydration/compiled/server/mixed-control-flow.js +3 -5
  128. package/tests/hydration/compiled/server/portal.js +1 -9
  129. package/tests/hydration/compiled/server/reactivity.js +9 -11
  130. package/tests/hydration/compiled/server/return.js +11 -13
  131. package/tests/hydration/compiled/server/switch.js +4 -6
  132. package/tests/hydration/components/events.ripple +8 -9
  133. package/tests/hydration/components/for.ripple +20 -21
  134. package/tests/hydration/components/head.ripple +6 -8
  135. package/tests/hydration/components/hmr.ripple +34 -0
  136. package/tests/hydration/components/html.ripple +1 -3
  137. package/tests/hydration/components/if-children.ripple +7 -8
  138. package/tests/hydration/components/if.ripple +5 -6
  139. package/tests/hydration/components/mixed-control-flow.ripple +4 -6
  140. package/tests/hydration/components/portal.ripple +1 -1
  141. package/tests/hydration/components/reactivity.ripple +9 -10
  142. package/tests/hydration/components/return.ripple +11 -12
  143. package/tests/hydration/components/switch.ripple +6 -8
  144. package/tests/hydration/hmr.test.js +74 -0
  145. package/tests/server/await.test.ripple +2 -2
  146. package/tests/server/basic.attributes.test.ripple +19 -21
  147. package/tests/server/basic.components.test.ripple +13 -7
  148. package/tests/server/basic.test.ripple +20 -21
  149. package/tests/server/compiler.test.ripple +5 -5
  150. package/tests/server/composite.props.test.ripple +6 -7
  151. package/tests/server/composite.test.ripple +4 -4
  152. package/tests/server/context.test.ripple +1 -3
  153. package/tests/server/dynamic-elements.test.ripple +24 -24
  154. package/tests/server/head.test.ripple +5 -7
  155. package/tests/server/style-identifier.test.ripple +16 -17
  156. package/types/index.d.ts +266 -62
  157. package/types/server.d.ts +6 -6
@@ -1,4 +1,4 @@
1
- import { flushSync, TrackedArray, track } from 'ripple';
1
+ import { flushSync, RippleArray } from 'ripple';
2
2
 
3
3
  describe('for statements', () => {
4
4
  it('renders a simple static array', () => {
@@ -17,7 +17,7 @@ describe('for statements', () => {
17
17
 
18
18
  it('renders a simple dynamic array', () => {
19
19
  component App() {
20
- const items = new TrackedArray('Item 1', 'Item 2', 'Item 3');
20
+ const items = #ripple['Item 1', 'Item 2', 'Item 3'];
21
21
 
22
22
  for (const item of items) {
23
23
  <div class={item}>{item}</div>
@@ -39,7 +39,7 @@ describe('for statements', () => {
39
39
 
40
40
  it('correctly handles intermediate statements in for block', () => {
41
41
  component App() {
42
- const items = new TrackedArray(1, 2, 3);
42
+ const items = #ripple[1, 2, 3];
43
43
 
44
44
  <div>
45
45
  for (const item of items) {
@@ -68,7 +68,7 @@ describe('for statements', () => {
68
68
 
69
69
  it('correctly handles the index in a for...of loop', () => {
70
70
  component App() {
71
- const items = new TrackedArray('a', 'b', 'c');
71
+ const items = #ripple['a', 'b', 'c'];
72
72
 
73
73
  <div>
74
74
  for (let item of items; index i) {
@@ -101,7 +101,7 @@ describe('for statements', () => {
101
101
 
102
102
  it('correctly handles keyed for...of loops', () => {
103
103
  component App() {
104
- let items = track([
104
+ let items = #ripple.track([
105
105
  { id: 1, text: 'Item 1' },
106
106
  { id: 2, text: 'Item 2' },
107
107
  { id: 3, text: 'Item 3' },
@@ -134,9 +134,9 @@ describe('for statements', () => {
134
134
 
135
135
  it('keyed for over derived updates sibling text nodes', () => {
136
136
  component App() {
137
- let count = track(0);
137
+ let count = #ripple.track(0);
138
138
 
139
- const items = track(
139
+ const items = #ripple.track(
140
140
  () => Array.from({ length: @count }).map((_, id) => ({ id, label: `Item ${id}` })),
141
141
  );
142
142
 
@@ -173,9 +173,42 @@ describe('for statements', () => {
173
173
  expect(container.querySelectorAll('.item').length).toBe(2);
174
174
  });
175
175
 
176
+ it('keyed for with 32+ items: full reversal updates values via Map path', () => {
177
+ component App() {
178
+ let items = track(Array.from({ length: 40 }, (_, i) => ({ id: i, text: `Item ${i}` })));
179
+
180
+ <div>
181
+ for (let item of @items; index idx; key item.id) {
182
+ <span class="item">{idx + ':' + item.text}</span>
183
+ }
184
+ </div>
185
+
186
+ <button
187
+ onClick={() => {
188
+ @items = @items.toReversed();
189
+ }}
190
+ >
191
+ {'Reverse'}
192
+ </button>
193
+ }
194
+
195
+ render(App);
196
+
197
+ const getTexts = () => Array.from(container.querySelectorAll('.item')).map(
198
+ (el) => el.textContent,
199
+ );
200
+
201
+ expect(getTexts()).toEqual(Array.from({ length: 40 }, (_, i) => `${i}:Item ${i}`));
202
+
203
+ container.querySelector('button').click();
204
+ flushSync();
205
+
206
+ expect(getTexts()).toEqual(Array.from({ length: 40 }, (_, i) => `${i}:Item ${39 - i}`));
207
+ });
208
+
176
209
  it('handles updating with new objects with same key', () => {
177
210
  component App() {
178
- let items = track([
211
+ let items = #ripple.track([
179
212
  { id: 1, text: 'Item 1' },
180
213
  { id: 2, text: 'Item 2' },
181
214
  { id: 3, text: 'Item 3' },
@@ -211,4 +244,39 @@ describe('for statements', () => {
211
244
 
212
245
  expect(container).toMatchSnapshot();
213
246
  });
247
+
248
+ it('ref-based for with 32+ items: remove from start with shared refs via Map path', () => {
249
+ const objects = Array.from({ length: 50 }, (_, i) => ({ id: i, text: `Obj ${i}` }));
250
+
251
+ component App() {
252
+ let items = track(objects.slice());
253
+
254
+ <div>
255
+ for (const item of @items) {
256
+ <span class="item">{item.text}</span>
257
+ }
258
+ </div>
259
+
260
+ <button
261
+ onClick={() => {
262
+ @items = objects.slice(15).reverse();
263
+ }}
264
+ >
265
+ {'Trim and reverse'}
266
+ </button>
267
+ }
268
+
269
+ render(App);
270
+
271
+ const getTexts = () => Array.from(container.querySelectorAll('.item')).map(
272
+ (el) => el.textContent,
273
+ );
274
+
275
+ expect(getTexts()).toEqual(objects.map((o) => o.text));
276
+
277
+ container.querySelector('button').click();
278
+ flushSync();
279
+
280
+ expect(getTexts()).toEqual(objects.slice(15).reverse().map((o) => o.text));
281
+ });
214
282
  });
@@ -1,6 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
2
  import { mount, flushSync } from 'ripple';
3
-
4
3
  import { test } from './function-overload-import.ripple';
5
4
 
6
5
  describe('function overload import tests', () => {
@@ -1,4 +1,4 @@
1
- import { flushSync, track } from 'ripple';
1
+ import { flushSync } from 'ripple';
2
2
 
3
3
  describe('head elements', () => {
4
4
  let originalTitle: string;
@@ -29,7 +29,7 @@ describe('head elements', () => {
29
29
 
30
30
  it('renders reactive title element', () => {
31
31
  component App() {
32
- let title = track('Initial Title');
32
+ let title = #ripple.track('Initial Title');
33
33
 
34
34
  <head>
35
35
  <title>{@title}</title>
@@ -61,7 +61,7 @@ describe('head elements', () => {
61
61
 
62
62
  it('renders title with template literal', () => {
63
63
  component App() {
64
- let name = track('World');
64
+ let name = #ripple.track('World');
65
65
 
66
66
  <head>
67
67
  <title>{`Hello ${@name}!`}</title>
@@ -90,7 +90,7 @@ describe('head elements', () => {
90
90
 
91
91
  it('renders title with computed value', () => {
92
92
  component App() {
93
- let count = track(0);
93
+ let count = #ripple.track(0);
94
94
  let prefix = 'Count: ';
95
95
 
96
96
  <head>
@@ -122,7 +122,7 @@ describe('head elements', () => {
122
122
 
123
123
  it('handles multiple title updates', () => {
124
124
  component App() {
125
- let step = track(1);
125
+ let step = #ripple.track(1);
126
126
 
127
127
  <head>
128
128
  <title>{`Step ${@step} of 3`}</title>
@@ -172,8 +172,8 @@ describe('head elements', () => {
172
172
 
173
173
  it('renders title with conditional content', () => {
174
174
  component App() {
175
- let showPrefix = track(true);
176
- let title = track('Main Page');
175
+ let showPrefix = #ripple.track(true);
176
+ let title = #ripple.track('Main Page');
177
177
 
178
178
  <head>
179
179
  <title>{@showPrefix ? 'App - ' + @title : @title}</title>
@@ -1,4 +1,4 @@
1
- import { flushSync, track } from 'ripple';
1
+ import { flushSync } from 'ripple';
2
2
 
3
3
  describe('html directive', () => {
4
4
  it('renders static html', () => {
@@ -14,7 +14,7 @@ describe('html directive', () => {
14
14
 
15
15
  it('renders dynamic html', () => {
16
16
  component App() {
17
- let str = track('<div>Test</div>');
17
+ let str = #ripple.track('<div>Test</div>');
18
18
 
19
19
  {html @str}
20
20