@esportsplus/reactivity 0.12.3 → 0.13.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.
- package/build/constants.d.ts +2 -1
- package/build/constants.js +2 -1
- package/build/reactive/array.d.ts +5 -62
- package/build/reactive/array.js +183 -169
- package/build/reactive/index.d.ts +4 -2
- package/build/reactive/object.d.ts +5 -2
- package/build/reactive/object.js +33 -32
- package/build/system.js +26 -19
- package/build/types.d.ts +2 -4
- package/package.json +2 -2
- package/src/constants.ts +3 -0
- package/src/reactive/array.ts +213 -218
- package/src/reactive/index.ts +4 -6
- package/src/reactive/object.ts +47 -38
- package/src/system.ts +33 -23
- package/src/types.ts +2 -7
package/src/reactive/array.ts
CHANGED
|
@@ -1,304 +1,246 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isNumber } from '@esportsplus/utilities';
|
|
2
2
|
import { REACTIVE_ARRAY } from '~/constants';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
3
|
+
import { dispose as d, isComputed, read } from '~/system';
|
|
4
|
+
import { Infer } from '~/types';
|
|
5
|
+
import { isReactiveObject } from './object';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
type API<T> = Infer<T
|
|
8
|
+
type API<T> = Infer<T[]> & {
|
|
9
|
+
clear: () => void;
|
|
10
|
+
dispose: () => void;
|
|
11
|
+
};
|
|
9
12
|
|
|
10
13
|
type Events<T> = {
|
|
14
|
+
clear: undefined,
|
|
11
15
|
pop: {
|
|
12
|
-
item:
|
|
16
|
+
item: T;
|
|
13
17
|
};
|
|
14
18
|
push: {
|
|
15
|
-
items:
|
|
19
|
+
items: T[];
|
|
16
20
|
};
|
|
17
21
|
reverse: undefined;
|
|
18
22
|
set: {
|
|
19
23
|
index: number;
|
|
20
|
-
item:
|
|
24
|
+
item: T;
|
|
21
25
|
};
|
|
22
26
|
shift: {
|
|
23
|
-
item:
|
|
27
|
+
item: T;
|
|
24
28
|
};
|
|
25
29
|
sort: undefined;
|
|
26
30
|
splice: {
|
|
27
31
|
deleteCount: number;
|
|
28
|
-
items:
|
|
32
|
+
items: T[];
|
|
29
33
|
start: number;
|
|
30
34
|
};
|
|
31
35
|
unshift: {
|
|
32
|
-
items:
|
|
36
|
+
items: T[];
|
|
33
37
|
};
|
|
34
38
|
};
|
|
35
39
|
|
|
36
|
-
type Item<T> = T | Computed<T> | API<T> | ReactiveObject< T extends Record<PropertyKey, unknown> ? T : never >;
|
|
37
|
-
|
|
38
40
|
type Listener<V> = {
|
|
39
41
|
once?: boolean;
|
|
40
42
|
(value: V): void;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
|
-
type
|
|
44
|
-
T extends Record<PropertyKey, unknown>
|
|
45
|
-
? ReactiveObject<T>
|
|
46
|
-
: T extends Array<infer U>
|
|
47
|
-
? API<U>
|
|
48
|
-
: T;
|
|
49
|
-
|
|
45
|
+
type Listeners = Record<string, (Listener<any> | null)[]>;
|
|
50
46
|
|
|
51
|
-
class ReactiveArray<T> {
|
|
52
|
-
[REACTIVE_ARRAY] = true;
|
|
53
|
-
disposables: number = 0;
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
private proxy: API<T>;
|
|
48
|
+
function at<T>(data: T[], i: number) {
|
|
49
|
+
let value = data[i];
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.data = data;
|
|
62
|
-
this.proxy = proxy;
|
|
51
|
+
if (isComputed(value)) {
|
|
52
|
+
return read(value);
|
|
63
53
|
}
|
|
64
54
|
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
function cleanup<T>(item: T) {
|
|
59
|
+
if (isReactiveObject(item)) {
|
|
60
|
+
item.dispose();
|
|
68
61
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (n > this.data.length) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
this.splice(n);
|
|
62
|
+
else if (isComputed(item)) {
|
|
63
|
+
d(item);
|
|
76
64
|
}
|
|
65
|
+
}
|
|
77
66
|
|
|
67
|
+
function clear<T>(data: T[], listeners: Listeners) {
|
|
68
|
+
dispose(data);
|
|
69
|
+
dispatch(listeners, 'clear');
|
|
70
|
+
}
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
else if (isComputed(item)) {
|
|
84
|
-
dispose(item);
|
|
85
|
-
}
|
|
72
|
+
function dispatch<T, K extends keyof Events<T>, V>(listeners: Listeners, event: K, value?: V) {
|
|
73
|
+
if (listeners === null || listeners[event] === undefined) {
|
|
74
|
+
return;
|
|
86
75
|
}
|
|
87
76
|
|
|
77
|
+
let bucket = listeners[event];
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
let
|
|
79
|
+
for (let i = 0, n = bucket.length; i < n; i++) {
|
|
80
|
+
let listener = bucket[i];
|
|
91
81
|
|
|
92
|
-
if (
|
|
93
|
-
|
|
82
|
+
if (listener === null) {
|
|
83
|
+
continue;
|
|
94
84
|
}
|
|
95
85
|
|
|
96
|
-
|
|
97
|
-
|
|
86
|
+
try {
|
|
87
|
+
listener(value);
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
if (listener.once !== undefined) {
|
|
90
|
+
bucket[i] = null;
|
|
91
|
+
}
|
|
102
92
|
}
|
|
93
|
+
catch {
|
|
94
|
+
bucket[i] = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
103
98
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
for (let i = 0, n = listeners.length; i < n; i++) {
|
|
107
|
-
let listener = listeners[i];
|
|
108
|
-
|
|
109
|
-
if (listener === null) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
99
|
+
function dispose<T>(data: T[]) {
|
|
100
|
+
let item;
|
|
112
101
|
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
while (item = data.pop()) {
|
|
103
|
+
cleanup(item);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
115
106
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
107
|
+
function map<T, R>(
|
|
108
|
+
data: T[],
|
|
109
|
+
proxy: API<T>,
|
|
110
|
+
fn: (this: API<T>, value: T, i: number) => R,
|
|
111
|
+
i?: number,
|
|
112
|
+
n?: number
|
|
113
|
+
) {
|
|
114
|
+
if (i === undefined) {
|
|
115
|
+
i = 0;
|
|
124
116
|
}
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
this.cleanup(this.data[i]);
|
|
129
|
-
}
|
|
118
|
+
if (n === undefined) {
|
|
119
|
+
n = data.length;
|
|
130
120
|
}
|
|
131
121
|
|
|
132
|
-
|
|
133
|
-
fn: (this: API<T>, value: Value<T>, i: number) => R,
|
|
134
|
-
i?: number,
|
|
135
|
-
n?: number
|
|
136
|
-
) {
|
|
137
|
-
let { data, proxy } = this,
|
|
138
|
-
values: R[] = [];
|
|
122
|
+
n = Math.min(n, data.length);
|
|
139
123
|
|
|
140
|
-
|
|
141
|
-
i = 0;
|
|
142
|
-
}
|
|
124
|
+
let values: R[] = new Array(n - i);
|
|
143
125
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
126
|
+
for (; i < n; i++) {
|
|
127
|
+
let item = data[i];
|
|
147
128
|
|
|
148
|
-
|
|
129
|
+
values[i] = fn.call(
|
|
130
|
+
proxy,
|
|
131
|
+
(isComputed(item) ? item.value : item) as T,
|
|
132
|
+
i
|
|
133
|
+
);
|
|
134
|
+
}
|
|
149
135
|
|
|
150
|
-
|
|
151
|
-
|
|
136
|
+
return values;
|
|
137
|
+
}
|
|
152
138
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
proxy,
|
|
156
|
-
(isComputed(item) ? item.value : item) as Value<T>,
|
|
157
|
-
i
|
|
158
|
-
)
|
|
159
|
-
);
|
|
160
|
-
}
|
|
139
|
+
function on<T, K extends keyof Events<T>>(listeners: Listeners, event: K, listener: Listener<Events<T>[K]>) {
|
|
140
|
+
let bucket = listeners[event];
|
|
161
141
|
|
|
162
|
-
|
|
142
|
+
if (bucket === undefined) {
|
|
143
|
+
listeners[event] = [listener];
|
|
163
144
|
}
|
|
145
|
+
else {
|
|
146
|
+
let hole = bucket.length;
|
|
164
147
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.listeners = { [event]: [listener] };
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
let listeners = this.listeners[event];
|
|
148
|
+
for (let i = 0, n = hole; i < n; i++) {
|
|
149
|
+
let l = bucket[i];
|
|
171
150
|
|
|
172
|
-
if (
|
|
173
|
-
|
|
151
|
+
if (l === listener) {
|
|
152
|
+
return;
|
|
174
153
|
}
|
|
175
|
-
else if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (i === -1) {
|
|
179
|
-
listeners.push(listener);
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
listeners[i] = listener;
|
|
183
|
-
}
|
|
154
|
+
else if (l === null && hole === n) {
|
|
155
|
+
hole = i;
|
|
184
156
|
}
|
|
185
157
|
}
|
|
186
|
-
}
|
|
187
158
|
|
|
188
|
-
|
|
189
|
-
listener.once = true;
|
|
190
|
-
this.on(event, listener);
|
|
159
|
+
bucket[hole] = listener;
|
|
191
160
|
}
|
|
161
|
+
}
|
|
192
162
|
|
|
193
|
-
|
|
194
|
-
|
|
163
|
+
function once<T, K extends keyof Events<T>>(listeners: Listeners, event: K, listener: Listener<Events<T>[K]>) {
|
|
164
|
+
listener.once = true;
|
|
165
|
+
on(listeners, event, listener);
|
|
166
|
+
}
|
|
195
167
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.dispatch('pop', { item });
|
|
199
|
-
}
|
|
168
|
+
function pop<T>(data: T[], listeners: Listeners) {
|
|
169
|
+
let item = data.pop();
|
|
200
170
|
|
|
201
|
-
|
|
171
|
+
if (item !== undefined) {
|
|
172
|
+
cleanup(item);
|
|
173
|
+
dispatch(listeners, 'pop', { item });
|
|
202
174
|
}
|
|
203
175
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
n = this.data.push(...items);
|
|
176
|
+
return item;
|
|
177
|
+
}
|
|
207
178
|
|
|
208
|
-
|
|
179
|
+
function push<T>(data: T[], listeners: Listeners, items: T[]) {
|
|
180
|
+
let n = data.push(...items);
|
|
209
181
|
|
|
210
|
-
|
|
211
|
-
}
|
|
182
|
+
dispatch(listeners, 'push', { items });
|
|
212
183
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
this.dispatch('reverse');
|
|
184
|
+
return n;
|
|
185
|
+
}
|
|
216
186
|
|
|
217
|
-
|
|
218
|
-
|
|
187
|
+
function reverse<T>(data: T[], listeners: Listeners) {
|
|
188
|
+
data.reverse();
|
|
189
|
+
dispatch(listeners, 'reverse');
|
|
190
|
+
}
|
|
219
191
|
|
|
220
|
-
|
|
221
|
-
|
|
192
|
+
function shift<T>(data: T[], listeners: Listeners) {
|
|
193
|
+
let item = data.shift();
|
|
222
194
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return item;
|
|
195
|
+
if (item !== undefined) {
|
|
196
|
+
cleanup(item);
|
|
197
|
+
dispatch(listeners, 'shift', { item });
|
|
229
198
|
}
|
|
230
199
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
(isComputed(a) ? a.value : a) as Value<T>,
|
|
234
|
-
(isComputed(b) ? b.value : b) as Value<T>
|
|
235
|
-
));
|
|
236
|
-
this.dispatch('sort');
|
|
200
|
+
return item;
|
|
201
|
+
}
|
|
237
202
|
|
|
238
|
-
|
|
239
|
-
|
|
203
|
+
function sort<T>(data: T[], listeners: Listeners, fn: (a: T, b: T) => number) {
|
|
204
|
+
data.sort((a, b) => fn(
|
|
205
|
+
(isComputed(a) ? a.value : a) as T,
|
|
206
|
+
(isComputed(b) ? b.value : b) as T
|
|
207
|
+
));
|
|
208
|
+
dispatch(listeners, 'sort');
|
|
209
|
+
}
|
|
240
210
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
removed = this.data.splice(start, deleteCount, ...items);
|
|
211
|
+
function splice<T>(data: T[], listeners: Listeners, start: number, deleteCount: number = data.length, items: T[] = []) {
|
|
212
|
+
let removed = data.splice(start, deleteCount, ...items);
|
|
244
213
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
this.dispatch('splice', {
|
|
251
|
-
deleteCount,
|
|
252
|
-
items,
|
|
253
|
-
start
|
|
254
|
-
});
|
|
214
|
+
if (items.length > 0 || removed.length > 0) {
|
|
215
|
+
for (let i = 0, n = removed.length; i < n; i++) {
|
|
216
|
+
cleanup(removed[i]);
|
|
255
217
|
}
|
|
256
218
|
|
|
257
|
-
|
|
219
|
+
dispatch(listeners, 'splice', {
|
|
220
|
+
deleteCount,
|
|
221
|
+
items,
|
|
222
|
+
start
|
|
223
|
+
});
|
|
258
224
|
}
|
|
259
225
|
|
|
260
|
-
|
|
261
|
-
let items = factory(input),
|
|
262
|
-
length = this.data.unshift(...items);
|
|
263
|
-
|
|
264
|
-
this.dispatch('unshift', { items });
|
|
265
|
-
|
|
266
|
-
return length;
|
|
267
|
-
}
|
|
226
|
+
return removed;
|
|
268
227
|
}
|
|
269
228
|
|
|
229
|
+
function unshift<T>(data: T[], listeners: Listeners, items: T[]) {
|
|
230
|
+
let length = data.unshift(...items);
|
|
270
231
|
|
|
271
|
-
|
|
272
|
-
let items: Item<T>[] = [];
|
|
273
|
-
|
|
274
|
-
for (let i = 0, n = input.length; i < n; i++) {
|
|
275
|
-
let value = input[i];
|
|
276
|
-
|
|
277
|
-
if (isFunction(value)) {
|
|
278
|
-
items[i] = computed(value as Computed<T>['fn']);
|
|
279
|
-
}
|
|
280
|
-
else if (isObject(value)) {
|
|
281
|
-
items[i] = object(value) as Item<T>;
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
items[i] = value;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
232
|
+
dispatch(listeners, 'unshift', { items });
|
|
287
233
|
|
|
288
|
-
return
|
|
234
|
+
return length;
|
|
289
235
|
}
|
|
290
236
|
|
|
291
237
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
export default <T>(input: T[]) => {
|
|
298
|
-
let proxy = new Proxy({}, {
|
|
299
|
-
get(_: any, key: any) {
|
|
238
|
+
export default <T>(data: T[]) => {
|
|
239
|
+
let listeners: Listeners = {},
|
|
240
|
+
proxy = new Proxy({}, {
|
|
241
|
+
get(_, key: any) {
|
|
300
242
|
if (isNumber(key)) {
|
|
301
|
-
let value =
|
|
243
|
+
let value = data[key];
|
|
302
244
|
|
|
303
245
|
if (isComputed(value)) {
|
|
304
246
|
return read(value);
|
|
@@ -306,29 +248,82 @@ export default <T>(input: T[]) => {
|
|
|
306
248
|
|
|
307
249
|
return value;
|
|
308
250
|
}
|
|
309
|
-
else if (key in
|
|
310
|
-
return
|
|
251
|
+
else if (key in wrapper) {
|
|
252
|
+
return wrapper[key as keyof typeof wrapper];
|
|
253
|
+
}
|
|
254
|
+
else if (key === 'length') {
|
|
255
|
+
return data.length;
|
|
311
256
|
}
|
|
312
257
|
|
|
313
|
-
return
|
|
258
|
+
return data[key];
|
|
314
259
|
},
|
|
315
|
-
set(_
|
|
260
|
+
set(_, key: any, value: any) {
|
|
316
261
|
if (isNumber(key)) {
|
|
317
|
-
|
|
318
|
-
return true;
|
|
262
|
+
splice(data, listeners, key, 1, value);
|
|
319
263
|
}
|
|
320
264
|
else if (key === 'length') {
|
|
321
|
-
|
|
265
|
+
if (value >= data.length) {
|
|
266
|
+
}
|
|
267
|
+
else if (value === 0) {
|
|
268
|
+
clear(data, listeners);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
splice(data, listeners, value);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
return false;
|
|
322
276
|
}
|
|
323
277
|
|
|
324
|
-
return
|
|
278
|
+
return true;
|
|
325
279
|
}
|
|
326
280
|
}) as API<T>,
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
281
|
+
wrapper = {
|
|
282
|
+
[REACTIVE_ARRAY]: true,
|
|
283
|
+
at: (i: number) => at(data, i),
|
|
284
|
+
clear: () => {
|
|
285
|
+
clear(data, listeners);
|
|
286
|
+
return proxy;
|
|
287
|
+
},
|
|
288
|
+
dispatch: <K extends keyof Events<T>, V>(event: K, value?: V) => {
|
|
289
|
+
dispatch(listeners, event, value);
|
|
290
|
+
return proxy;
|
|
291
|
+
},
|
|
292
|
+
dispose: () => {
|
|
293
|
+
dispose(data);
|
|
294
|
+
return proxy;
|
|
295
|
+
},
|
|
296
|
+
map: <R>(
|
|
297
|
+
fn: (this: API<T>, value: T, i: number) => R,
|
|
298
|
+
i?: number,
|
|
299
|
+
n?: number
|
|
300
|
+
) => {
|
|
301
|
+
return map(data, proxy, fn, i, n);
|
|
302
|
+
},
|
|
303
|
+
on: <K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>) => {
|
|
304
|
+
on(listeners, event, listener);
|
|
305
|
+
return proxy;
|
|
306
|
+
},
|
|
307
|
+
once: <K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>) => {
|
|
308
|
+
once(listeners, event, listener);
|
|
309
|
+
return proxy;
|
|
310
|
+
},
|
|
311
|
+
pop: () => pop(data, listeners),
|
|
312
|
+
push: (...items: T[]) => push(data, listeners, items),
|
|
313
|
+
reverse: () => {
|
|
314
|
+
reverse(data, listeners);
|
|
315
|
+
return proxy;
|
|
316
|
+
},
|
|
317
|
+
shift: () => shift(data, listeners),
|
|
318
|
+
sort: (fn: (a: T, b: T) => number) => {
|
|
319
|
+
sort(data, listeners, fn);
|
|
320
|
+
return proxy;
|
|
321
|
+
},
|
|
322
|
+
splice: (start: number, deleteCount?: number, ...items: T[]) => {
|
|
323
|
+
return splice(data, listeners, start, deleteCount, items);
|
|
324
|
+
},
|
|
325
|
+
unshift: (...items: T[]) => unshift(data, listeners, items),
|
|
326
|
+
};
|
|
330
327
|
|
|
331
328
|
return proxy;
|
|
332
329
|
};
|
|
333
|
-
export { isReactiveArray };
|
|
334
|
-
export type { API as ReactiveArray };
|
package/src/reactive/index.ts
CHANGED
|
@@ -13,15 +13,13 @@ type API<T> =
|
|
|
13
13
|
|
|
14
14
|
type Input<T> =
|
|
15
15
|
T extends { dispose: any }
|
|
16
|
-
? never
|
|
17
|
-
: T extends Record<PropertyKey, unknown>
|
|
16
|
+
? { never: '[ dispose, signals ] are reserved keys' }
|
|
17
|
+
: T extends Record<PropertyKey, unknown> | unknown[]
|
|
18
18
|
? T
|
|
19
|
-
:
|
|
20
|
-
? Input<T[number]>[]
|
|
21
|
-
: never;
|
|
19
|
+
: never;
|
|
22
20
|
|
|
23
21
|
|
|
24
|
-
export default <T
|
|
22
|
+
export default <T>(input: Input<T>): API<T> => {
|
|
25
23
|
let value: API<T> | undefined;
|
|
26
24
|
|
|
27
25
|
return root(() => {
|