ripple 0.2.116 → 0.2.119
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/package.json +16 -16
- package/src/compiler/index.js +20 -1
- package/src/compiler/phases/3-transform/segments.js +99 -57
- package/src/compiler/phases/3-transform/server/index.js +21 -11
- package/src/runtime/index-client.js +1 -1
- package/src/runtime/index-server.js +24 -0
- package/src/runtime/internal/client/runtime.js +10 -0
- package/src/runtime/internal/client/utils.js +0 -8
- package/tests/client/__snapshots__/for.test.ripple.snap +80 -0
- package/tests/client/_etc.test.ripple +5 -0
- package/tests/client/array/array.copy-within.test.ripple +120 -0
- package/tests/client/array/array.derived.test.ripple +495 -0
- package/tests/client/array/array.iteration.test.ripple +115 -0
- package/tests/client/array/array.mutations.test.ripple +385 -0
- package/tests/client/array/array.static.test.ripple +237 -0
- package/tests/client/array/array.to-methods.test.ripple +93 -0
- package/tests/client/basic/__snapshots__/basic.attributes.test.ripple.snap +60 -0
- package/tests/client/basic/__snapshots__/basic.rendering.test.ripple.snap +106 -0
- package/tests/client/basic/__snapshots__/basic.text.test.ripple.snap +49 -0
- package/tests/client/basic/basic.attributes.test.ripple +474 -0
- package/tests/client/basic/basic.collections.test.ripple +94 -0
- package/tests/client/basic/basic.components.test.ripple +225 -0
- package/tests/client/basic/basic.errors.test.ripple +126 -0
- package/tests/client/basic/basic.events.test.ripple +222 -0
- package/tests/client/basic/basic.reactivity.test.ripple +476 -0
- package/tests/client/basic/basic.rendering.test.ripple +204 -0
- package/tests/client/basic/basic.styling.test.ripple +63 -0
- package/tests/client/basic/basic.utilities.test.ripple +25 -0
- package/tests/client/boundaries.test.ripple +2 -21
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.ripple.snap +12 -0
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.ripple.snap +22 -0
- package/tests/client/compiler/compiler.assignments.test.ripple +112 -0
- package/tests/client/compiler/compiler.attributes.test.ripple +95 -0
- package/tests/client/compiler/compiler.basic.test.ripple +203 -0
- package/tests/client/compiler/compiler.regex.test.ripple +87 -0
- package/tests/client/compiler/compiler.typescript.test.ripple +29 -0
- package/tests/client/{__snapshots__/composite.test.ripple.snap → composite/__snapshots__/composite.render.test.ripple.snap} +2 -2
- package/tests/client/composite/composite.dynamic-components.test.ripple +100 -0
- package/tests/client/composite/composite.generics.test.ripple +211 -0
- package/tests/client/composite/composite.props.test.ripple +106 -0
- package/tests/client/composite/composite.reactivity.test.ripple +184 -0
- package/tests/client/composite/composite.render.test.ripple +84 -0
- package/tests/client/computed-properties.test.ripple +2 -21
- package/tests/client/context.test.ripple +5 -22
- package/tests/client/date.test.ripple +1 -20
- package/tests/client/dynamic-elements.test.ripple +16 -24
- package/tests/client/for.test.ripple +4 -23
- package/tests/client/head.test.ripple +11 -23
- package/tests/client/html.test.ripple +1 -20
- package/tests/client/input-value.test.ripple +11 -31
- package/tests/client/map.test.ripple +3 -22
- package/tests/client/media-query.test.ripple +10 -23
- package/tests/client/object.test.ripple +5 -24
- package/tests/client/portal.test.ripple +2 -19
- package/tests/client/ref.test.ripple +8 -26
- package/tests/client/set.test.ripple +3 -22
- package/tests/client/svg.test.ripple +1 -22
- package/tests/client/switch.test.ripple +6 -25
- package/tests/client/tracked-expression.test.ripple +2 -21
- package/tests/client/typescript-generics.test.ripple +0 -21
- package/tests/client/url/url.derived.test.ripple +83 -0
- package/tests/client/url/url.parsing.test.ripple +165 -0
- package/tests/client/url/url.partial-removal.test.ripple +198 -0
- package/tests/client/url/url.reactivity.test.ripple +449 -0
- package/tests/client/url/url.serialization.test.ripple +50 -0
- package/tests/client/url-search-params/url-search-params.derived.test.ripple +84 -0
- package/tests/client/url-search-params/url-search-params.initialization.test.ripple +61 -0
- package/tests/client/url-search-params/url-search-params.iteration.test.ripple +153 -0
- package/tests/client/url-search-params/url-search-params.mutation.test.ripple +343 -0
- package/tests/client/url-search-params/url-search-params.retrieval.test.ripple +160 -0
- package/tests/client/url-search-params/url-search-params.serialization.test.ripple +53 -0
- package/tests/client/url-search-params/url-search-params.tracked-url.test.ripple +55 -0
- package/tests/client.d.ts +12 -0
- package/tests/server/if.test.ripple +66 -0
- package/tests/setup-client.js +28 -0
- package/tsconfig.json +4 -2
- package/types/index.d.ts +5 -1
- package/LICENSE +0 -21
- package/tests/client/__snapshots__/basic.test.ripple.snap +0 -117
- package/tests/client/__snapshots__/compiler.test.ripple.snap +0 -33
- package/tests/client/array.test.ripple +0 -1455
- package/tests/client/basic.test.ripple +0 -1892
- package/tests/client/compiler.test.ripple +0 -541
- package/tests/client/composite.test.ripple +0 -692
- package/tests/client/url-search-params.test.ripple +0 -912
- package/tests/client/url.test.ripple +0 -954
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { flushSync, track, TrackedURLSearchParams } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('TrackedURLSearchParams > retrieval', () => {
|
|
4
|
+
it('handles get operation with reactivity', () => {
|
|
5
|
+
component URLTest() {
|
|
6
|
+
const params = new TrackedURLSearchParams('foo=bar&baz=qux');
|
|
7
|
+
let foo = track(() => params.get('foo'));
|
|
8
|
+
let baz = track(() => params.get('baz'));
|
|
9
|
+
|
|
10
|
+
<button onClick={() => params.set('foo', 'updated')}>{'update foo'}</button>
|
|
11
|
+
<pre>{@foo}</pre>
|
|
12
|
+
<pre>{@baz}</pre>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
render(URLTest);
|
|
16
|
+
|
|
17
|
+
const button = container.querySelector('button');
|
|
18
|
+
|
|
19
|
+
// Initial state
|
|
20
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('bar');
|
|
21
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('qux');
|
|
22
|
+
|
|
23
|
+
// Test update
|
|
24
|
+
button.click();
|
|
25
|
+
flushSync();
|
|
26
|
+
|
|
27
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('updated');
|
|
28
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('qux');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('handles get for nonexistent key', () => {
|
|
32
|
+
component URLTest() {
|
|
33
|
+
const params = new TrackedURLSearchParams('foo=bar');
|
|
34
|
+
let nonexistent = track(() => params.get('nonexistent'));
|
|
35
|
+
|
|
36
|
+
<pre>{String(@nonexistent)}</pre>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
render(URLTest);
|
|
40
|
+
|
|
41
|
+
expect(container.querySelector('pre').textContent).toBe('null');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('handles getAll operation with reactivity', () => {
|
|
45
|
+
component URLTest() {
|
|
46
|
+
const params = new TrackedURLSearchParams('foo=bar&foo=baz');
|
|
47
|
+
let allFoo = track(() => params.getAll('foo'));
|
|
48
|
+
|
|
49
|
+
<button onClick={() => params.append('foo', 'qux')}>{'append foo'}</button>
|
|
50
|
+
<pre>{JSON.stringify(@allFoo)}</pre>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
render(URLTest);
|
|
54
|
+
|
|
55
|
+
const button = container.querySelector('button');
|
|
56
|
+
|
|
57
|
+
// Initial state
|
|
58
|
+
expect(container.querySelector('pre').textContent).toBe('["bar","baz"]');
|
|
59
|
+
|
|
60
|
+
// Test append
|
|
61
|
+
button.click();
|
|
62
|
+
flushSync();
|
|
63
|
+
|
|
64
|
+
expect(container.querySelector('pre').textContent).toBe('["bar","baz","qux"]');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('handles has operation with reactivity', () => {
|
|
68
|
+
component URLTest() {
|
|
69
|
+
const params = new TrackedURLSearchParams('foo=bar');
|
|
70
|
+
let hasFoo = track(() => params.has('foo'));
|
|
71
|
+
let hasBaz = track(() => params.has('baz'));
|
|
72
|
+
|
|
73
|
+
<button onClick={() => params.append('baz', 'qux')}>{'add baz'}</button>
|
|
74
|
+
<button onClick={() => params.delete('foo')}>{'delete foo'}</button>
|
|
75
|
+
<pre>{@hasFoo.toString()}</pre>
|
|
76
|
+
<pre>{@hasBaz.toString()}</pre>
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
render(URLTest);
|
|
80
|
+
|
|
81
|
+
const addButton = container.querySelectorAll('button')[0];
|
|
82
|
+
const deleteButton = container.querySelectorAll('button')[1];
|
|
83
|
+
|
|
84
|
+
// Initial state
|
|
85
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('true');
|
|
86
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('false');
|
|
87
|
+
|
|
88
|
+
// Test add
|
|
89
|
+
addButton.click();
|
|
90
|
+
flushSync();
|
|
91
|
+
|
|
92
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('true');
|
|
93
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('true');
|
|
94
|
+
|
|
95
|
+
// Test delete
|
|
96
|
+
deleteButton.click();
|
|
97
|
+
flushSync();
|
|
98
|
+
|
|
99
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('false');
|
|
100
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('true');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('handles has with specific value', () => {
|
|
104
|
+
component URLTest() {
|
|
105
|
+
const params = new TrackedURLSearchParams('foo=bar&foo=baz');
|
|
106
|
+
let hasBarValue = track(() => params.has('foo', 'bar'));
|
|
107
|
+
let hasQuxValue = track(() => params.has('foo', 'qux'));
|
|
108
|
+
|
|
109
|
+
<button onClick={() => params.append('foo', 'qux')}>{'add qux'}</button>
|
|
110
|
+
<pre>{@hasBarValue.toString()}</pre>
|
|
111
|
+
<pre>{@hasQuxValue.toString()}</pre>
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
render(URLTest);
|
|
115
|
+
|
|
116
|
+
const button = container.querySelector('button');
|
|
117
|
+
|
|
118
|
+
// Initial state
|
|
119
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('true');
|
|
120
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('false');
|
|
121
|
+
|
|
122
|
+
// Test add
|
|
123
|
+
button.click();
|
|
124
|
+
flushSync();
|
|
125
|
+
|
|
126
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('true');
|
|
127
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('true');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('handles size property with reactivity', () => {
|
|
131
|
+
component URLTest() {
|
|
132
|
+
const params = new TrackedURLSearchParams('foo=bar');
|
|
133
|
+
let size = track(() => params.size);
|
|
134
|
+
|
|
135
|
+
<button onClick={() => params.append('baz', 'qux')}>{'add'}</button>
|
|
136
|
+
<button onClick={() => params.delete('foo')}>{'delete'}</button>
|
|
137
|
+
<pre>{@size}</pre>
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
render(URLTest);
|
|
141
|
+
|
|
142
|
+
const addButton = container.querySelectorAll('button')[0];
|
|
143
|
+
const deleteButton = container.querySelectorAll('button')[1];
|
|
144
|
+
|
|
145
|
+
// Initial state
|
|
146
|
+
expect(container.querySelector('pre').textContent).toBe('1');
|
|
147
|
+
|
|
148
|
+
// Test add
|
|
149
|
+
addButton.click();
|
|
150
|
+
flushSync();
|
|
151
|
+
|
|
152
|
+
expect(container.querySelector('pre').textContent).toBe('2');
|
|
153
|
+
|
|
154
|
+
// Test delete
|
|
155
|
+
deleteButton.click();
|
|
156
|
+
flushSync();
|
|
157
|
+
|
|
158
|
+
expect(container.querySelector('pre').textContent).toBe('1');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { flushSync, track, TrackedURLSearchParams } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('TrackedURLSearchParams > serialization', () => {
|
|
4
|
+
it('handles toString method with reactivity', () => {
|
|
5
|
+
component URLTest() {
|
|
6
|
+
const params = new TrackedURLSearchParams('foo=bar');
|
|
7
|
+
let string = track(() => params.toString());
|
|
8
|
+
|
|
9
|
+
<button onClick={() => params.append('baz', 'qux')}>{'add'}</button>
|
|
10
|
+
<pre>{@string}</pre>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
render(URLTest);
|
|
14
|
+
|
|
15
|
+
const button = container.querySelector('button');
|
|
16
|
+
|
|
17
|
+
// Initial state
|
|
18
|
+
expect(container.querySelector('pre').textContent).toBe('foo=bar');
|
|
19
|
+
|
|
20
|
+
// Test add
|
|
21
|
+
button.click();
|
|
22
|
+
flushSync();
|
|
23
|
+
|
|
24
|
+
expect(container.querySelector('pre').textContent).toBe('foo=bar&baz=qux');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('handles special characters encoding', () => {
|
|
28
|
+
component URLTest() {
|
|
29
|
+
const params = new TrackedURLSearchParams();
|
|
30
|
+
|
|
31
|
+
<button onClick={() => params.set('key', 'value with spaces')}>{'add spaces'}</button>
|
|
32
|
+
<button onClick={() => params.set('special', '!@#$%^&*()')}>{'add special'}</button>
|
|
33
|
+
<pre>{params.toString()}</pre>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render(URLTest);
|
|
37
|
+
|
|
38
|
+
const spacesButton = container.querySelectorAll('button')[0];
|
|
39
|
+
const specialButton = container.querySelectorAll('button')[1];
|
|
40
|
+
|
|
41
|
+
// Test spaces
|
|
42
|
+
spacesButton.click();
|
|
43
|
+
flushSync();
|
|
44
|
+
|
|
45
|
+
expect(container.querySelector('pre').textContent).toBe('key=value+with+spaces');
|
|
46
|
+
|
|
47
|
+
// Test special characters
|
|
48
|
+
specialButton.click();
|
|
49
|
+
flushSync();
|
|
50
|
+
|
|
51
|
+
expect(container.querySelector('pre').textContent).toContain('special');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { flushSync, TrackedURL } from 'ripple';
|
|
2
|
+
|
|
3
|
+
describe('TrackedURLSearchParams > TrackedURL integration', () => {
|
|
4
|
+
it('integrates with TrackedURL', () => {
|
|
5
|
+
component URLTest() {
|
|
6
|
+
const url = new TrackedURL('https://example.com?foo=bar');
|
|
7
|
+
const params = url.searchParams;
|
|
8
|
+
|
|
9
|
+
<button onClick={() => params.append('baz', 'qux')}>{'add param'}</button>
|
|
10
|
+
<pre>{url.href}</pre>
|
|
11
|
+
<pre>{params.toString()}</pre>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
render(URLTest);
|
|
15
|
+
|
|
16
|
+
const button = container.querySelector('button');
|
|
17
|
+
|
|
18
|
+
// Initial state
|
|
19
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/?foo=bar');
|
|
20
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('foo=bar');
|
|
21
|
+
|
|
22
|
+
// Test add param - should update URL
|
|
23
|
+
button.click();
|
|
24
|
+
flushSync();
|
|
25
|
+
|
|
26
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/?foo=bar&baz=qux');
|
|
27
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('foo=bar&baz=qux');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('handles empty search string in URL', () => {
|
|
31
|
+
component URLTest() {
|
|
32
|
+
const url = new TrackedURL('https://example.com');
|
|
33
|
+
const params = url.searchParams;
|
|
34
|
+
|
|
35
|
+
<button onClick={() => params.append('foo', 'bar')}>{'add first param'}</button>
|
|
36
|
+
<pre>{url.href}</pre>
|
|
37
|
+
<pre>{params.size}</pre>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
render(URLTest);
|
|
41
|
+
|
|
42
|
+
const button = container.querySelector('button');
|
|
43
|
+
|
|
44
|
+
// Initial state - no search params
|
|
45
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/');
|
|
46
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('0');
|
|
47
|
+
|
|
48
|
+
// Test add first param
|
|
49
|
+
button.click();
|
|
50
|
+
flushSync();
|
|
51
|
+
|
|
52
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/?foo=bar');
|
|
53
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('1');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare var container: HTMLDivElement;
|
|
2
|
+
declare var error: string | undefined;
|
|
3
|
+
declare function render(component: () => void): void;
|
|
4
|
+
|
|
5
|
+
interface HTMLElement {
|
|
6
|
+
// We don't care about checking if it returned an element or null in tests
|
|
7
|
+
// because if it returned null, those tests will fail anyway. This
|
|
8
|
+
// typing drastically simplifies testing: you don't have to check if the
|
|
9
|
+
// query returned null or an actual element, and you don't have to do
|
|
10
|
+
// optional chaining everywhere (elem?.textContent)
|
|
11
|
+
querySelector(selectors: string): HTMLElement;
|
|
12
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { render } from 'ripple/server';
|
|
3
|
+
|
|
4
|
+
describe('if statements in SSR', () => {
|
|
5
|
+
it('renders if block when condition is true', async () => {
|
|
6
|
+
component App() {
|
|
7
|
+
let condition = true;
|
|
8
|
+
|
|
9
|
+
if (condition) {
|
|
10
|
+
<div>{'If block'}</div>
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { body } = await render(App);
|
|
15
|
+
expect(body).toBe('<div>If block</div>');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('renders else block when condition is false', async () => {
|
|
19
|
+
component App() {
|
|
20
|
+
let condition = false;
|
|
21
|
+
|
|
22
|
+
if (condition) {
|
|
23
|
+
<div>{'If block'}</div>
|
|
24
|
+
} else {
|
|
25
|
+
<div>{'Else block'}</div>
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { body } = await render(App);
|
|
30
|
+
expect(body).toBe('<div>Else block</div>');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('renders else if block when condition is true', async () => {
|
|
34
|
+
component App() {
|
|
35
|
+
let value = 'b';
|
|
36
|
+
|
|
37
|
+
if (value === 'a') {
|
|
38
|
+
<div>{'Case A'}</div>
|
|
39
|
+
} else if (value === 'b') {
|
|
40
|
+
<div>{'Case B'}</div>
|
|
41
|
+
} else {
|
|
42
|
+
<div>{'Default Case'}</div>
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { body } = await render(App);
|
|
47
|
+
expect(body).toBe('<div>Case B</div>');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('renders final else block in an if-else if-else chain', async () => {
|
|
51
|
+
component App() {
|
|
52
|
+
let value = 'c';
|
|
53
|
+
|
|
54
|
+
if (value === 'a') {
|
|
55
|
+
<div>{'Case A'}</div>
|
|
56
|
+
} else if (value === 'b') {
|
|
57
|
+
<div>{'Case B'}</div>
|
|
58
|
+
} else {
|
|
59
|
+
<div>{'Default Case'}</div>
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { body } = await render(App);
|
|
64
|
+
expect(body).toBe('<div>Default Case</div>');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mount } from 'ripple';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {() => void} component
|
|
6
|
+
*/
|
|
7
|
+
globalThis.render = function render(component) {
|
|
8
|
+
mount(component, {
|
|
9
|
+
target: /** @type {HTMLDivElement} */ (globalThis.container)
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
globalThis.container = /** @type {HTMLDivElement} */ (document.createElement('div'));
|
|
15
|
+
document.body.appendChild(globalThis.container);
|
|
16
|
+
|
|
17
|
+
globalThis.error = undefined;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
// Container is guaranteed to exist in all tests, so it was easier to type it without undefined.
|
|
22
|
+
// And when we unset it, we just type-cast it to HTMLDivElement to avoid TS errors, because we
|
|
23
|
+
// know it's guaranteed to exist in the next test again.
|
|
24
|
+
document.body.removeChild(/** @type {HTMLDivElement} */ (globalThis.container));
|
|
25
|
+
globalThis.container = /** @type {HTMLDivElement} */ (/** @type {unknown} */(undefined));
|
|
26
|
+
|
|
27
|
+
globalThis.error = undefined;
|
|
28
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"noErrorTruncation": true,
|
|
11
11
|
"allowSyntheticDefaultImports": true,
|
|
12
12
|
"verbatimModuleSyntax": true,
|
|
13
|
-
"types": ["node"],
|
|
13
|
+
"types": ["node", "vitest/globals"],
|
|
14
14
|
"jsx": "preserve",
|
|
15
15
|
"jsxImportSource": "ripple",
|
|
16
16
|
"strict": true,
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
"include": [
|
|
24
24
|
"./*.js",
|
|
25
25
|
"./src/",
|
|
26
|
-
"./tests
|
|
26
|
+
"./tests/**/*.test.ripple",
|
|
27
|
+
"./tests/**/*.d.ts",
|
|
28
|
+
"./tests/**/*.js"
|
|
27
29
|
]
|
|
28
30
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare function tick(): Promise<void>;
|
|
|
9
9
|
|
|
10
10
|
export declare function untrack<T>(fn: () => T): T;
|
|
11
11
|
|
|
12
|
-
export declare function flushSync<T>(fn
|
|
12
|
+
export declare function flushSync<T>(fn?: () => T): T;
|
|
13
13
|
|
|
14
14
|
export declare function effect(fn: (() => void) | (() => () => void)): void;
|
|
15
15
|
|
|
@@ -105,6 +105,10 @@ type SplitResult<T extends Props, K extends readonly (keyof T)[]> = [
|
|
|
105
105
|
Tracked<RestKeys<T, K>>,
|
|
106
106
|
];
|
|
107
107
|
|
|
108
|
+
export declare function get<V>(tracked: Tracked<V>): V;
|
|
109
|
+
|
|
110
|
+
export declare function set<V>(tracked: Tracked<V>, value: V): void;
|
|
111
|
+
|
|
108
112
|
// Overload for function values - infers the return type of the function
|
|
109
113
|
export declare function track<V>(
|
|
110
114
|
value: () => V,
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Dominic Gannaway
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
-
|
|
3
|
-
exports[`basic client > basic operations 1`] = `
|
|
4
|
-
<div>
|
|
5
|
-
<div>
|
|
6
|
-
0
|
|
7
|
-
</div>
|
|
8
|
-
<div>
|
|
9
|
-
2
|
|
10
|
-
</div>
|
|
11
|
-
<div>
|
|
12
|
-
5
|
|
13
|
-
</div>
|
|
14
|
-
<div>
|
|
15
|
-
2
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
</div>
|
|
19
|
-
`;
|
|
20
|
-
|
|
21
|
-
exports[`basic client > handles boolean attributes with no prop value provides 1`] = `
|
|
22
|
-
<div>
|
|
23
|
-
<div
|
|
24
|
-
class="container"
|
|
25
|
-
>
|
|
26
|
-
<button
|
|
27
|
-
disabled=""
|
|
28
|
-
>
|
|
29
|
-
Button
|
|
30
|
-
</button>
|
|
31
|
-
<input
|
|
32
|
-
checked=""
|
|
33
|
-
type="checkbox"
|
|
34
|
-
/>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
</div>
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
exports[`basic client > handles boolean props correctly 1`] = `
|
|
41
|
-
<div>
|
|
42
|
-
<div
|
|
43
|
-
data-disabled=""
|
|
44
|
-
/>
|
|
45
|
-
<input
|
|
46
|
-
disabled=""
|
|
47
|
-
/>
|
|
48
|
-
<!---->
|
|
49
|
-
|
|
50
|
-
</div>
|
|
51
|
-
`;
|
|
52
|
-
|
|
53
|
-
exports[`basic client > render semi-dynamic text 1`] = `
|
|
54
|
-
<div>
|
|
55
|
-
<div>
|
|
56
|
-
Hello World
|
|
57
|
-
</div>
|
|
58
|
-
|
|
59
|
-
</div>
|
|
60
|
-
`;
|
|
61
|
-
|
|
62
|
-
exports[`basic client > render spread props without duplication 1`] = `
|
|
63
|
-
<div>
|
|
64
|
-
<div>
|
|
65
|
-
<input
|
|
66
|
-
id="vehicle1"
|
|
67
|
-
name="car"
|
|
68
|
-
type="checkbox"
|
|
69
|
-
value="Bike"
|
|
70
|
-
/>
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
</div>
|
|
74
|
-
`;
|
|
75
|
-
|
|
76
|
-
exports[`basic client > render static attributes 1`] = `
|
|
77
|
-
<div>
|
|
78
|
-
<div
|
|
79
|
-
class="foo"
|
|
80
|
-
id="bar"
|
|
81
|
-
style="color: red;"
|
|
82
|
-
>
|
|
83
|
-
Hello World
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
</div>
|
|
87
|
-
`;
|
|
88
|
-
|
|
89
|
-
exports[`basic client > render static text 1`] = `
|
|
90
|
-
<div>
|
|
91
|
-
<div>
|
|
92
|
-
Hello World
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
</div>
|
|
96
|
-
`;
|
|
97
|
-
|
|
98
|
-
exports[`basic client > renders simple JS expression logic correctly 1`] = `
|
|
99
|
-
<div>
|
|
100
|
-
<div>
|
|
101
|
-
{"0":"Test"}
|
|
102
|
-
</div>
|
|
103
|
-
<div>
|
|
104
|
-
1
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
</div>
|
|
108
|
-
`;
|
|
109
|
-
|
|
110
|
-
exports[`basic client > should handle lexical scopes correctly 1`] = `
|
|
111
|
-
<div>
|
|
112
|
-
<section>
|
|
113
|
-
Nested scope variable
|
|
114
|
-
</section>
|
|
115
|
-
|
|
116
|
-
</div>
|
|
117
|
-
`;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
-
|
|
3
|
-
exports[`compiler success tests > compiles TSInstantiationExpression 1`] = `
|
|
4
|
-
"import * as _$_ from 'ripple/internal/client';
|
|
5
|
-
|
|
6
|
-
function makeBox(value) {
|
|
7
|
-
return { value };
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const makeStringBox = (makeBox);
|
|
11
|
-
const stringBox = makeStringBox('abc');
|
|
12
|
-
const ErrorMap = (Map);
|
|
13
|
-
const errorMap = new ErrorMap();"
|
|
14
|
-
`;
|
|
15
|
-
|
|
16
|
-
exports[`compiler success tests > compiles tracked values in effect with assignment expression 1`] = `"state.count = _$_.get(count);"`;
|
|
17
|
-
|
|
18
|
-
exports[`compiler success tests > compiles tracked values in effect with update expressions 1`] = `
|
|
19
|
-
"_$_.with_scope(__block, () => untrack(() => {
|
|
20
|
-
state.preIncrement = _$_.update_pre(count, __block);
|
|
21
|
-
state.postIncrement = _$_.update(count, __block);
|
|
22
|
-
state.preDecrement = _$_.update_pre(count, __block, -1);
|
|
23
|
-
state.postDecrement = _$_.update(count, __block, -1);
|
|
24
|
-
}));"
|
|
25
|
-
`;
|
|
26
|
-
|
|
27
|
-
exports[`compiler success tests > removes type assertions from function parameters and leaves default values 1`] = `
|
|
28
|
-
"import * as _$_ from 'ripple/internal/client';
|
|
29
|
-
|
|
30
|
-
function getString(e = 'test') {
|
|
31
|
-
return e;
|
|
32
|
-
}"
|
|
33
|
-
`;
|