@esportsplus/reactivity 0.31.3 → 0.33.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/README.md +43 -6
- package/bench/cellx.bench.ts +61 -0
- package/bench/dynamic.bench.ts +103 -0
- package/bench/kairo.bench.ts +368 -0
- package/bench/lib/reactive-adapter.ts +51 -0
- package/bench/molbench.bench.ts +75 -0
- package/{tests/bench/system.ts → bench/system.bench.ts} +3 -3
- package/build/compiler/array.d.ts +1 -1
- package/build/compiler/constants.d.ts +7 -6
- package/build/compiler/constants.js +6 -7
- package/build/compiler/object.d.ts +1 -1
- package/build/compiler/object.js +1 -2
- package/build/compiler/primitives.d.ts +1 -1
- package/build/constants.d.ts +3 -1
- package/build/constants.js +3 -1
- package/build/reactive/array.d.ts +7 -3
- package/build/reactive/array.js +32 -24
- package/build/reactive/index.d.ts +2 -2
- package/build/reactive/index.js +1 -1
- package/build/reactive/object.d.ts +4 -4
- package/build/reactive/object.js +8 -23
- package/build/system.d.ts +15 -6
- package/build/system.js +432 -69
- package/build/types.d.ts +22 -4
- package/package.json +10 -7
- package/src/compiler/array.ts +1 -1
- package/src/compiler/constants.ts +8 -6
- package/src/compiler/index.ts +2 -1
- package/src/compiler/object.ts +2 -2
- package/src/compiler/plugins/vite.ts +1 -0
- package/src/compiler/primitives.ts +1 -1
- package/src/constants.ts +6 -2
- package/src/reactive/array.ts +50 -35
- package/src/reactive/index.ts +6 -6
- package/src/reactive/object.ts +16 -41
- package/src/system.ts +635 -80
- package/src/types.ts +38 -9
- package/test/async-computed.test.ts +409 -0
- package/test/async-errors.test.ts +146 -0
- package/test/async-hardening.test.ts +73 -0
- package/test/async-iterable.test.ts +221 -0
- package/test/async-nested.test.ts +19 -0
- package/test/deep-graphs.test.ts +215 -0
- package/{tests/effects.ts → test/effects.test.ts} +122 -0
- package/test/equals.test.ts +142 -0
- package/test/errors.test.ts +201 -0
- package/test/flush.test.ts +185 -0
- package/test/glitch-freedom.test.ts +115 -0
- package/test/invalidate.test.ts +147 -0
- package/test/lib/wait-for.ts +28 -0
- package/test/pending-writes.test.ts +139 -0
- package/{tests/reactive.ts → test/reactive/reactive.test.ts} +20 -19
- package/test/read-dedup.test.ts +120 -0
- package/test/signal-selector.test.ts +187 -0
- package/{tests/system.ts → test/system.test.ts} +210 -19
- package/test/tsconfig.json +16 -0
- package/test/untrack.test.ts +146 -0
- package/vitest.config.ts +2 -2
- package/tests/async-computed.ts +0 -239
- /package/{tests/bench/array.ts → bench/reactive/array.bench.ts} +0 -0
- /package/{tests/bench/reactive-object.ts → bench/reactive/reactive-object.bench.ts} +0 -0
- /package/{tests → bench}/tsconfig.json +0 -0
- /package/{tests/compiler.ts → test/compiler/compiler.test.ts} +0 -0
- /package/{tests/primitives.ts → test/primitives.test.ts} +0 -0
- /package/{tests/array.ts → test/reactive/array.test.ts} +0 -0
- /package/{tests/nested.ts → test/reactive/nested.test.ts} +0 -0
- /package/{tests/objects.ts → test/reactive/objects.test.ts} +0 -0
package/build/types.d.ts
CHANGED
|
@@ -5,15 +5,23 @@ interface Computed<T> {
|
|
|
5
5
|
cleanup: VoidFunction | VoidFunction[] | null;
|
|
6
6
|
deps: Link | null;
|
|
7
7
|
depsTail: Link | null;
|
|
8
|
+
disposal: VoidFunction | null;
|
|
9
|
+
equals: ((a: unknown, b: unknown) => boolean) | null;
|
|
10
|
+
error: unknown;
|
|
8
11
|
fn: (onCleanup: (fn: VoidFunction) => typeof fn) => T;
|
|
12
|
+
gv: number;
|
|
9
13
|
height: number;
|
|
10
14
|
nextHeap: Computed<unknown> | undefined;
|
|
11
15
|
prevHeap: Computed<unknown>;
|
|
16
|
+
rv: number;
|
|
12
17
|
state: number;
|
|
13
18
|
subs: Link | null;
|
|
14
19
|
subsTail: Link | null;
|
|
15
20
|
value: T;
|
|
16
21
|
}
|
|
22
|
+
type ComputedResult<T> = T extends Promise<any> | AsyncIterable<any> ? Computed<Settled<T>> & {
|
|
23
|
+
pending: Signal<boolean>;
|
|
24
|
+
} : Computed<Settled<T>>;
|
|
17
25
|
interface Link {
|
|
18
26
|
dep: Signal<unknown> | Computed<unknown>;
|
|
19
27
|
nextDep: Link | null;
|
|
@@ -23,16 +31,26 @@ interface Link {
|
|
|
23
31
|
version: number;
|
|
24
32
|
}
|
|
25
33
|
declare const READONLY: unique symbol;
|
|
26
|
-
type Reactive<T> = T extends (...args:
|
|
27
|
-
readonly [READONLY]: true;
|
|
28
|
-
} : T extends (...args: any[]) => infer R ? R & {
|
|
34
|
+
type Reactive<T> = T extends (...args: never[]) => infer R ? Settled<R> & {
|
|
29
35
|
readonly [READONLY]: true;
|
|
30
36
|
} : T extends (infer U)[] ? U[] & Pick<ReactiveArray<U>, 'clear' | 'dispose' | 'on' | 'once'> : T extends Record<PropertyKey, unknown> ? {
|
|
31
37
|
[K in keyof T]: T[K] extends (infer U)[] ? Reactive<U[]> : T[K];
|
|
32
38
|
} & {
|
|
33
39
|
dispose: VoidFunction;
|
|
34
40
|
} : T;
|
|
41
|
+
type SelectorSignal<T> = Signal<boolean> & {
|
|
42
|
+
key: T;
|
|
43
|
+
parent: Signal<T>;
|
|
44
|
+
};
|
|
45
|
+
type Settled<T> = T extends Promise<infer U> ? Awaited<U> | undefined : T extends AsyncIterable<infer U> ? U | undefined : T;
|
|
35
46
|
type Signal<T> = {
|
|
47
|
+
equals: ((a: unknown, b: unknown) => boolean) | null;
|
|
48
|
+
key: unknown;
|
|
49
|
+
keys: Map<T, SelectorSignal<T>> | null;
|
|
50
|
+
nextPending: Signal<unknown> | null;
|
|
51
|
+
parent: Signal<unknown> | undefined;
|
|
52
|
+
rv: number;
|
|
53
|
+
state: number;
|
|
36
54
|
subs: Link | null;
|
|
37
55
|
subsTail: Link | null;
|
|
38
56
|
type: typeof SIGNAL;
|
|
@@ -43,4 +61,4 @@ interface TransformResult {
|
|
|
43
61
|
code: string;
|
|
44
62
|
sourceFile: ts.SourceFile;
|
|
45
63
|
}
|
|
46
|
-
export type { Computed, Link, Reactive, Signal, TransformResult };
|
|
64
|
+
export type { Computed, ComputedResult, Link, Reactive, SelectorSignal, Settled, Signal, TransformResult };
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "ICJR",
|
|
3
3
|
"dependencies": {
|
|
4
|
-
"@esportsplus/utilities": "^0.
|
|
4
|
+
"@esportsplus/utilities": "^0.28.0"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"@esportsplus/typescript": "^0.29.
|
|
8
|
-
"@types/node": "^
|
|
9
|
-
"vite": "^8.
|
|
10
|
-
"vitest": "^4.1.
|
|
7
|
+
"@esportsplus/typescript": "^0.29.5",
|
|
8
|
+
"@types/node": "^26.1.1",
|
|
9
|
+
"vite": "^8.1.5",
|
|
10
|
+
"vitest": "^4.1.10"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
@@ -36,10 +36,13 @@
|
|
|
36
36
|
},
|
|
37
37
|
"type": "module",
|
|
38
38
|
"types": "build/index.d.ts",
|
|
39
|
-
"version": "0.
|
|
39
|
+
"version": "0.33.0",
|
|
40
40
|
"scripts": {
|
|
41
|
+
"agent:bench": "vitest bench --run",
|
|
42
|
+
"agent:test": "tsc --noEmit && vitest run",
|
|
43
|
+
"bench": "vitest bench --run",
|
|
41
44
|
"build": "tsc",
|
|
42
|
-
"
|
|
45
|
+
"test": "vitest run",
|
|
43
46
|
"-": "-"
|
|
44
47
|
}
|
|
45
48
|
}
|
package/src/compiler/array.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
3
2
|
import { ast, imports } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
4
4
|
import { ENTRYPOINT, NAMESPACE, PACKAGE_NAME, TYPES } from './constants';
|
|
5
5
|
import type { Bindings } from './types';
|
|
6
6
|
|
|
@@ -8,12 +8,14 @@ const ENTRYPOINT_REGEX = /\breactive\b/;
|
|
|
8
8
|
const NAMESPACE = uid('reactivity');
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
Array,
|
|
13
|
-
Computed,
|
|
14
|
-
Object,
|
|
15
|
-
Signal
|
|
16
|
-
}
|
|
11
|
+
const TYPES = {
|
|
12
|
+
Array: 0,
|
|
13
|
+
Computed: 1,
|
|
14
|
+
Object: 2,
|
|
15
|
+
Signal: 3
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
type TYPES = typeof TYPES[keyof typeof TYPES];
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
export { ENTRYPOINT, ENTRYPOINT_REGEX, NAMESPACE, TYPES };
|
package/src/compiler/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { ImportIntent, ReplacementIntent, TransformContext } from '@esportsplus/typescript/compiler';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
3
2
|
import { imports } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import type { ImportIntent, ReplacementIntent, TransformContext } from '@esportsplus/typescript/compiler';
|
|
4
4
|
import { ENTRYPOINT, NAMESPACE, PACKAGE_NAME } from './constants';
|
|
5
5
|
import type { Bindings } from './types';
|
|
6
|
+
|
|
6
7
|
import array from './array';
|
|
7
8
|
import object from './object';
|
|
8
9
|
import primitives from './primitives';
|
package/src/compiler/object.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { code, imports, type ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
3
|
-
import { uid } from '@esportsplus/typescript/compiler';
|
|
2
|
+
import { code, imports, uid } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
4
4
|
import { ENTRYPOINT, NAMESPACE, PACKAGE_NAME, TYPES } from './constants';
|
|
5
5
|
import type { Bindings } from './types';
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
3
3
|
import { NAMESPACE, TYPES } from './constants';
|
|
4
4
|
import type { Bindings } from './types';
|
|
5
5
|
|
package/src/constants.ts
CHANGED
|
@@ -28,14 +28,18 @@ const STATE_IN_HEAP = 1 << 3;
|
|
|
28
28
|
|
|
29
29
|
const STATE_COMPUTED = 1 << 4;
|
|
30
30
|
|
|
31
|
+
const STATE_ERROR = 1 << 5;
|
|
32
|
+
|
|
33
|
+
const STATE_EFFECT = 1 << 6;
|
|
34
|
+
|
|
31
35
|
const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
export {
|
|
35
39
|
COMPUTED,
|
|
36
|
-
REACTIVE_ARRAY, REACTIVE_OBJECT,
|
|
37
40
|
PACKAGE_NAME,
|
|
41
|
+
REACTIVE_ARRAY, REACTIVE_OBJECT,
|
|
38
42
|
SIGNAL,
|
|
39
43
|
STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED,
|
|
40
|
-
STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING
|
|
44
|
+
STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING
|
|
41
45
|
};
|
package/src/reactive/array.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import { read, signal, write } from '~/system';
|
|
3
2
|
import { REACTIVE_ARRAY } from '~/constants';
|
|
3
|
+
import { read, signal, write } from '~/system';
|
|
4
4
|
import type { Signal } from '~/types';
|
|
5
5
|
import { isReactiveObject } from './object';
|
|
6
6
|
|
|
@@ -42,7 +42,9 @@ type Listener<V> = {
|
|
|
42
42
|
(value: V): void;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
-
type
|
|
45
|
+
type AnyListener<T> = Listener<Events<T>[keyof Events<T>]>;
|
|
46
|
+
|
|
47
|
+
type Listeners<T> = { [K in keyof Events<T>]?: (AnyListener<T> | null)[] };
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
function dispose(value: unknown) {
|
|
@@ -52,10 +54,13 @@ function dispose(value: unknown) {
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
|
|
57
|
+
// Derived arrays (splice removals, map/filter/slice) must be plain Arrays: species-creating a
|
|
58
|
+
// ReactiveArray runs the reactive constructor per call and seeds _length from the length argument.
|
|
55
59
|
class ReactiveArray<T> extends Array<T> {
|
|
60
|
+
|
|
56
61
|
private _length: Signal<number>;
|
|
57
62
|
|
|
58
|
-
listeners: Listeners = {};
|
|
63
|
+
listeners: Listeners<T> = {};
|
|
59
64
|
|
|
60
65
|
|
|
61
66
|
constructor(...items: T[]) {
|
|
@@ -64,6 +69,11 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
|
|
72
|
+
static get [Symbol.species]() {
|
|
73
|
+
return Array;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
67
77
|
get $length() {
|
|
68
78
|
return read(this._length);
|
|
69
79
|
}
|
|
@@ -130,7 +140,7 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
130
140
|
return this;
|
|
131
141
|
}
|
|
132
142
|
|
|
133
|
-
dispatch<K extends keyof Events<T
|
|
143
|
+
dispatch<K extends keyof Events<T>>(event: K, value?: Events<T>[K]) {
|
|
134
144
|
let listeners = this.listeners[event];
|
|
135
145
|
|
|
136
146
|
if (!listeners) {
|
|
@@ -147,7 +157,7 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
147
157
|
}
|
|
148
158
|
|
|
149
159
|
try {
|
|
150
|
-
listener(value);
|
|
160
|
+
listener(value as Events<T>[K]);
|
|
151
161
|
|
|
152
162
|
if (listener.once !== undefined) {
|
|
153
163
|
dirty = true;
|
|
@@ -176,10 +186,11 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
176
186
|
}
|
|
177
187
|
|
|
178
188
|
on<K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>) {
|
|
179
|
-
let
|
|
189
|
+
let entry = listener as AnyListener<T>,
|
|
190
|
+
listeners = this.listeners[event];
|
|
180
191
|
|
|
181
192
|
if (listeners === undefined) {
|
|
182
|
-
this.listeners[event] = [
|
|
193
|
+
this.listeners[event] = [entry];
|
|
183
194
|
}
|
|
184
195
|
else {
|
|
185
196
|
let hole = listeners.length;
|
|
@@ -187,7 +198,7 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
187
198
|
for (let i = 0, n = hole; i < n; i++) {
|
|
188
199
|
let l = listeners[i];
|
|
189
200
|
|
|
190
|
-
if (l ===
|
|
201
|
+
if (l === entry) {
|
|
191
202
|
return;
|
|
192
203
|
}
|
|
193
204
|
else if (l === null && hole === n) {
|
|
@@ -195,7 +206,7 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
195
206
|
}
|
|
196
207
|
}
|
|
197
208
|
|
|
198
|
-
listeners[hole] =
|
|
209
|
+
listeners[hole] = entry;
|
|
199
210
|
|
|
200
211
|
while (listeners.length && listeners[listeners.length - 1] === null) {
|
|
201
212
|
listeners.pop();
|
|
@@ -214,7 +225,6 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
214
225
|
if (item !== undefined) {
|
|
215
226
|
dispose(item);
|
|
216
227
|
write(this._length, this.length);
|
|
217
|
-
|
|
218
228
|
this.dispatch('pop', { item });
|
|
219
229
|
}
|
|
220
230
|
|
|
@@ -229,6 +239,7 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
229
239
|
let length = super.push(...items);
|
|
230
240
|
|
|
231
241
|
write(this._length, length);
|
|
242
|
+
|
|
232
243
|
this.dispatch('push', { items });
|
|
233
244
|
|
|
234
245
|
return length;
|
|
@@ -247,7 +258,6 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
247
258
|
if (item !== undefined) {
|
|
248
259
|
dispose(item);
|
|
249
260
|
write(this._length, this.length);
|
|
250
|
-
|
|
251
261
|
this.dispatch('shift', { item });
|
|
252
262
|
}
|
|
253
263
|
|
|
@@ -255,41 +265,46 @@ class ReactiveArray<T> extends Array<T> {
|
|
|
255
265
|
}
|
|
256
266
|
|
|
257
267
|
sort(fn?: (a: T, b: T) => number) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
for (let i = 0; i < n; i++) {
|
|
262
|
-
before[i] = this[i];
|
|
268
|
+
if (this.listeners.sort === undefined) {
|
|
269
|
+
super.sort(fn);
|
|
263
270
|
}
|
|
271
|
+
else {
|
|
272
|
+
let n = this.length,
|
|
273
|
+
before = new Array(n) as T[];
|
|
264
274
|
|
|
265
|
-
|
|
275
|
+
for (let i = 0; i < n; i++) {
|
|
276
|
+
before[i] = this[i];
|
|
277
|
+
}
|
|
266
278
|
|
|
267
|
-
|
|
268
|
-
order = new Array(n);
|
|
279
|
+
super.sort(fn);
|
|
269
280
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
list = buckets.get(value);
|
|
281
|
+
let buckets = new Map<T, number[]>(),
|
|
282
|
+
order = new Array(n);
|
|
273
283
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
list
|
|
284
|
+
for (let i = 0; i < n; i++) {
|
|
285
|
+
let value = before[i],
|
|
286
|
+
list = buckets.get(value);
|
|
287
|
+
|
|
288
|
+
if (!list) {
|
|
289
|
+
buckets.set(value, [i]);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
list.push(i);
|
|
293
|
+
}
|
|
279
294
|
}
|
|
280
|
-
}
|
|
281
295
|
|
|
282
|
-
|
|
283
|
-
|
|
296
|
+
for (let i = 0; i < n; i++) {
|
|
297
|
+
let list = buckets.get(this[i])!;
|
|
284
298
|
|
|
285
|
-
|
|
299
|
+
order[i] = list.length === 1 ? list[0] : list[list.length - 1];
|
|
286
300
|
|
|
287
|
-
|
|
288
|
-
|
|
301
|
+
if (list.length > 1) {
|
|
302
|
+
list.pop();
|
|
303
|
+
}
|
|
289
304
|
}
|
|
290
|
-
}
|
|
291
305
|
|
|
292
|
-
|
|
306
|
+
this.dispatch('sort', { order });
|
|
307
|
+
}
|
|
293
308
|
|
|
294
309
|
return this;
|
|
295
310
|
}
|
package/src/reactive/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { onCleanup, root } from '@esportsplus/reactivity';
|
|
2
2
|
import { isArray, isObject } from '@esportsplus/utilities';
|
|
3
|
-
import {
|
|
3
|
+
import { PACKAGE_NAME } from '~/constants';
|
|
4
|
+
import type { Reactive } from '~/types';
|
|
4
5
|
import { ReactiveArray } from './array';
|
|
5
6
|
import { ReactiveObject } from './object';
|
|
6
|
-
import { PACKAGE_NAME } from '~/constants';
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
type Guard<T> =
|
|
10
10
|
T extends Record<PropertyKey, unknown>
|
|
11
|
-
? T extends { dispose:
|
|
11
|
+
? T extends { dispose: unknown }
|
|
12
12
|
? { never: '[ dispose ] is a reserved key' }
|
|
13
13
|
: T
|
|
14
14
|
: never;
|
|
@@ -23,10 +23,10 @@ function reactive<T>(input: T): Reactive<T> {
|
|
|
23
23
|
let response: Reactive<T> | undefined;
|
|
24
24
|
|
|
25
25
|
if (isObject(input)) {
|
|
26
|
-
response = new ReactiveObject(input) as
|
|
26
|
+
response = new ReactiveObject(input) as unknown as Reactive<T>;
|
|
27
27
|
}
|
|
28
28
|
else if (isArray(input)) {
|
|
29
|
-
response = new ReactiveArray(...input) as
|
|
29
|
+
response = new ReactiveArray(...input) as unknown as Reactive<T>;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (response) {
|
|
@@ -41,7 +41,7 @@ function reactive<T>(input: T): Reactive<T> {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
if (dispose) {
|
|
44
|
-
onCleanup(() => (value as
|
|
44
|
+
onCleanup(() => (value as unknown as { dispose: VoidFunction }).dispose());
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
return value;
|
package/src/reactive/object.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { defineProperty, isArray
|
|
2
|
-
import { computed, dispose, effect, read, root, signal, write } from '~/system';
|
|
3
|
-
import { Computed, Signal } from '~/types';
|
|
1
|
+
import { defineProperty, isArray } from '@esportsplus/utilities';
|
|
4
2
|
import { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL } from '~/constants';
|
|
3
|
+
import { computed, dispose, read, root, signal, write } from '~/system';
|
|
4
|
+
import { Computed } from '~/types';
|
|
5
5
|
import { ReactiveArray } from './array';
|
|
6
6
|
|
|
7
7
|
|
|
@@ -32,10 +32,7 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
|
32
32
|
continue;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (value
|
|
36
|
-
// Skip isArray when possible
|
|
37
|
-
}
|
|
38
|
-
else if (isArray(value)) {
|
|
35
|
+
if (value != null && type === 'object' && isArray(value)) {
|
|
39
36
|
defineProperty(this, key, {
|
|
40
37
|
enumerable: true,
|
|
41
38
|
value: this[REACTIVE_ARRAY](value)
|
|
@@ -59,44 +56,22 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
|
59
56
|
}
|
|
60
57
|
|
|
61
58
|
|
|
62
|
-
protected [REACTIVE_ARRAY]<U>(value: U[]): ReactiveArray<U> {
|
|
63
|
-
let node = new ReactiveArray(...value);
|
|
64
|
-
|
|
65
|
-
(this.disposers ??= []).push( () => node.dispose() );
|
|
66
|
-
|
|
67
|
-
return node;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
59
|
protected [COMPUTED]<T extends Computed<ReturnType<T>>['fn']>(value: T) {
|
|
71
60
|
return root(() => {
|
|
72
|
-
let node
|
|
73
|
-
|
|
74
|
-
if (isPromise(node.value)) {
|
|
75
|
-
let factory = node as Computed<ReturnType<T>>,
|
|
76
|
-
out = signal<ReturnType<T> | undefined>(undefined),
|
|
77
|
-
v = 0;
|
|
78
|
-
|
|
79
|
-
(this.disposers ??= []).push(
|
|
80
|
-
effect(() => {
|
|
81
|
-
let id = ++v;
|
|
61
|
+
let node = computed(value);
|
|
82
62
|
|
|
83
|
-
|
|
84
|
-
if (id !== v) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
63
|
+
(this.disposers ??= []).push(() => dispose(node));
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
65
|
+
return node;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
92
68
|
|
|
93
|
-
|
|
94
|
-
|
|
69
|
+
protected [REACTIVE_ARRAY]<U>(value: U[]): ReactiveArray<U> {
|
|
70
|
+
let node = new ReactiveArray(...value);
|
|
95
71
|
|
|
96
|
-
|
|
72
|
+
(this.disposers ??= []).push( () => node.dispose() );
|
|
97
73
|
|
|
98
|
-
|
|
99
|
-
});
|
|
74
|
+
return node;
|
|
100
75
|
}
|
|
101
76
|
|
|
102
77
|
protected [SIGNAL]<T>(value: T) {
|
|
@@ -121,9 +96,9 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
|
121
96
|
Object.defineProperty(ReactiveObject.prototype, REACTIVE_OBJECT, { value: true });
|
|
122
97
|
|
|
123
98
|
|
|
124
|
-
const isReactiveObject = (value:
|
|
125
|
-
return typeof value === 'object' && value !== null && value[REACTIVE_OBJECT] === true;
|
|
99
|
+
const isReactiveObject = (value: unknown): value is ReactiveObject<Record<PropertyKey, unknown>> => {
|
|
100
|
+
return typeof value === 'object' && value !== null && (value as Record<PropertyKey, unknown>)[REACTIVE_OBJECT] === true;
|
|
126
101
|
};
|
|
127
102
|
|
|
128
103
|
|
|
129
|
-
export { isReactiveObject, ReactiveObject };
|
|
104
|
+
export { isReactiveObject, ReactiveObject };
|