ripple 0.2.16 → 0.2.18
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 +1 -1
- package/src/compiler/phases/3-transform/index.js +7 -1
- package/src/runtime/index.js +2 -0
- package/src/runtime/set.js +179 -0
- package/tests/set.test.ripple +99 -0
- package/types/index.d.ts +12 -0
package/package.json
CHANGED
|
@@ -115,7 +115,13 @@ const visitors = {
|
|
|
115
115
|
if (!context.state.to_ts && node.importKind === 'type') {
|
|
116
116
|
return b.empty;
|
|
117
117
|
}
|
|
118
|
-
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...node,
|
|
121
|
+
specifiers: node.specifiers
|
|
122
|
+
.filter((spec) => spec.importKind !== 'type')
|
|
123
|
+
.map((spec) => context.visit(spec.local)),
|
|
124
|
+
};
|
|
119
125
|
},
|
|
120
126
|
|
|
121
127
|
CallExpression(node, context) {
|
package/src/runtime/index.js
CHANGED
|
@@ -40,6 +40,8 @@ export { flush_sync as flushSync, untrack, deferred } from './internal/client/ru
|
|
|
40
40
|
|
|
41
41
|
export { RippleArray } from './array.js';
|
|
42
42
|
|
|
43
|
+
export { RippleSet } from './set.js';
|
|
44
|
+
|
|
43
45
|
export { keyed } from './internal/client/for.js';
|
|
44
46
|
|
|
45
47
|
export { user_effect as effect } from './internal/client/blocks.js';
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { get, increment, scope, set, tracked } from './internal/client/runtime.js';
|
|
2
|
+
|
|
3
|
+
const introspect_methods = [
|
|
4
|
+
'entries',
|
|
5
|
+
'forEach',
|
|
6
|
+
'keys',
|
|
7
|
+
'values',
|
|
8
|
+
Symbol.iterator
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const compare_other_methods = [
|
|
12
|
+
'isDisjointFrom',
|
|
13
|
+
'isSubsetOf',
|
|
14
|
+
'isSupersetOf',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const new_other_methods = [
|
|
18
|
+
'difference',
|
|
19
|
+
'intersection',
|
|
20
|
+
'symmetricDifference',
|
|
21
|
+
'union',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
let init = false;
|
|
25
|
+
|
|
26
|
+
export class RippleSet extends Set {
|
|
27
|
+
#tracked_size;
|
|
28
|
+
#tracked_items = new Map();
|
|
29
|
+
|
|
30
|
+
constructor(iterable) {
|
|
31
|
+
super();
|
|
32
|
+
|
|
33
|
+
var block = scope();
|
|
34
|
+
|
|
35
|
+
if (iterable) {
|
|
36
|
+
for (var item of iterable) {
|
|
37
|
+
super.add(item);
|
|
38
|
+
this.#tracked_items.set(item, tracked(0, block));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.#tracked_size = tracked(this.size, block);
|
|
43
|
+
|
|
44
|
+
if (!init) {
|
|
45
|
+
init = true;
|
|
46
|
+
this.#init();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#init() {
|
|
51
|
+
var proto = RippleSet.prototype;
|
|
52
|
+
var set_proto = Set.prototype;
|
|
53
|
+
|
|
54
|
+
for (const method of introspect_methods) {
|
|
55
|
+
if (!(method in set_proto)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
proto[method] = function (...v) {
|
|
60
|
+
this.$size;
|
|
61
|
+
|
|
62
|
+
return set_proto[method].apply(this, v);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const method of compare_other_methods) {
|
|
67
|
+
if (!(method in set_proto)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
proto[method] = function (other, ...v) {
|
|
72
|
+
this.$size;
|
|
73
|
+
|
|
74
|
+
if (other instanceof RippleSet) {
|
|
75
|
+
other.$size;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return set_proto[method].apply(this, [other, ...v]);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const method of new_other_methods) {
|
|
83
|
+
if (!(method in set_proto)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
proto[method] = function (other, ...v) {
|
|
88
|
+
this.$size;
|
|
89
|
+
|
|
90
|
+
if (other instanceof RippleSet) {
|
|
91
|
+
other.$size;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return new RippleSet(
|
|
95
|
+
set_proto[method].apply(this, [other, ...v])
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
add(value) {
|
|
102
|
+
var block = scope();
|
|
103
|
+
|
|
104
|
+
if (!super.has(value)) {
|
|
105
|
+
super.add(value);
|
|
106
|
+
this.#tracked_items.set(value, tracked(0, block));
|
|
107
|
+
set(this.#tracked_size, this.size, block);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
delete(value) {
|
|
114
|
+
var block = scope();
|
|
115
|
+
|
|
116
|
+
if (super.has(value)) {
|
|
117
|
+
super.delete(value);
|
|
118
|
+
var t = this.#tracked_items.get(value);
|
|
119
|
+
|
|
120
|
+
if (t) {
|
|
121
|
+
increment(t, block);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.#tracked_items.delete(value);
|
|
125
|
+
set(this.#tracked_size, this.size, block);
|
|
126
|
+
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
has(value) {
|
|
134
|
+
var block = scope();
|
|
135
|
+
var has = super.has(value);
|
|
136
|
+
var tracked_items = this.#tracked_items;
|
|
137
|
+
var t = tracked_items.get(value);
|
|
138
|
+
|
|
139
|
+
if (t === undefined) {
|
|
140
|
+
if (!has) {
|
|
141
|
+
// If the value doesn't exist, track the size in case it's added later
|
|
142
|
+
// but don't create tracked entries willy-nilly to track all possible values
|
|
143
|
+
this.$size;
|
|
144
|
+
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
t = tracked(0, block);
|
|
149
|
+
tracked_items.set(value, t);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
get(t);
|
|
153
|
+
return has;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
clear() {
|
|
157
|
+
var block = scope();
|
|
158
|
+
|
|
159
|
+
if (this.size > 0) {
|
|
160
|
+
for (var [value, t] of this.#tracked_items) {
|
|
161
|
+
increment(t, block);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
super.clear();
|
|
165
|
+
this.#tracked_items.clear();
|
|
166
|
+
set(this.#tracked_size, 0, block);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get $size() {
|
|
171
|
+
return get(this.#tracked_size);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
toJSON() {
|
|
175
|
+
this.$size;
|
|
176
|
+
|
|
177
|
+
return [...this];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mount, flushSync, RippleSet } from 'ripple';
|
|
3
|
+
|
|
4
|
+
describe('RippleSet', () => {
|
|
5
|
+
let container;
|
|
6
|
+
|
|
7
|
+
function render(component) {
|
|
8
|
+
mount(component, {
|
|
9
|
+
target: container
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
container = document.createElement('div');
|
|
15
|
+
document.body.appendChild(container);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
document.body.removeChild(container);
|
|
20
|
+
container = null;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('handles add and delete operations', () => {
|
|
24
|
+
component SetTest() {
|
|
25
|
+
let items = new RippleSet([1, 2, 3]);
|
|
26
|
+
|
|
27
|
+
<button onClick={() => items.add(4)}>{'add'}</button>
|
|
28
|
+
<button onClick={() => items.delete(2)}>{'delete'}</button>
|
|
29
|
+
<Child items={items} />
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
component Child({ items }) {
|
|
33
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
34
|
+
<pre>{items.$size}</pre>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
render(SetTest);
|
|
38
|
+
|
|
39
|
+
const addButton = container.querySelectorAll('button')[0];
|
|
40
|
+
const deleteButton = container.querySelectorAll('button')[1];
|
|
41
|
+
|
|
42
|
+
addButton.click();
|
|
43
|
+
flushSync();
|
|
44
|
+
|
|
45
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,2,3,4]');
|
|
46
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('4');
|
|
47
|
+
|
|
48
|
+
deleteButton.click();
|
|
49
|
+
flushSync();
|
|
50
|
+
|
|
51
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[1,3,4]');
|
|
52
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('3');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('handles clear operation', () => {
|
|
56
|
+
component SetTest() {
|
|
57
|
+
let items = new RippleSet([1, 2, 3]);
|
|
58
|
+
|
|
59
|
+
<button onClick={() => items.clear()}>{'clear'}</button>
|
|
60
|
+
<Child items={items} />
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
component Child({ items }) {
|
|
64
|
+
<pre>{JSON.stringify(items)}</pre>
|
|
65
|
+
<pre>{items.$size}</pre>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
render(SetTest);
|
|
69
|
+
|
|
70
|
+
const clearButton = container.querySelector('button');
|
|
71
|
+
|
|
72
|
+
clearButton.click();
|
|
73
|
+
flushSync();
|
|
74
|
+
|
|
75
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('[]');
|
|
76
|
+
expect(container.querySelectorAll('pre')[1].textContent).toBe('0');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('handles has operation', () => {
|
|
80
|
+
component SetTest() {
|
|
81
|
+
let items = new RippleSet([1, 2, 3]);
|
|
82
|
+
let $hasValue = items.has(2);
|
|
83
|
+
|
|
84
|
+
<button onClick={() => items.delete(2)}>{'delete'}</button>
|
|
85
|
+
<pre>{JSON.stringify($hasValue)}</pre>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
render(SetTest);
|
|
89
|
+
|
|
90
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('true');
|
|
91
|
+
|
|
92
|
+
const deleteButton = container.querySelectorAll('button')[0];
|
|
93
|
+
|
|
94
|
+
deleteButton.click();
|
|
95
|
+
flushSync();
|
|
96
|
+
|
|
97
|
+
expect(container.querySelectorAll('pre')[0].textContent).toBe('false');
|
|
98
|
+
});
|
|
99
|
+
});
|
package/types/index.d.ts
CHANGED
|
@@ -38,3 +38,15 @@ export type Context<T> = {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
export declare function createContext<T>(initialValue: T): Context<T>;
|
|
41
|
+
|
|
42
|
+
export class RippleSet<T> extends Set<T> {
|
|
43
|
+
readonly $size: number;
|
|
44
|
+
isDisjointFrom(other: RippleSet<T> | Set<T>): boolean;
|
|
45
|
+
isSubsetOf(other: RippleSet<T> | Set<T>): boolean;
|
|
46
|
+
isSupersetOf(other: RippleSet<T> | Set<T>): boolean;
|
|
47
|
+
difference(other: RippleSet<T> | Set<T>): RippleSet<T>;
|
|
48
|
+
intersection(other: RippleSet<T> | Set<T>): RippleSet<T>;
|
|
49
|
+
symmetricDifference(other: RippleSet<T> | Set<T>): RippleSet<T>;
|
|
50
|
+
union(other: RippleSet<T> | Set<T>): RippleSet<T>;
|
|
51
|
+
toJSON(): T[];
|
|
52
|
+
}
|