ripple 0.3.43 → 0.3.44

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # ripple
2
2
 
3
+ ## 0.3.44
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ [[`f5a3c1b`](https://github.com/Ripple-TS/ripple/commit/f5a3c1b9e915c250c8cd1a7dcf4e80c44abe720f)]:
9
+ - @tsrx/ripple@0.0.26
10
+ - ripple@0.3.44
11
+
3
12
  ## 0.3.43
4
13
 
5
14
  ### Patch Changes
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Ripple is an elegant TypeScript UI framework",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.3.43",
6
+ "version": "0.3.44",
7
7
  "type": "module",
8
8
  "module": "src/runtime/index-client.js",
9
9
  "main": "src/runtime/index-client.js",
@@ -76,7 +76,7 @@
76
76
  "esm-env": "^1.2.2",
77
77
  "@types/estree": "^1.0.8",
78
78
  "@types/estree-jsx": "^1.0.5",
79
- "@tsrx/ripple": "0.0.25"
79
+ "@tsrx/ripple": "0.0.26"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@types/node": "^24.3.0",
@@ -84,9 +84,9 @@
84
84
  "typescript": "^5.9.3",
85
85
  "@volar/language-core": "~2.4.28",
86
86
  "vscode-languageserver-types": "^3.17.5",
87
- "@tsrx/core": "0.0.23"
87
+ "@tsrx/core": "0.0.24"
88
88
  },
89
89
  "peerDependencies": {
90
- "ripple": "0.3.43"
90
+ "ripple": "0.3.44"
91
91
  }
92
92
  }
@@ -882,6 +882,22 @@ export component App() {}
882
882
  );
883
883
  });
884
884
 
885
+ it('does not let nested for...of continues satisfy an outer if body', () => {
886
+ const source = `
887
+ export component App({ items }: { items: string[] }) {
888
+ if (items.length) {
889
+ for (const item of items) {
890
+ if (!item) continue
891
+ }
892
+ }
893
+ }`;
894
+
895
+ const result = compile(source, 'test.tsrx', { collect: true });
896
+ expect(result.errors.map((error) => error.message)).toContain(
897
+ 'Component if statements must contain a template in their "then" body. Move the if statement into an effect if it does not render anything.',
898
+ );
899
+ });
900
+
885
901
  it('preserves class extends generic type arguments in volar output', () => {
886
902
  const source = `class StringMap extends Map<string, string> {}
887
903
  export component App() {}`;
@@ -1,4 +1,5 @@
1
1
  import { RippleArray, flushSync, track } from 'ripple';
2
+ import { compile } from '@tsrx/ripple';
2
3
 
3
4
  describe('for statements', () => {
4
5
  it('renders a simple static array', () => {
@@ -15,6 +16,71 @@ describe('for statements', () => {
15
16
  expect(container).toMatchSnapshot();
16
17
  });
17
18
 
19
+ it('allows continue to skip an iteration', () => {
20
+ component App() {
21
+ const items = ['Item 1', '', 'Item 3'];
22
+
23
+ for (const item of items) {
24
+ if (!item) continue;
25
+ <div class="item">{item}</div>
26
+ }
27
+ }
28
+
29
+ render(App);
30
+
31
+ expect(Array.from(container.querySelectorAll('.item')).map((el) => el.textContent)).toEqual([
32
+ 'Item 1',
33
+ 'Item 3',
34
+ ]);
35
+ });
36
+
37
+ it('allows continue after setup statements to skip an iteration', () => {
38
+ const skipped = [];
39
+
40
+ component App() {
41
+ const items = ['Item 1', '', 'Item 3'];
42
+
43
+ for (const item of items) {
44
+ if (!item) {
45
+ skipped.push('skip');
46
+ continue;
47
+ }
48
+ <div class="item">{item}</div>
49
+ }
50
+ }
51
+
52
+ render(App);
53
+
54
+ expect(skipped).toEqual(['skip']);
55
+ expect(Array.from(container.querySelectorAll('.item')).map((el) => el.textContent)).toEqual([
56
+ 'Item 1',
57
+ 'Item 3',
58
+ ]);
59
+ });
60
+
61
+ it('does not emit JavaScript continue in for...of skip callbacks', () => {
62
+ const { js } = compile(
63
+ `component App() {
64
+ const items = ['Item 1', '', 'Item 3'];
65
+ const skipped = [];
66
+
67
+ for (const item of items) {
68
+ if (!item) {
69
+ skipped.push('skip');
70
+ continue;
71
+ }
72
+ <div class="item">{item}</div>
73
+ }
74
+ }`,
75
+ 'App.tsrx',
76
+ { mode: 'client' },
77
+ );
78
+
79
+ expect(js.code).toContain('skipped.push(\'skip\')');
80
+ expect(js.code).not.toContain('continue;');
81
+ expect(js.code).not.toMatch(/continue;\s*return/);
82
+ });
83
+
18
84
  it('renders a simple dynamic array', () => {
19
85
  component App() {
20
86
  const items = new RippleArray('Item 1', 'Item 2', 'Item 3');
@@ -95,4 +95,71 @@ describe('for statements in SSR', () => {
95
95
  '<div class="Item 1 0">Item 1 0</div><div class="Item 2 1">Item 2 1</div><div class="Item 3 2">Item 3 2</div>',
96
96
  );
97
97
  });
98
+
99
+ it('allows continue to skip a for...of iteration', async () => {
100
+ component App() {
101
+ const items = ['Item 1', '', 'Item 3'];
102
+
103
+ for (const item of items) {
104
+ if (!item) continue;
105
+ <div>{item}</div>
106
+ }
107
+ }
108
+
109
+ const { body } = await render(App);
110
+ expect(body).toBeHtml('<div>Item 1</div><div>Item 3</div>');
111
+ });
112
+
113
+ it('allows ordinary function control flow inside for...of loops', async () => {
114
+ component App() {
115
+ const items = ['Item 1', '', 'Item 3'];
116
+
117
+ for (const item of items) {
118
+ function label(value) {
119
+ for (let i = 0; i < 1; i++) {
120
+ while (i < 0) {
121
+ break;
122
+ }
123
+ if (!value) return 'missing';
124
+ }
125
+ return value;
126
+ }
127
+
128
+ <div>{label(item)}</div>
129
+ }
130
+ }
131
+
132
+ const { body } = await render(App);
133
+ expect(body).toBeHtml('<div>Item 1</div><div>missing</div><div>Item 3</div>');
134
+ });
135
+
136
+ it('throws for return statements inside for...of loops', () => {
137
+ expect(
138
+ () => compile(
139
+ `component App(items) {
140
+ for (const item of items) {
141
+ if (!item) return
142
+ <div>{item}</div>
143
+ }
144
+ }`,
145
+ 'App.tsrx',
146
+ { mode: 'server' },
147
+ ),
148
+ ).toThrow('Return statements are not allowed inside component for...of loops');
149
+ });
150
+
151
+ it('throws for break statements targeting for...of loops', () => {
152
+ expect(
153
+ () => compile(
154
+ `component App(items) {
155
+ for (const item of items) {
156
+ if (!item) break
157
+ <div>{item}</div>
158
+ }
159
+ }`,
160
+ 'App.tsrx',
161
+ { mode: 'server' },
162
+ ),
163
+ ).toThrow('Break statements are not allowed inside component for...of loops');
164
+ });
98
165
  });