@esportsplus/reactivity 0.8.0 → 0.8.1
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/index.d.ts +1 -2
- package/build/index.js +1 -2
- package/build/reactive/{promise.d.ts → async.d.ts} +2 -2
- package/build/reactive/{promise.js → async.js} +2 -2
- package/build/reactive/index.d.ts +5 -4
- package/build/reactive/index.js +15 -10
- package/build/reactive/object.js +2 -2
- package/build/signal.d.ts +6 -10
- package/build/signal.js +112 -107
- package/build/types.d.ts +2 -2
- package/package.json +1 -1
- package/src/index.ts +1 -2
- package/src/reactive/{promise.ts → async.ts} +2 -2
- package/src/reactive/index.ts +32 -22
- package/src/reactive/object.ts +2 -2
- package/src/signal.ts +125 -119
- package/src/types.ts +2 -2
- package/build/scheduler.d.ts +0 -4
- package/build/scheduler.js +0 -17
- package/src/scheduler.ts +0 -27
package/build/index.d.ts
CHANGED
package/build/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import CustomFunction from '@esportsplus/custom-function';
|
|
2
|
-
declare class
|
|
2
|
+
declare class ReactiveAsyncFunction<A extends unknown[], R extends Promise<unknown>> extends CustomFunction {
|
|
3
3
|
private arguments;
|
|
4
4
|
private okay;
|
|
5
5
|
private response;
|
|
@@ -9,5 +9,5 @@ declare class ReactivePromise<A extends unknown[], R extends Promise<unknown>> e
|
|
|
9
9
|
get input(): A | null;
|
|
10
10
|
get ok(): boolean | null;
|
|
11
11
|
}
|
|
12
|
-
declare const _default: <A extends unknown[], R extends Promise<unknown>>(fn: (...args: A) => R) =>
|
|
12
|
+
declare const _default: <A extends unknown[], R extends Promise<unknown>>(fn: (...args: A) => R) => ReactiveAsyncFunction<A, R>;
|
|
13
13
|
export default _default;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import CustomFunction from '@esportsplus/custom-function';
|
|
2
2
|
import { read, root, signal } from '../signal.js';
|
|
3
3
|
let { set } = signal;
|
|
4
|
-
class
|
|
4
|
+
class ReactiveAsyncFunction extends CustomFunction {
|
|
5
5
|
arguments;
|
|
6
6
|
okay;
|
|
7
7
|
response;
|
|
@@ -44,5 +44,5 @@ class ReactivePromise extends CustomFunction {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
export default (fn) => {
|
|
47
|
-
return new
|
|
47
|
+
return new ReactiveAsyncFunction(fn);
|
|
48
48
|
};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { Computed } from '../types.js';
|
|
1
2
|
import array from './array.js';
|
|
3
|
+
import async from './async.js';
|
|
2
4
|
import object from './object.js';
|
|
3
|
-
|
|
4
|
-
type
|
|
5
|
-
type Guard<T> = T extends (...args: unknown[]) => Promise<unknown> ? T : T extends {
|
|
5
|
+
type API<T> = T extends (...args: infer A) => Promise<infer R> ? ReturnType<typeof async<A, Promise<R>>> : T extends (...args: unknown[]) => unknown ? void : T extends Record<PropertyKey, unknown> ? ReturnType<typeof object<T>> : T extends unknown[] ? ReturnType<typeof array<T>> : never;
|
|
6
|
+
type Input<T> = T extends (...args: unknown[]) => Promise<unknown> ? T : T extends (...args: unknown[]) => unknown ? Computed<T>['fn'] : T extends {
|
|
6
7
|
dispose: any;
|
|
7
8
|
} | {
|
|
8
9
|
signals: any;
|
|
9
10
|
} ? {
|
|
10
11
|
never: '[ dispose, signals ] are reserved keys';
|
|
11
12
|
} : T extends Record<PropertyKey, unknown> | unknown[] ? T : never;
|
|
12
|
-
declare const _default: <T>(
|
|
13
|
+
declare const _default: <T>(input: Input<T>) => API<T>;
|
|
13
14
|
export default _default;
|
package/build/reactive/index.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import { isArray,
|
|
1
|
+
import { isArray, isAsyncFunction, isFunction, isObject } from '@esportsplus/utilities';
|
|
2
|
+
import { computed } from '../signal.js';
|
|
2
3
|
import array from './array.js';
|
|
4
|
+
import async from './async.js';
|
|
3
5
|
import object from './object.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return array(data);
|
|
6
|
+
export default (input) => {
|
|
7
|
+
if (isArray(input)) {
|
|
8
|
+
return array(input);
|
|
8
9
|
}
|
|
9
|
-
else if (
|
|
10
|
-
return
|
|
10
|
+
else if (isAsyncFunction(input)) {
|
|
11
|
+
return async(input);
|
|
11
12
|
}
|
|
12
|
-
else if (
|
|
13
|
-
|
|
13
|
+
else if (isFunction(input)) {
|
|
14
|
+
computed(input);
|
|
15
|
+
return undefined;
|
|
14
16
|
}
|
|
15
|
-
|
|
17
|
+
else if (isObject(input)) {
|
|
18
|
+
return object(input);
|
|
19
|
+
}
|
|
20
|
+
throw new Error(`@esportsplus/reactivity: 'reactive' received invalid input - ${JSON.stringify(input)}`);
|
|
16
21
|
};
|
package/build/reactive/object.js
CHANGED
|
@@ -2,7 +2,7 @@ import { defineProperty, isArray, isAsyncFunction, isFunction, isInstanceOf } fr
|
|
|
2
2
|
import array from './array.js';
|
|
3
3
|
import { computed, dispose, read, signal } from '../signal.js';
|
|
4
4
|
import { Disposable } from './disposable.js';
|
|
5
|
-
import
|
|
5
|
+
import async from './async.js';
|
|
6
6
|
let { set } = signal;
|
|
7
7
|
class ReactiveObject extends Disposable {
|
|
8
8
|
disposable = {};
|
|
@@ -26,7 +26,7 @@ class ReactiveObject extends Disposable {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
else if (isAsyncFunction(value)) {
|
|
29
|
-
let p =
|
|
29
|
+
let p = async(value);
|
|
30
30
|
defineProperty(this, key, {
|
|
31
31
|
enumerable: true,
|
|
32
32
|
get() {
|
package/build/signal.d.ts
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { Computed, Signal } from './types.js';
|
|
2
2
|
declare const computed: <T>(fn: Computed<T>["fn"]) => Computed<T>;
|
|
3
|
-
declare const dispose: <T>(
|
|
3
|
+
declare const dispose: <T>(computed: Computed<T>) => void;
|
|
4
4
|
declare const isComputed: (value: unknown) => value is Computed<unknown>;
|
|
5
|
-
declare const isReactive: (value: unknown) => value is Computed<unknown> | Signal<unknown>;
|
|
6
5
|
declare const isSignal: (value: unknown) => value is Signal<unknown>;
|
|
7
|
-
declare const
|
|
8
|
-
declare const read: <T>(
|
|
6
|
+
declare const onCleanup: (fn: VoidFunction) => typeof fn;
|
|
7
|
+
declare const read: <T>(node: Signal<T> | Computed<T>) => T;
|
|
9
8
|
declare const root: <T>(fn: () => T) => T;
|
|
10
9
|
declare const signal: {
|
|
11
10
|
<T>(value: T): Signal<T>;
|
|
12
|
-
set<T>(
|
|
11
|
+
set<T>(signal: Signal<T>, value: T): void;
|
|
13
12
|
};
|
|
14
|
-
declare const stabilize:
|
|
15
|
-
|
|
16
|
-
state: Signal<number>;
|
|
17
|
-
};
|
|
18
|
-
export { computed, dispose, isComputed, isReactive, isSignal, oncleanup, read, root, signal, stabilize };
|
|
13
|
+
declare const stabilize: () => void;
|
|
14
|
+
export { computed, dispose, isComputed, isSignal, onCleanup, read, root, signal, stabilize };
|
package/build/signal.js
CHANGED
|
@@ -1,63 +1,64 @@
|
|
|
1
|
-
import { isArray, isObject } from '@esportsplus/utilities';
|
|
1
|
+
import { defineProperty, isArray, isObject } from '@esportsplus/utilities';
|
|
2
2
|
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants.js';
|
|
3
|
-
let
|
|
3
|
+
let heap = new Array(2000), iHeap = 0, nHeap = 0, notifiedHeap = false, observer = null, scheduled = false, scheduler = null;
|
|
4
4
|
function cleanup(node) {
|
|
5
5
|
if (!node.cleanup) {
|
|
6
6
|
return;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
let cleanup = node.cleanup;
|
|
9
|
+
if (isArray(cleanup)) {
|
|
10
|
+
for (let i = 0; i < cleanup.length; i++) {
|
|
11
|
+
cleanup[i]();
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
14
|
else {
|
|
14
|
-
|
|
15
|
+
cleanup();
|
|
15
16
|
}
|
|
16
17
|
node.cleanup = null;
|
|
17
18
|
}
|
|
18
|
-
function deleteFromHeap(
|
|
19
|
-
let state =
|
|
19
|
+
function deleteFromHeap(computed) {
|
|
20
|
+
let state = computed.state;
|
|
20
21
|
if (!(state & STATE_IN_HEAP)) {
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
-
let height =
|
|
25
|
-
if (
|
|
26
|
-
|
|
24
|
+
computed.state = state & ~STATE_IN_HEAP;
|
|
25
|
+
let height = computed.height;
|
|
26
|
+
if (computed.prevHeap === computed) {
|
|
27
|
+
heap[height] = undefined;
|
|
27
28
|
}
|
|
28
29
|
else {
|
|
29
|
-
let next =
|
|
30
|
-
if (
|
|
31
|
-
|
|
30
|
+
let next = computed.nextHeap, dhh = heap[height], end = next ?? dhh;
|
|
31
|
+
if (computed === dhh) {
|
|
32
|
+
heap[height] = next;
|
|
32
33
|
}
|
|
33
34
|
else {
|
|
34
|
-
|
|
35
|
+
computed.prevHeap.nextHeap = next;
|
|
35
36
|
}
|
|
36
|
-
end.prevHeap =
|
|
37
|
+
end.prevHeap = computed.prevHeap;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
computed.nextHeap = undefined;
|
|
40
|
+
computed.prevHeap = computed;
|
|
40
41
|
}
|
|
41
|
-
function insertIntoHeap(
|
|
42
|
-
let state =
|
|
42
|
+
function insertIntoHeap(computed) {
|
|
43
|
+
let state = computed.state;
|
|
43
44
|
if (state & STATE_IN_HEAP) {
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
let height =
|
|
47
|
+
computed.state = state | STATE_IN_HEAP;
|
|
48
|
+
let height = computed.height, heapAtHeight = heap[height];
|
|
48
49
|
if (heapAtHeight === undefined) {
|
|
49
|
-
|
|
50
|
+
heap[height] = computed;
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
52
53
|
let tail = heapAtHeight.prevHeap;
|
|
53
|
-
tail.nextHeap =
|
|
54
|
-
|
|
55
|
-
heapAtHeight.prevHeap =
|
|
56
|
-
}
|
|
57
|
-
if (height >
|
|
58
|
-
|
|
59
|
-
if (height >=
|
|
60
|
-
|
|
54
|
+
tail.nextHeap = computed;
|
|
55
|
+
computed.prevHeap = tail;
|
|
56
|
+
heapAtHeight.prevHeap = computed;
|
|
57
|
+
}
|
|
58
|
+
if (height > nHeap) {
|
|
59
|
+
nHeap = height;
|
|
60
|
+
if (height >= heap.length) {
|
|
61
|
+
heap.length += 250;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
}
|
|
@@ -95,49 +96,38 @@ function link(dep, sub) {
|
|
|
95
96
|
dep.subs = newLink;
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
|
-
function
|
|
99
|
-
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
markedHeap = true;
|
|
103
|
-
for (let i = 0; i <= maxDirty; i++) {
|
|
104
|
-
for (let el = dirtyHeap[i]; el !== undefined; el = el.nextHeap) {
|
|
105
|
-
markNode(el);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function markNode(el, newState = STATE_DIRTY) {
|
|
110
|
-
let state = el.state;
|
|
99
|
+
function notify(computed, newState = STATE_DIRTY) {
|
|
100
|
+
let state = computed.state;
|
|
111
101
|
if ((state & (STATE_CHECK | STATE_DIRTY)) >= newState) {
|
|
112
102
|
return;
|
|
113
103
|
}
|
|
114
|
-
|
|
115
|
-
for (let link =
|
|
116
|
-
|
|
104
|
+
computed.state = state | newState;
|
|
105
|
+
for (let link = computed.subs; link !== null; link = link.nextSub) {
|
|
106
|
+
notify(link.sub, STATE_CHECK);
|
|
117
107
|
}
|
|
118
108
|
}
|
|
119
|
-
function recompute(
|
|
109
|
+
function recompute(computed, del) {
|
|
120
110
|
if (del) {
|
|
121
|
-
deleteFromHeap(
|
|
111
|
+
deleteFromHeap(computed);
|
|
122
112
|
}
|
|
123
113
|
else {
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
computed.nextHeap = undefined;
|
|
115
|
+
computed.prevHeap = computed;
|
|
126
116
|
}
|
|
127
|
-
cleanup(
|
|
117
|
+
cleanup(computed);
|
|
128
118
|
let o = observer, ok = true, value;
|
|
129
|
-
observer =
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
observer = computed;
|
|
120
|
+
computed.depsTail = null;
|
|
121
|
+
computed.state = STATE_RECOMPUTING;
|
|
132
122
|
try {
|
|
133
|
-
value =
|
|
123
|
+
value = computed.fn(onCleanup);
|
|
134
124
|
}
|
|
135
125
|
catch (e) {
|
|
136
126
|
ok = false;
|
|
137
127
|
}
|
|
138
128
|
observer = o;
|
|
139
|
-
|
|
140
|
-
let depsTail =
|
|
129
|
+
computed.state = STATE_NONE;
|
|
130
|
+
let depsTail = computed.depsTail, toRemove = depsTail !== null ? depsTail.nextDep : computed.deps;
|
|
141
131
|
if (toRemove !== null) {
|
|
142
132
|
do {
|
|
143
133
|
toRemove = unlink(toRemove);
|
|
@@ -146,21 +136,25 @@ function recompute(el, del) {
|
|
|
146
136
|
depsTail.nextDep = null;
|
|
147
137
|
}
|
|
148
138
|
else {
|
|
149
|
-
|
|
139
|
+
computed.deps = null;
|
|
150
140
|
}
|
|
151
141
|
}
|
|
152
|
-
if (ok && value !==
|
|
153
|
-
|
|
154
|
-
for (let
|
|
155
|
-
let o =
|
|
142
|
+
if (ok && value !== computed.value) {
|
|
143
|
+
computed.value = value;
|
|
144
|
+
for (let c = computed.subs; c !== null; c = c.nextSub) {
|
|
145
|
+
let o = c.sub, state = o.state;
|
|
156
146
|
if (state & STATE_CHECK) {
|
|
157
147
|
o.state = state | STATE_DIRTY;
|
|
158
148
|
}
|
|
159
149
|
insertIntoHeap(o);
|
|
160
150
|
}
|
|
161
151
|
}
|
|
162
|
-
if (
|
|
163
|
-
|
|
152
|
+
if (!scheduled && scheduler) {
|
|
153
|
+
scheduled = true;
|
|
154
|
+
scheduler(stabilize);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
throw new Error('@esportsplus/reactivity: stabilize.scheduler has not been set to process updates.');
|
|
164
158
|
}
|
|
165
159
|
}
|
|
166
160
|
function unlink(link) {
|
|
@@ -182,22 +176,22 @@ function unlink(link) {
|
|
|
182
176
|
}
|
|
183
177
|
return nextDep;
|
|
184
178
|
}
|
|
185
|
-
function update(
|
|
186
|
-
if (
|
|
187
|
-
for (let
|
|
188
|
-
let dep =
|
|
179
|
+
function update(computed) {
|
|
180
|
+
if (computed.state & STATE_CHECK) {
|
|
181
|
+
for (let link = computed.deps; link; link = link.nextDep) {
|
|
182
|
+
let dep = link.dep;
|
|
189
183
|
if ('fn' in dep) {
|
|
190
184
|
update(dep);
|
|
191
185
|
}
|
|
192
|
-
if (
|
|
186
|
+
if (computed.state & STATE_DIRTY) {
|
|
193
187
|
break;
|
|
194
188
|
}
|
|
195
189
|
}
|
|
196
190
|
}
|
|
197
|
-
if (
|
|
198
|
-
recompute(
|
|
191
|
+
if (computed.state & STATE_DIRTY) {
|
|
192
|
+
recompute(computed, true);
|
|
199
193
|
}
|
|
200
|
-
|
|
194
|
+
computed.state = STATE_NONE;
|
|
201
195
|
}
|
|
202
196
|
const computed = (fn) => {
|
|
203
197
|
let self = {
|
|
@@ -231,25 +225,22 @@ const computed = (fn) => {
|
|
|
231
225
|
}
|
|
232
226
|
return self;
|
|
233
227
|
};
|
|
234
|
-
const dispose = (
|
|
235
|
-
deleteFromHeap(
|
|
236
|
-
let dep =
|
|
228
|
+
const dispose = (computed) => {
|
|
229
|
+
deleteFromHeap(computed);
|
|
230
|
+
let dep = computed.deps;
|
|
237
231
|
while (dep !== null) {
|
|
238
232
|
dep = unlink(dep);
|
|
239
233
|
}
|
|
240
|
-
|
|
241
|
-
cleanup(
|
|
234
|
+
computed.deps = null;
|
|
235
|
+
cleanup(computed);
|
|
242
236
|
};
|
|
243
237
|
const isComputed = (value) => {
|
|
244
238
|
return isObject(value) && REACTIVE in value && 'fn' in value;
|
|
245
239
|
};
|
|
246
|
-
const isReactive = (value) => {
|
|
247
|
-
return isObject(value) && REACTIVE in value;
|
|
248
|
-
};
|
|
249
240
|
const isSignal = (value) => {
|
|
250
241
|
return isObject(value) && REACTIVE in value && 'fn' in value === false;
|
|
251
242
|
};
|
|
252
|
-
const
|
|
243
|
+
const onCleanup = (fn) => {
|
|
253
244
|
if (!observer) {
|
|
254
245
|
return fn;
|
|
255
246
|
}
|
|
@@ -265,22 +256,29 @@ const oncleanup = (fn) => {
|
|
|
265
256
|
}
|
|
266
257
|
return fn;
|
|
267
258
|
};
|
|
268
|
-
const read = (
|
|
259
|
+
const read = (node) => {
|
|
269
260
|
if (observer) {
|
|
270
|
-
link(
|
|
271
|
-
if ('fn' in
|
|
272
|
-
let height =
|
|
261
|
+
link(node, observer);
|
|
262
|
+
if ('fn' in node) {
|
|
263
|
+
let height = node.height;
|
|
273
264
|
if (height >= observer.height) {
|
|
274
265
|
observer.height = height + 1;
|
|
275
266
|
}
|
|
276
|
-
if (height >=
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
267
|
+
if (height >= iHeap ||
|
|
268
|
+
node.state & (STATE_DIRTY | STATE_CHECK)) {
|
|
269
|
+
if (!notifiedHeap) {
|
|
270
|
+
notifiedHeap = true;
|
|
271
|
+
for (let i = 0; i <= nHeap; i++) {
|
|
272
|
+
for (let computed = heap[i]; computed !== undefined; computed = computed.nextHeap) {
|
|
273
|
+
notify(computed);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
update(node);
|
|
280
278
|
}
|
|
281
279
|
}
|
|
282
280
|
}
|
|
283
|
-
return
|
|
281
|
+
return node.value;
|
|
284
282
|
};
|
|
285
283
|
const root = (fn) => {
|
|
286
284
|
let o = observer;
|
|
@@ -297,29 +295,36 @@ const signal = (value) => {
|
|
|
297
295
|
value,
|
|
298
296
|
};
|
|
299
297
|
};
|
|
300
|
-
signal.set = (
|
|
301
|
-
if (
|
|
298
|
+
signal.set = (signal, value) => {
|
|
299
|
+
if (signal.value === value) {
|
|
302
300
|
return;
|
|
303
301
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
302
|
+
notifiedHeap = false;
|
|
303
|
+
signal.value = value;
|
|
304
|
+
for (let link = signal.subs; link !== null; link = link.nextSub) {
|
|
307
305
|
insertIntoHeap(link.sub);
|
|
308
306
|
}
|
|
309
307
|
};
|
|
310
308
|
const stabilize = () => {
|
|
311
309
|
root(() => {
|
|
312
|
-
for (
|
|
313
|
-
let
|
|
314
|
-
|
|
315
|
-
while (
|
|
316
|
-
let next =
|
|
317
|
-
recompute(
|
|
318
|
-
|
|
310
|
+
for (iHeap = 0; iHeap <= nHeap; iHeap++) {
|
|
311
|
+
let computed = heap[iHeap];
|
|
312
|
+
heap[iHeap] = undefined;
|
|
313
|
+
while (computed !== undefined) {
|
|
314
|
+
let next = computed.nextHeap;
|
|
315
|
+
recompute(computed, false);
|
|
316
|
+
computed = next;
|
|
319
317
|
}
|
|
320
318
|
}
|
|
321
|
-
|
|
319
|
+
scheduled = false;
|
|
322
320
|
});
|
|
323
321
|
};
|
|
324
|
-
stabilize
|
|
325
|
-
|
|
322
|
+
defineProperty(stabilize, 'scheduler', {
|
|
323
|
+
get() {
|
|
324
|
+
return scheduler;
|
|
325
|
+
},
|
|
326
|
+
set(s) {
|
|
327
|
+
scheduler = s;
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
export { computed, dispose, isComputed, isSignal, onCleanup, read, root, signal, stabilize };
|
package/build/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants.js';
|
|
2
|
-
import {
|
|
2
|
+
import { onCleanup } from './signal.js';
|
|
3
3
|
import { ReactiveArray } from './reactive/array.js';
|
|
4
4
|
import { ReactiveObject } from './reactive/object.js';
|
|
5
5
|
interface Computed<T> extends Signal<T> {
|
|
@@ -7,7 +7,7 @@ interface Computed<T> extends Signal<T> {
|
|
|
7
7
|
cleanup: VoidFunction | VoidFunction[] | null;
|
|
8
8
|
deps: Link | null;
|
|
9
9
|
depsTail: Link | null;
|
|
10
|
-
fn: (oc?: typeof
|
|
10
|
+
fn: (oc?: typeof onCleanup) => T;
|
|
11
11
|
height: number;
|
|
12
12
|
nextHeap: Computed<unknown> | undefined;
|
|
13
13
|
prevHeap: Computed<unknown>;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Signal } from '~/types';
|
|
|
6
6
|
let { set } = signal;
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class ReactiveAsyncFunction<A extends unknown[], R extends Promise<unknown>> extends CustomFunction {
|
|
10
10
|
private arguments: Signal<A | null>;
|
|
11
11
|
private okay: Signal<boolean | null>;
|
|
12
12
|
private response: Signal<Awaited<R> | null>;
|
|
@@ -63,5 +63,5 @@ class ReactivePromise<A extends unknown[], R extends Promise<unknown>> extends C
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
export default <A extends unknown[], R extends Promise<unknown>>(fn: (...args: A) => R) => {
|
|
66
|
-
return new
|
|
66
|
+
return new ReactiveAsyncFunction(fn);
|
|
67
67
|
};
|
package/src/reactive/index.ts
CHANGED
|
@@ -1,38 +1,48 @@
|
|
|
1
|
-
import { isArray,
|
|
1
|
+
import { isArray, isAsyncFunction, isFunction, isObject } from '@esportsplus/utilities';
|
|
2
|
+
import { computed } from '~/signal';
|
|
3
|
+
import { Computed } from '~/types';
|
|
2
4
|
import array from './array';
|
|
5
|
+
import async from './async';
|
|
3
6
|
import object from './object';
|
|
4
|
-
import promise from './promise';
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
type API<T> =
|
|
8
10
|
T extends (...args: infer A) => Promise<infer R>
|
|
9
|
-
? ReturnType<typeof
|
|
10
|
-
: T extends
|
|
11
|
-
?
|
|
12
|
-
: T extends unknown
|
|
13
|
-
? ReturnType<typeof
|
|
14
|
-
:
|
|
11
|
+
? ReturnType<typeof async<A, Promise<R>>>
|
|
12
|
+
: T extends (...args: unknown[]) => unknown
|
|
13
|
+
? void
|
|
14
|
+
: T extends Record<PropertyKey, unknown>
|
|
15
|
+
? ReturnType<typeof object<T>>
|
|
16
|
+
: T extends unknown[]
|
|
17
|
+
? ReturnType<typeof array<T>>
|
|
18
|
+
: never;
|
|
15
19
|
|
|
16
|
-
type
|
|
20
|
+
type Input<T> =
|
|
17
21
|
T extends (...args: unknown[]) => Promise<unknown>
|
|
18
22
|
? T
|
|
19
|
-
: T extends
|
|
20
|
-
?
|
|
21
|
-
: T extends
|
|
22
|
-
?
|
|
23
|
-
:
|
|
23
|
+
: T extends (...args: unknown[]) => unknown
|
|
24
|
+
? Computed<T>['fn']
|
|
25
|
+
: T extends { dispose: any } | { signals: any }
|
|
26
|
+
? { never: '[ dispose, signals ] are reserved keys' }
|
|
27
|
+
: T extends Record<PropertyKey, unknown> | unknown[]
|
|
28
|
+
? T
|
|
29
|
+
: never;
|
|
24
30
|
|
|
25
31
|
|
|
26
|
-
export default <T>(
|
|
27
|
-
if (isArray(
|
|
28
|
-
return array(
|
|
32
|
+
export default <T>(input: Input<T>): API<T> => {
|
|
33
|
+
if (isArray(input)) {
|
|
34
|
+
return array(input) as API<T>;
|
|
29
35
|
}
|
|
30
|
-
else if (
|
|
31
|
-
return
|
|
36
|
+
else if (isAsyncFunction(input)) {
|
|
37
|
+
return async(input) as API<T>;
|
|
32
38
|
}
|
|
33
|
-
else if (
|
|
34
|
-
|
|
39
|
+
else if (isFunction(input)) {
|
|
40
|
+
computed(input as Computed<T>['fn']);
|
|
41
|
+
return undefined as API<T>;
|
|
42
|
+
}
|
|
43
|
+
else if (isObject(input)) {
|
|
44
|
+
return object(input) as API<T>;
|
|
35
45
|
}
|
|
36
46
|
|
|
37
|
-
throw new Error(`@esportsplus/reactivity: 'reactive' received invalid input - ${JSON.stringify(
|
|
47
|
+
throw new Error(`@esportsplus/reactivity: 'reactive' received invalid input - ${JSON.stringify(input)}`);
|
|
38
48
|
};
|
package/src/reactive/object.ts
CHANGED
|
@@ -3,7 +3,7 @@ import array, { ReactiveArray } from './array';
|
|
|
3
3
|
import { computed, dispose, read, signal } from '~/signal';
|
|
4
4
|
import { Computed, Infer, Signal } from '~/types';
|
|
5
5
|
import { Disposable } from './disposable';
|
|
6
|
-
import
|
|
6
|
+
import async from './async';
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
type API<T extends Record<PropertyKey, unknown>> = Prettify<{ [K in keyof T]: Infer<T[K]> }> & ReactiveObject<T>;
|
|
@@ -45,7 +45,7 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> extends Disposable
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
else if (isAsyncFunction(value)) {
|
|
48
|
-
let p =
|
|
48
|
+
let p = async(value);
|
|
49
49
|
|
|
50
50
|
defineProperty(this, key, {
|
|
51
51
|
enumerable: true,
|
package/src/signal.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { isArray, isObject } from '@esportsplus/utilities';
|
|
1
|
+
import { defineProperty, isArray, isObject } from '@esportsplus/utilities';
|
|
2
2
|
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants';
|
|
3
3
|
import { Computed, Link, Signal, } from './types';
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
observer: Computed<unknown> | null = null
|
|
6
|
+
let heap: (Computed<unknown> | undefined)[] = new Array(2000),
|
|
7
|
+
iHeap = 0,
|
|
8
|
+
nHeap = 0,
|
|
9
|
+
notifiedHeap = false,
|
|
10
|
+
observer: Computed<unknown> | null = null,
|
|
11
|
+
scheduled = false,
|
|
12
|
+
scheduler: ((task: VoidFunction) => void) | null = null;
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
function cleanup<T>(node: Computed<T>): void {
|
|
@@ -15,80 +17,82 @@ function cleanup<T>(node: Computed<T>): void {
|
|
|
15
17
|
return;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
let cleanup = node.cleanup;
|
|
21
|
+
|
|
22
|
+
if (isArray(cleanup)) {
|
|
23
|
+
for (let i = 0; i < cleanup.length; i++) {
|
|
24
|
+
cleanup[i]();
|
|
21
25
|
}
|
|
22
26
|
}
|
|
23
27
|
else {
|
|
24
|
-
|
|
28
|
+
cleanup();
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
node.cleanup = null;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
function deleteFromHeap<T>(
|
|
31
|
-
let state =
|
|
34
|
+
function deleteFromHeap<T>(computed: Computed<T>) {
|
|
35
|
+
let state = computed.state;
|
|
32
36
|
|
|
33
37
|
if (!(state & STATE_IN_HEAP)) {
|
|
34
38
|
return;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
computed.state = state & ~STATE_IN_HEAP;
|
|
38
42
|
|
|
39
|
-
let height =
|
|
43
|
+
let height = computed.height;
|
|
40
44
|
|
|
41
|
-
if (
|
|
42
|
-
|
|
45
|
+
if (computed.prevHeap === computed) {
|
|
46
|
+
heap[height] = undefined;
|
|
43
47
|
}
|
|
44
48
|
else {
|
|
45
|
-
let next =
|
|
46
|
-
dhh =
|
|
49
|
+
let next = computed.nextHeap,
|
|
50
|
+
dhh = heap[height]!,
|
|
47
51
|
end = next ?? dhh;
|
|
48
52
|
|
|
49
|
-
if (
|
|
50
|
-
|
|
53
|
+
if (computed === dhh) {
|
|
54
|
+
heap[height] = next;
|
|
51
55
|
}
|
|
52
56
|
else {
|
|
53
|
-
|
|
57
|
+
computed.prevHeap.nextHeap = next;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
end.prevHeap =
|
|
60
|
+
end.prevHeap = computed.prevHeap;
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
computed.nextHeap = undefined;
|
|
64
|
+
computed.prevHeap = computed;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
function insertIntoHeap<T>(
|
|
64
|
-
let state =
|
|
67
|
+
function insertIntoHeap<T>(computed: Computed<T>) {
|
|
68
|
+
let state = computed.state;
|
|
65
69
|
|
|
66
70
|
if (state & STATE_IN_HEAP) {
|
|
67
71
|
return;
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
|
|
74
|
+
computed.state = state | STATE_IN_HEAP;
|
|
71
75
|
|
|
72
|
-
let height =
|
|
73
|
-
heapAtHeight =
|
|
76
|
+
let height = computed.height,
|
|
77
|
+
heapAtHeight = heap[height];
|
|
74
78
|
|
|
75
79
|
if (heapAtHeight === undefined) {
|
|
76
|
-
|
|
80
|
+
heap[height] = computed;
|
|
77
81
|
}
|
|
78
82
|
else {
|
|
79
83
|
let tail = heapAtHeight.prevHeap;
|
|
80
84
|
|
|
81
|
-
tail.nextHeap =
|
|
82
|
-
|
|
83
|
-
heapAtHeight.prevHeap =
|
|
85
|
+
tail.nextHeap = computed;
|
|
86
|
+
computed.prevHeap = tail;
|
|
87
|
+
heapAtHeight.prevHeap = computed;
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
if (height >
|
|
87
|
-
|
|
90
|
+
if (height > nHeap) {
|
|
91
|
+
nHeap = height;
|
|
88
92
|
|
|
89
93
|
// Simple auto adjust to avoid manual management within apps.
|
|
90
|
-
if (height >=
|
|
91
|
-
|
|
94
|
+
if (height >= heap.length) {
|
|
95
|
+
heap.length += 250;
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
}
|
|
@@ -138,65 +142,51 @@ function link<T>(dep: Signal<T> | Computed<T>, sub: Computed<T>) {
|
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
144
|
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
markedHeap = true;
|
|
147
|
-
|
|
148
|
-
for (let i = 0; i <= maxDirty; i++) {
|
|
149
|
-
for (let el = dirtyHeap[i]; el !== undefined; el = el.nextHeap) {
|
|
150
|
-
markNode(el);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function markNode<T>(el: Computed<T>, newState = STATE_DIRTY) {
|
|
156
|
-
let state = el.state;
|
|
145
|
+
function notify<T>(computed: Computed<T>, newState = STATE_DIRTY) {
|
|
146
|
+
let state = computed.state;
|
|
157
147
|
|
|
158
148
|
if ((state & (STATE_CHECK | STATE_DIRTY)) >= newState) {
|
|
159
149
|
return;
|
|
160
150
|
}
|
|
161
151
|
|
|
162
|
-
|
|
152
|
+
computed.state = state | newState;
|
|
163
153
|
|
|
164
|
-
for (let link =
|
|
165
|
-
|
|
154
|
+
for (let link = computed.subs; link !== null; link = link.nextSub) {
|
|
155
|
+
notify(link.sub, STATE_CHECK);
|
|
166
156
|
}
|
|
167
157
|
}
|
|
168
158
|
|
|
169
|
-
function recompute<T>(
|
|
159
|
+
function recompute<T>(computed: Computed<T>, del: boolean) {
|
|
170
160
|
if (del) {
|
|
171
|
-
deleteFromHeap(
|
|
161
|
+
deleteFromHeap(computed);
|
|
172
162
|
}
|
|
173
163
|
else {
|
|
174
|
-
|
|
175
|
-
|
|
164
|
+
computed.nextHeap = undefined;
|
|
165
|
+
computed.prevHeap = computed;
|
|
176
166
|
}
|
|
177
167
|
|
|
178
|
-
cleanup(
|
|
168
|
+
cleanup(computed);
|
|
179
169
|
|
|
180
170
|
let o = observer,
|
|
181
171
|
ok = true,
|
|
182
172
|
value;
|
|
183
173
|
|
|
184
|
-
observer =
|
|
185
|
-
|
|
186
|
-
|
|
174
|
+
observer = computed;
|
|
175
|
+
computed.depsTail = null;
|
|
176
|
+
computed.state = STATE_RECOMPUTING;
|
|
187
177
|
|
|
188
178
|
try {
|
|
189
|
-
value =
|
|
179
|
+
value = computed.fn(onCleanup);
|
|
190
180
|
}
|
|
191
181
|
catch (e) {
|
|
192
182
|
ok = false;
|
|
193
183
|
}
|
|
194
184
|
|
|
195
185
|
observer = o;
|
|
196
|
-
|
|
186
|
+
computed.state = STATE_NONE;
|
|
197
187
|
|
|
198
|
-
let depsTail =
|
|
199
|
-
toRemove = depsTail !== null ? depsTail.nextDep :
|
|
188
|
+
let depsTail = computed.depsTail as Link | null,
|
|
189
|
+
toRemove = depsTail !== null ? depsTail.nextDep : computed.deps;
|
|
200
190
|
|
|
201
191
|
if (toRemove !== null) {
|
|
202
192
|
do {
|
|
@@ -208,15 +198,15 @@ function recompute<T>(el: Computed<T>, del: boolean) {
|
|
|
208
198
|
depsTail.nextDep = null;
|
|
209
199
|
}
|
|
210
200
|
else {
|
|
211
|
-
|
|
201
|
+
computed.deps = null;
|
|
212
202
|
}
|
|
213
203
|
}
|
|
214
204
|
|
|
215
|
-
if (ok && value !==
|
|
216
|
-
|
|
205
|
+
if (ok && value !== computed.value) {
|
|
206
|
+
computed.value = value as T;
|
|
217
207
|
|
|
218
|
-
for (let
|
|
219
|
-
let o =
|
|
208
|
+
for (let c = computed.subs; c !== null; c = c.nextSub) {
|
|
209
|
+
let o = c.sub,
|
|
220
210
|
state = o.state;
|
|
221
211
|
|
|
222
212
|
if (state & STATE_CHECK) {
|
|
@@ -227,8 +217,12 @@ function recompute<T>(el: Computed<T>, del: boolean) {
|
|
|
227
217
|
}
|
|
228
218
|
}
|
|
229
219
|
|
|
230
|
-
if (
|
|
231
|
-
|
|
220
|
+
if (!scheduled && scheduler) {
|
|
221
|
+
scheduled = true;
|
|
222
|
+
scheduler(stabilize);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
throw new Error('@esportsplus/reactivity: stabilize.scheduler has not been set to process updates.');
|
|
232
226
|
}
|
|
233
227
|
}
|
|
234
228
|
|
|
@@ -260,26 +254,26 @@ function unlink(link: Link): Link | null {
|
|
|
260
254
|
return nextDep;
|
|
261
255
|
}
|
|
262
256
|
|
|
263
|
-
function update<T>(
|
|
264
|
-
if (
|
|
265
|
-
for (let
|
|
266
|
-
let dep =
|
|
257
|
+
function update<T>(computed: Computed<T>): void {
|
|
258
|
+
if (computed.state & STATE_CHECK) {
|
|
259
|
+
for (let link = computed.deps; link; link = link.nextDep) {
|
|
260
|
+
let dep = link.dep;
|
|
267
261
|
|
|
268
262
|
if ('fn' in dep) {
|
|
269
263
|
update(dep);
|
|
270
264
|
}
|
|
271
265
|
|
|
272
|
-
if (
|
|
266
|
+
if (computed.state & STATE_DIRTY) {
|
|
273
267
|
break;
|
|
274
268
|
}
|
|
275
269
|
}
|
|
276
270
|
}
|
|
277
271
|
|
|
278
|
-
if (
|
|
279
|
-
recompute(
|
|
272
|
+
if (computed.state & STATE_DIRTY) {
|
|
273
|
+
recompute(computed, true);
|
|
280
274
|
}
|
|
281
275
|
|
|
282
|
-
|
|
276
|
+
computed.state = STATE_NONE;
|
|
283
277
|
}
|
|
284
278
|
|
|
285
279
|
|
|
@@ -320,33 +314,29 @@ const computed = <T>(fn: Computed<T>['fn']): Computed<T> => {
|
|
|
320
314
|
return self;
|
|
321
315
|
};
|
|
322
316
|
|
|
323
|
-
const dispose = <T>(
|
|
324
|
-
deleteFromHeap(
|
|
317
|
+
const dispose = <T>(computed: Computed<T>) => {
|
|
318
|
+
deleteFromHeap(computed);
|
|
325
319
|
|
|
326
|
-
let dep =
|
|
320
|
+
let dep = computed.deps;
|
|
327
321
|
|
|
328
322
|
while (dep !== null) {
|
|
329
323
|
dep = unlink(dep);
|
|
330
324
|
}
|
|
331
325
|
|
|
332
|
-
|
|
326
|
+
computed.deps = null;
|
|
333
327
|
|
|
334
|
-
cleanup(
|
|
335
|
-
}
|
|
328
|
+
cleanup(computed);
|
|
329
|
+
};
|
|
336
330
|
|
|
337
331
|
const isComputed = (value: unknown): value is Computed<unknown> => {
|
|
338
332
|
return isObject(value) && REACTIVE in value && 'fn' in value;
|
|
339
333
|
};
|
|
340
334
|
|
|
341
|
-
const isReactive = (value: unknown): value is Computed<unknown> | Signal<unknown> => {
|
|
342
|
-
return isObject(value) && REACTIVE in value;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
335
|
const isSignal = (value: unknown): value is Signal<unknown> => {
|
|
346
336
|
return isObject(value) && REACTIVE in value && 'fn' in value === false;
|
|
347
337
|
};
|
|
348
338
|
|
|
349
|
-
const
|
|
339
|
+
const onCleanup = (fn: VoidFunction): typeof fn => {
|
|
350
340
|
if (!observer) {
|
|
351
341
|
return fn;
|
|
352
342
|
}
|
|
@@ -366,28 +356,37 @@ const oncleanup = (fn: VoidFunction): typeof fn => {
|
|
|
366
356
|
return fn;
|
|
367
357
|
};
|
|
368
358
|
|
|
369
|
-
const read = <T>(
|
|
359
|
+
const read = <T>(node: Signal<T> | Computed<T>): T => {
|
|
370
360
|
if (observer) {
|
|
371
|
-
link(
|
|
361
|
+
link(node, observer);
|
|
372
362
|
|
|
373
|
-
if ('fn' in
|
|
374
|
-
let height =
|
|
363
|
+
if ('fn' in node) {
|
|
364
|
+
let height = node.height;
|
|
375
365
|
|
|
376
366
|
if (height >= observer.height) {
|
|
377
367
|
observer.height = height + 1;
|
|
378
368
|
}
|
|
379
369
|
|
|
380
370
|
if (
|
|
381
|
-
height >=
|
|
382
|
-
|
|
371
|
+
height >= iHeap ||
|
|
372
|
+
node.state & (STATE_DIRTY | STATE_CHECK)
|
|
383
373
|
) {
|
|
384
|
-
|
|
385
|
-
|
|
374
|
+
if (!notifiedHeap) {
|
|
375
|
+
notifiedHeap = true;
|
|
376
|
+
|
|
377
|
+
for (let i = 0; i <= nHeap; i++) {
|
|
378
|
+
for (let computed = heap[i]; computed !== undefined; computed = computed.nextHeap) {
|
|
379
|
+
notify(computed);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
update(node);
|
|
386
385
|
}
|
|
387
386
|
}
|
|
388
387
|
}
|
|
389
388
|
|
|
390
|
-
return
|
|
389
|
+
return node.value;
|
|
391
390
|
};
|
|
392
391
|
|
|
393
392
|
const root = <T>(fn: () => T) => {
|
|
@@ -411,47 +410,54 @@ const signal = <T>(value: T): Signal<T> => {
|
|
|
411
410
|
};
|
|
412
411
|
};
|
|
413
412
|
|
|
414
|
-
signal.set = <T>(
|
|
415
|
-
if (
|
|
413
|
+
signal.set = <T>(signal: Signal<T>, value: T) => {
|
|
414
|
+
if (signal.value === value) {
|
|
416
415
|
return;
|
|
417
416
|
}
|
|
418
417
|
|
|
419
|
-
|
|
418
|
+
notifiedHeap = false;
|
|
419
|
+
signal.value = value;
|
|
420
420
|
|
|
421
|
-
for (let link =
|
|
422
|
-
markedHeap = false;
|
|
421
|
+
for (let link = signal.subs; link !== null; link = link.nextSub) {
|
|
423
422
|
insertIntoHeap(link.sub);
|
|
424
423
|
}
|
|
425
424
|
};
|
|
426
425
|
|
|
427
426
|
const stabilize = () => {
|
|
428
427
|
root(() => {
|
|
429
|
-
for (
|
|
430
|
-
let
|
|
428
|
+
for (iHeap = 0; iHeap <= nHeap; iHeap++) {
|
|
429
|
+
let computed = heap[iHeap];
|
|
431
430
|
|
|
432
|
-
|
|
431
|
+
heap[iHeap] = undefined;
|
|
433
432
|
|
|
434
|
-
while (
|
|
435
|
-
let next =
|
|
433
|
+
while (computed !== undefined) {
|
|
434
|
+
let next = computed.nextHeap;
|
|
436
435
|
|
|
437
|
-
recompute(
|
|
436
|
+
recompute(computed, false);
|
|
438
437
|
|
|
439
|
-
|
|
438
|
+
computed = next;
|
|
440
439
|
}
|
|
441
440
|
}
|
|
442
441
|
|
|
443
|
-
|
|
442
|
+
scheduled = false;
|
|
444
443
|
});
|
|
445
444
|
};
|
|
446
445
|
|
|
447
|
-
stabilize
|
|
446
|
+
defineProperty(stabilize, 'scheduler', {
|
|
447
|
+
get() {
|
|
448
|
+
return scheduler;
|
|
449
|
+
},
|
|
450
|
+
set(s: typeof scheduler) {
|
|
451
|
+
scheduler = s;
|
|
452
|
+
},
|
|
453
|
+
});
|
|
448
454
|
|
|
449
455
|
|
|
450
456
|
export {
|
|
451
457
|
computed,
|
|
452
458
|
dispose,
|
|
453
|
-
isComputed,
|
|
454
|
-
|
|
459
|
+
isComputed, isSignal,
|
|
460
|
+
onCleanup,
|
|
455
461
|
read, root,
|
|
456
462
|
signal, stabilize
|
|
457
463
|
};
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants';
|
|
2
|
-
import {
|
|
2
|
+
import { onCleanup } from './signal';
|
|
3
3
|
import { ReactiveArray } from './reactive/array';
|
|
4
4
|
import { ReactiveObject } from './reactive/object';
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ interface Computed<T> extends Signal<T> {
|
|
|
9
9
|
cleanup: VoidFunction | VoidFunction[] | null;
|
|
10
10
|
deps: Link | null;
|
|
11
11
|
depsTail: Link | null;
|
|
12
|
-
fn: (oc?: typeof
|
|
12
|
+
fn: (oc?: typeof onCleanup) => T;
|
|
13
13
|
height: number;
|
|
14
14
|
nextHeap: Computed<unknown> | undefined;
|
|
15
15
|
prevHeap: Computed<unknown>;
|
package/build/scheduler.d.ts
DELETED
package/build/scheduler.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { STATE_DIRTY, STATE_NONE } from './constants.js';
|
|
2
|
-
import { computed, dispose, read, signal, stabilize } from './signal.js';
|
|
3
|
-
let c = null;
|
|
4
|
-
const scheduler = (schedule) => {
|
|
5
|
-
if (c) {
|
|
6
|
-
dispose(c);
|
|
7
|
-
}
|
|
8
|
-
c = computed(() => {
|
|
9
|
-
if (read(state) !== STATE_DIRTY) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
schedule(stabilize);
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
const state = signal(STATE_NONE);
|
|
16
|
-
export default scheduler;
|
|
17
|
-
export { state };
|
package/src/scheduler.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { STATE_DIRTY, STATE_NONE } from './constants';
|
|
2
|
-
import { computed, dispose, read, signal, stabilize } from './signal';
|
|
3
|
-
import { Computed } from './types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let c: Computed<void> | null = null;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const scheduler = (schedule: (task: VoidFunction) => void) => {
|
|
10
|
-
if (c) {
|
|
11
|
-
dispose(c);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
c = computed(() => {
|
|
15
|
-
if (read(state) !== STATE_DIRTY) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
schedule(stabilize);
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const state = signal(STATE_NONE);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export default scheduler;
|
|
27
|
-
export { state };
|