@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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { bench, describe } from 'vitest';
|
|
2
|
+
import { assert, framework } from './lib/reactive-adapter';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// Ported from milomg/js-reactivity-benchmark packages/core/src/benches/kairo/molBench.ts (MIT)
|
|
6
|
+
|
|
7
|
+
let numbers = Array.from({ length: 5 }, (_, i) => i);
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function fib(n: number): number {
|
|
11
|
+
if (n < 2) {
|
|
12
|
+
return 1;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return fib(n - 1) + fib(n - 2);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function hard(n: number) {
|
|
19
|
+
return n + fib(16);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function mol() {
|
|
23
|
+
let res: number[] = [];
|
|
24
|
+
|
|
25
|
+
let a = framework.signal(0);
|
|
26
|
+
|
|
27
|
+
let b = framework.signal(0);
|
|
28
|
+
|
|
29
|
+
let c = framework.computed(() => (a.read() % 2) + (b.read() % 2));
|
|
30
|
+
|
|
31
|
+
let d = framework.computed(() => numbers.map((i) => ({ x: i + (a.read() % 2) - (b.read() % 2) })));
|
|
32
|
+
|
|
33
|
+
let e = framework.computed(() => hard(c.read() + a.read() + d.read()[0].x));
|
|
34
|
+
|
|
35
|
+
let f = framework.computed(() => hard(d.read()[2].x || b.read()));
|
|
36
|
+
|
|
37
|
+
let g = framework.computed(() => c.read() + (c.read() || e.read() % 2) + d.read()[4].x + f.read());
|
|
38
|
+
|
|
39
|
+
// Keeper: G reads E conditionally; without a live subscriber E would auto-dispose on first drop
|
|
40
|
+
framework.effect(() => e.read());
|
|
41
|
+
|
|
42
|
+
framework.effect(() => res.push(hard(g.read())));
|
|
43
|
+
|
|
44
|
+
framework.effect(() => res.push(g.read()));
|
|
45
|
+
|
|
46
|
+
framework.effect(() => res.push(hard(f.read())));
|
|
47
|
+
|
|
48
|
+
let i = 0;
|
|
49
|
+
|
|
50
|
+
return async () => {
|
|
51
|
+
i++;
|
|
52
|
+
res.length = 0;
|
|
53
|
+
|
|
54
|
+
await framework.withBatch(() => {
|
|
55
|
+
b.write(1);
|
|
56
|
+
a.write(1 + i * 2);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
await framework.withBatch(() => {
|
|
60
|
+
a.write(2 + i * 2);
|
|
61
|
+
b.write(2);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
assert(res.length > 0, 'molBench: effects did not run');
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
describe('molBench', () => {
|
|
70
|
+
let molRun = framework.withBuild(mol);
|
|
71
|
+
|
|
72
|
+
bench('molBench', async () => {
|
|
73
|
+
await molRun();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { bench, describe } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { computed, dispose, effect, onCleanup, read, root, signal, write } from '~/system';
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
describe('signal', () => {
|
|
@@ -78,13 +78,13 @@ describe('computed', () => {
|
|
|
78
78
|
|
|
79
79
|
describe('asyncComputed', () => {
|
|
80
80
|
bench('create asyncComputed', () => {
|
|
81
|
-
|
|
81
|
+
computed(() => Promise.resolve(0));
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
bench('create asyncComputed from signal', () => {
|
|
85
85
|
let s = signal(0);
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
computed(() => Promise.resolve(read(s)));
|
|
88
88
|
});
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -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 type { Bindings } from './types.js';
|
|
4
4
|
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, checker?: ts.TypeChecker) => ReplacementIntent[];
|
|
5
5
|
export default _default;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
declare const ENTRYPOINT = "reactive";
|
|
2
2
|
declare const ENTRYPOINT_REGEX: RegExp;
|
|
3
3
|
declare const NAMESPACE: string;
|
|
4
|
-
declare const
|
|
5
|
-
Array
|
|
6
|
-
Computed
|
|
7
|
-
Object
|
|
8
|
-
Signal
|
|
9
|
-
}
|
|
4
|
+
declare const TYPES: {
|
|
5
|
+
readonly Array: 0;
|
|
6
|
+
readonly Computed: 1;
|
|
7
|
+
readonly Object: 2;
|
|
8
|
+
readonly Signal: 3;
|
|
9
|
+
};
|
|
10
|
+
type TYPES = typeof TYPES[keyof typeof TYPES];
|
|
10
11
|
export { ENTRYPOINT, ENTRYPOINT_REGEX, NAMESPACE, TYPES };
|
|
11
12
|
export { PACKAGE_NAME } from '../constants.js';
|
|
@@ -2,12 +2,11 @@ import { uid } from '@esportsplus/typescript/compiler';
|
|
|
2
2
|
const ENTRYPOINT = 'reactive';
|
|
3
3
|
const ENTRYPOINT_REGEX = /\breactive\b/;
|
|
4
4
|
const NAMESPACE = uid('reactivity');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
})(TYPES || (TYPES = {}));
|
|
5
|
+
const TYPES = {
|
|
6
|
+
Array: 0,
|
|
7
|
+
Computed: 1,
|
|
8
|
+
Object: 2,
|
|
9
|
+
Signal: 3
|
|
10
|
+
};
|
|
12
11
|
export { ENTRYPOINT, ENTRYPOINT_REGEX, NAMESPACE, TYPES };
|
|
13
12
|
export { PACKAGE_NAME } from '../constants.js';
|
|
@@ -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 type { Bindings } from './types.js';
|
|
4
4
|
type ObjectTransformResult = {
|
|
5
5
|
prepend: string[];
|
package/build/compiler/object.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { code, imports } 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';
|
|
4
3
|
import { ENTRYPOINT, NAMESPACE, PACKAGE_NAME, TYPES } from './constants.js';
|
|
5
4
|
function analyzeProperty(prop, sourceFile) {
|
|
6
5
|
if (!ts.isPropertyAssignment(prop)) {
|
|
@@ -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 type { Bindings } from './types.js';
|
|
4
4
|
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: (node: ts.Node) => boolean) => ReplacementIntent[];
|
|
5
5
|
export default _default;
|
package/build/constants.d.ts
CHANGED
|
@@ -13,5 +13,7 @@ declare const STATE_DIRTY: number;
|
|
|
13
13
|
declare const STATE_RECOMPUTING: number;
|
|
14
14
|
declare const STATE_IN_HEAP: number;
|
|
15
15
|
declare const STATE_COMPUTED: number;
|
|
16
|
+
declare const STATE_ERROR: number;
|
|
17
|
+
declare const STATE_EFFECT: number;
|
|
16
18
|
declare const STATE_NOTIFY_MASK: number;
|
|
17
|
-
export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT,
|
|
19
|
+
export { COMPUTED, PACKAGE_NAME, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
|
package/build/constants.js
CHANGED
|
@@ -13,5 +13,7 @@ const STATE_DIRTY = 1 << 1;
|
|
|
13
13
|
const STATE_RECOMPUTING = 1 << 2;
|
|
14
14
|
const STATE_IN_HEAP = 1 << 3;
|
|
15
15
|
const STATE_COMPUTED = 1 << 4;
|
|
16
|
+
const STATE_ERROR = 1 << 5;
|
|
17
|
+
const STATE_EFFECT = 1 << 6;
|
|
16
18
|
const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
|
|
17
|
-
export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT,
|
|
19
|
+
export { COMPUTED, PACKAGE_NAME, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
|
|
@@ -33,18 +33,22 @@ type Listener<V> = {
|
|
|
33
33
|
once?: boolean;
|
|
34
34
|
(value: V): void;
|
|
35
35
|
};
|
|
36
|
-
type
|
|
36
|
+
type AnyListener<T> = Listener<Events<T>[keyof Events<T>]>;
|
|
37
|
+
type Listeners<T> = {
|
|
38
|
+
[K in keyof Events<T>]?: (AnyListener<T> | null)[];
|
|
39
|
+
};
|
|
37
40
|
declare class ReactiveArray<T> extends Array<T> {
|
|
38
41
|
private _length;
|
|
39
|
-
listeners: Listeners
|
|
42
|
+
listeners: Listeners<T>;
|
|
40
43
|
constructor(...items: T[]);
|
|
44
|
+
static get [Symbol.species](): ArrayConstructor;
|
|
41
45
|
get $length(): number;
|
|
42
46
|
set $length(value: number);
|
|
43
47
|
$set(i: number, value: T): void;
|
|
44
48
|
clear(): void;
|
|
45
49
|
concat(...items: ConcatArray<T>[]): ReactiveArray<T>;
|
|
46
50
|
concat(...items: (T | ConcatArray<T>)[]): ReactiveArray<T>;
|
|
47
|
-
dispatch<K extends keyof Events<T
|
|
51
|
+
dispatch<K extends keyof Events<T>>(event: K, value?: Events<T>[K]): void;
|
|
48
52
|
dispose(): void;
|
|
49
53
|
on<K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>): void;
|
|
50
54
|
once<K extends keyof Events<T>>(event: K, listener: Listener<Events<T>[K]>): void;
|
package/build/reactive/array.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import { read, signal, write } from '../system.js';
|
|
3
2
|
import { REACTIVE_ARRAY } from '../constants.js';
|
|
3
|
+
import { read, signal, write } from '../system.js';
|
|
4
4
|
import { isReactiveObject } from './object.js';
|
|
5
5
|
function dispose(value) {
|
|
6
6
|
if (isReactiveObject(value)) {
|
|
@@ -14,6 +14,9 @@ class ReactiveArray extends Array {
|
|
|
14
14
|
super(...items);
|
|
15
15
|
this._length = signal(items.length);
|
|
16
16
|
}
|
|
17
|
+
static get [Symbol.species]() {
|
|
18
|
+
return Array;
|
|
19
|
+
}
|
|
17
20
|
get $length() {
|
|
18
21
|
return read(this._length);
|
|
19
22
|
}
|
|
@@ -97,22 +100,22 @@ class ReactiveArray extends Array {
|
|
|
97
100
|
write(this._length, 0);
|
|
98
101
|
}
|
|
99
102
|
on(event, listener) {
|
|
100
|
-
let listeners = this.listeners[event];
|
|
103
|
+
let entry = listener, listeners = this.listeners[event];
|
|
101
104
|
if (listeners === undefined) {
|
|
102
|
-
this.listeners[event] = [
|
|
105
|
+
this.listeners[event] = [entry];
|
|
103
106
|
}
|
|
104
107
|
else {
|
|
105
108
|
let hole = listeners.length;
|
|
106
109
|
for (let i = 0, n = hole; i < n; i++) {
|
|
107
110
|
let l = listeners[i];
|
|
108
|
-
if (l ===
|
|
111
|
+
if (l === entry) {
|
|
109
112
|
return;
|
|
110
113
|
}
|
|
111
114
|
else if (l === null && hole === n) {
|
|
112
115
|
hole = i;
|
|
113
116
|
}
|
|
114
117
|
}
|
|
115
|
-
listeners[hole] =
|
|
118
|
+
listeners[hole] = entry;
|
|
116
119
|
while (listeners.length && listeners[listeners.length - 1] === null) {
|
|
117
120
|
listeners.pop();
|
|
118
121
|
}
|
|
@@ -155,29 +158,34 @@ class ReactiveArray extends Array {
|
|
|
155
158
|
return item;
|
|
156
159
|
}
|
|
157
160
|
sort(fn) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
let value = before[i], list = buckets.get(value);
|
|
166
|
-
if (!list) {
|
|
167
|
-
buckets.set(value, [i]);
|
|
161
|
+
if (this.listeners.sort === undefined) {
|
|
162
|
+
super.sort(fn);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
let n = this.length, before = new Array(n);
|
|
166
|
+
for (let i = 0; i < n; i++) {
|
|
167
|
+
before[i] = this[i];
|
|
168
168
|
}
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
super.sort(fn);
|
|
170
|
+
let buckets = new Map(), order = new Array(n);
|
|
171
|
+
for (let i = 0; i < n; i++) {
|
|
172
|
+
let value = before[i], list = buckets.get(value);
|
|
173
|
+
if (!list) {
|
|
174
|
+
buckets.set(value, [i]);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
list.push(i);
|
|
178
|
+
}
|
|
171
179
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
for (let i = 0; i < n; i++) {
|
|
181
|
+
let list = buckets.get(this[i]);
|
|
182
|
+
order[i] = list.length === 1 ? list[0] : list[list.length - 1];
|
|
183
|
+
if (list.length > 1) {
|
|
184
|
+
list.pop();
|
|
185
|
+
}
|
|
178
186
|
}
|
|
187
|
+
this.dispatch('sort', { order });
|
|
179
188
|
}
|
|
180
|
-
this.dispatch('sort', { order });
|
|
181
189
|
return this;
|
|
182
190
|
}
|
|
183
191
|
splice(start, deleteCount = this.length, ...items) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Reactive } from '../types.js';
|
|
1
|
+
import type { Reactive } from '../types.js';
|
|
2
2
|
import { ReactiveArray } from './array.js';
|
|
3
3
|
import { ReactiveObject } from './object.js';
|
|
4
4
|
type Guard<T> = T extends Record<PropertyKey, unknown> ? T extends {
|
|
5
|
-
dispose:
|
|
5
|
+
dispose: unknown;
|
|
6
6
|
} ? {
|
|
7
7
|
never: '[ dispose ] is a reserved key';
|
|
8
8
|
} : T : never;
|
package/build/reactive/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { onCleanup, root } from '@esportsplus/reactivity';
|
|
2
2
|
import { isArray, isObject } from '@esportsplus/utilities';
|
|
3
|
+
import { PACKAGE_NAME } from '../constants.js';
|
|
3
4
|
import { ReactiveArray } from './array.js';
|
|
4
5
|
import { ReactiveObject } from './object.js';
|
|
5
|
-
import { PACKAGE_NAME } from '../constants.js';
|
|
6
6
|
function reactive(input) {
|
|
7
7
|
let dispose = false, value = root(() => {
|
|
8
8
|
let response;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Computed, Signal } from '../types.js';
|
|
2
1
|
import { COMPUTED, REACTIVE_ARRAY, SIGNAL } from '../constants.js';
|
|
2
|
+
import { Computed } from '../types.js';
|
|
3
3
|
import { ReactiveArray } from './array.js';
|
|
4
4
|
declare class ReactiveObject<T extends Record<PropertyKey, unknown>> {
|
|
5
5
|
protected disposers: VoidFunction[] | null;
|
|
6
6
|
constructor(data: T | null);
|
|
7
|
+
protected [COMPUTED]<T extends Computed<ReturnType<T>>['fn']>(value: T): import("../types.js").ComputedResult<ReturnType<T>>;
|
|
7
8
|
protected [REACTIVE_ARRAY]<U>(value: U[]): ReactiveArray<U>;
|
|
8
|
-
protected [
|
|
9
|
-
protected [SIGNAL]<T>(value: T): Signal<T>;
|
|
9
|
+
protected [SIGNAL]<T>(value: T): import("../types.js").Signal<T>;
|
|
10
10
|
dispose(): void;
|
|
11
11
|
}
|
|
12
|
-
declare const isReactiveObject: (value:
|
|
12
|
+
declare const isReactiveObject: (value: unknown) => value is ReactiveObject<Record<PropertyKey, unknown>>;
|
|
13
13
|
export { isReactiveObject, ReactiveObject };
|
package/build/reactive/object.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { defineProperty, isArray
|
|
2
|
-
import { computed, dispose, effect, read, root, signal, write } from '../system.js';
|
|
1
|
+
import { defineProperty, isArray } from '@esportsplus/utilities';
|
|
3
2
|
import { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL } from '../constants.js';
|
|
3
|
+
import { computed, dispose, read, root, signal, write } from '../system.js';
|
|
4
4
|
import { ReactiveArray } from './array.js';
|
|
5
5
|
class ReactiveObject {
|
|
6
6
|
disposers = null;
|
|
@@ -19,9 +19,7 @@ class ReactiveObject {
|
|
|
19
19
|
});
|
|
20
20
|
continue;
|
|
21
21
|
}
|
|
22
|
-
if (value
|
|
23
|
-
}
|
|
24
|
-
else if (isArray(value)) {
|
|
22
|
+
if (value != null && type === 'object' && isArray(value)) {
|
|
25
23
|
defineProperty(this, key, {
|
|
26
24
|
enumerable: true,
|
|
27
25
|
value: this[REACTIVE_ARRAY](value)
|
|
@@ -40,31 +38,18 @@ class ReactiveObject {
|
|
|
40
38
|
});
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
|
-
[REACTIVE_ARRAY](value) {
|
|
44
|
-
let node = new ReactiveArray(...value);
|
|
45
|
-
(this.disposers ??= []).push(() => node.dispose());
|
|
46
|
-
return node;
|
|
47
|
-
}
|
|
48
41
|
[COMPUTED](value) {
|
|
49
42
|
return root(() => {
|
|
50
43
|
let node = computed(value);
|
|
51
|
-
if (isPromise(node.value)) {
|
|
52
|
-
let factory = node, out = signal(undefined), v = 0;
|
|
53
|
-
(this.disposers ??= []).push(effect(() => {
|
|
54
|
-
let id = ++v;
|
|
55
|
-
read(factory).then((resolved) => {
|
|
56
|
-
if (id !== v) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
write(out, resolved);
|
|
60
|
-
});
|
|
61
|
-
}));
|
|
62
|
-
return out;
|
|
63
|
-
}
|
|
64
44
|
(this.disposers ??= []).push(() => dispose(node));
|
|
65
45
|
return node;
|
|
66
46
|
});
|
|
67
47
|
}
|
|
48
|
+
[REACTIVE_ARRAY](value) {
|
|
49
|
+
let node = new ReactiveArray(...value);
|
|
50
|
+
(this.disposers ??= []).push(() => node.dispose());
|
|
51
|
+
return node;
|
|
52
|
+
}
|
|
68
53
|
[SIGNAL](value) {
|
|
69
54
|
return signal(value);
|
|
70
55
|
}
|
package/build/system.d.ts
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
|
-
import { Computed, Signal } from './types.js';
|
|
2
|
-
declare const
|
|
3
|
-
declare const computed:
|
|
1
|
+
import { Computed, ComputedResult, Settled, Signal } from './types.js';
|
|
2
|
+
declare const batch: <T>(fn: () => T) => T;
|
|
3
|
+
declare const computed: {
|
|
4
|
+
<T>(fn: Computed<T>["fn"], equals?: ((a: Settled<T>, b: Settled<T>) => boolean) | null): ComputedResult<T>;
|
|
5
|
+
invalidate<T>(c: Computed<T>): void;
|
|
6
|
+
};
|
|
4
7
|
declare const dispose: <T>(computed: Computed<T>) => void;
|
|
5
|
-
declare const effect: <T>(fn: Computed<T>["fn"]) => () => void;
|
|
8
|
+
declare const effect: <T>(fn: Computed<T>["fn"], apply?: (value: T, prev: T | undefined) => void) => () => void;
|
|
9
|
+
declare const flush: () => void;
|
|
6
10
|
declare const isComputed: (value: unknown) => value is Computed<unknown>;
|
|
7
11
|
declare const isSignal: (value: unknown) => value is Signal<unknown>;
|
|
8
12
|
declare const onCleanup: (fn: VoidFunction) => typeof fn;
|
|
13
|
+
declare const peek: <T>(node: Signal<T> | Computed<T>) => T;
|
|
9
14
|
declare const read: <T>(node: Signal<T> | Computed<T>) => T;
|
|
10
15
|
declare const root: {
|
|
11
16
|
<T>(fn: ((dispose: VoidFunction) => T) | (() => T)): T;
|
|
12
17
|
disposables: number;
|
|
13
18
|
};
|
|
14
|
-
declare const signal:
|
|
19
|
+
declare const signal: {
|
|
20
|
+
<T>(value: T, equals?: ((a: T, b: T) => boolean) | null): Signal<T>;
|
|
21
|
+
selector<T>(node: Signal<T>, key: T): boolean;
|
|
22
|
+
};
|
|
23
|
+
declare const untrack: <T>(fn: () => T) => T;
|
|
15
24
|
declare const write: <T>(signal: Signal<T>, value: T) => void;
|
|
16
|
-
export {
|
|
25
|
+
export { batch, computed, dispose, effect, flush, isComputed, isSignal, onCleanup, peek, read, root, signal, untrack, write };
|
|
17
26
|
export type { Computed, Signal };
|