@esportsplus/reactivity 0.4.8 → 0.6.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 +7 -9
- package/build/constants.js +7 -9
- package/build/index.d.ts +1 -3
- package/build/index.js +1 -3
- package/build/reactive/array.d.ts +20 -17
- package/build/reactive/array.js +101 -52
- package/build/reactive/disposable.d.ts +4 -0
- package/build/reactive/disposable.js +6 -0
- package/build/reactive/index.d.ts +3 -3
- package/build/reactive/index.js +10 -6
- package/build/reactive/object.d.ts +12 -7
- package/build/reactive/object.js +55 -22
- package/build/reactive/promise.d.ts +13 -0
- package/build/reactive/promise.js +48 -0
- package/build/signal.d.ts +15 -31
- package/build/signal.js +270 -232
- package/build/types.d.ts +27 -37
- package/build/types.js +1 -1
- package/package.json +4 -4
- package/readme.md +2 -2
- package/src/constants.ts +7 -12
- package/src/index.ts +1 -3
- package/src/reactive/array.ts +143 -67
- package/src/reactive/disposable.ts +8 -0
- package/src/reactive/index.ts +18 -12
- package/src/reactive/object.ts +69 -26
- package/src/reactive/promise.ts +67 -0
- package/src/signal.ts +338 -263
- package/src/types.ts +36 -57
- package/build/macro.d.ts +0 -9
- package/build/macro.js +0 -17
- package/src/macro.ts +0 -26
package/build/signal.d.ts
CHANGED
|
@@ -1,31 +1,15 @@
|
|
|
1
|
-
import { Computed,
|
|
2
|
-
declare
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
dispatch<D>(event: Event, data?: D): void;
|
|
17
|
-
dispose(): void;
|
|
18
|
-
get(): T;
|
|
19
|
-
on<T>(event: Event, listener: Listener<T>): void;
|
|
20
|
-
once<T>(event: Event, listener: Listener<T>): void;
|
|
21
|
-
set(value: T): T;
|
|
22
|
-
}
|
|
23
|
-
declare const computed: <T>(fn: Computed<T>["fn"], options?: Options) => Computed<T>;
|
|
24
|
-
declare const dispose: <T extends {
|
|
25
|
-
dispose: VoidFunction;
|
|
26
|
-
}>(dispose?: T[] | T | null) => T | T[] | null | undefined;
|
|
27
|
-
declare const effect: (fn: Effect["fn"]) => Effect;
|
|
28
|
-
declare const root: <T>(fn: NeverAsync<(instance: Root) => T>, scheduler?: Scheduler) => T;
|
|
29
|
-
declare const signal: <T>(value: T, options?: Options) => Signal<T>;
|
|
30
|
-
export { computed, dispose, effect, root, signal };
|
|
31
|
-
export { Reactive };
|
|
1
|
+
import { Computed, Signal } from './types.js';
|
|
2
|
+
declare const computed: <T>(fn: Computed<T>["fn"]) => Computed<T>;
|
|
3
|
+
declare const dispose: <T>(el: Computed<T>) => void;
|
|
4
|
+
declare const isComputed: (value: unknown) => value is Computed<unknown>;
|
|
5
|
+
declare const isReactive: (value: unknown) => value is Computed<unknown> | Signal<unknown>;
|
|
6
|
+
declare const isSignal: (value: unknown) => value is Signal<unknown>;
|
|
7
|
+
declare const oncleanup: (fn: VoidFunction) => typeof fn;
|
|
8
|
+
declare const read: <T>(el: Signal<T> | Computed<T>) => T;
|
|
9
|
+
declare const root: <T>(fn: () => T) => T;
|
|
10
|
+
declare const signal: {
|
|
11
|
+
<T>(value: T): Signal<T>;
|
|
12
|
+
set<T>(el: Signal<T>, v: T): void;
|
|
13
|
+
};
|
|
14
|
+
declare const stabilize: () => void;
|
|
15
|
+
export { computed, dispose, isComputed, isReactive, isSignal, oncleanup, read, root, signal, stabilize };
|
package/build/signal.js
CHANGED
|
@@ -1,280 +1,318 @@
|
|
|
1
|
-
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import {
|
|
3
|
-
let
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
listeners = null;
|
|
8
|
-
observers = null;
|
|
9
|
-
root;
|
|
10
|
-
scheduler = null;
|
|
11
|
-
sources = null;
|
|
12
|
-
state;
|
|
13
|
-
task = null;
|
|
14
|
-
tracking = null;
|
|
15
|
-
type;
|
|
16
|
-
value;
|
|
17
|
-
constructor(state, type, value) {
|
|
18
|
-
let root = null;
|
|
19
|
-
if (type !== ROOT) {
|
|
20
|
-
if (scope !== null) {
|
|
21
|
-
root = scope;
|
|
22
|
-
}
|
|
23
|
-
else if (observer !== null) {
|
|
24
|
-
root = observer.root;
|
|
25
|
-
}
|
|
26
|
-
if (root == null) {
|
|
27
|
-
if (type === EFFECT) {
|
|
28
|
-
throw new Error(`@esportsplus/reactivity: 'effect' cannot be created without a reactive root`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
else if (root.tracking) {
|
|
32
|
-
root.on('dispose', () => this.dispose());
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
this.root = root;
|
|
36
|
-
this.state = state;
|
|
37
|
-
this.type = type;
|
|
38
|
-
this.value = value;
|
|
1
|
+
import { isArray, isObject } from '@esportsplus/utilities';
|
|
2
|
+
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants.js';
|
|
3
|
+
let dirtyHeap = new Array(2000), maxDirty = 0, markedHeap = false, minDirty = 0, observer = null;
|
|
4
|
+
function cleanup(node) {
|
|
5
|
+
if (!node.cleanup) {
|
|
6
|
+
return;
|
|
39
7
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
let listeners = this.listeners[event];
|
|
45
|
-
for (let i = 0, n = listeners.length; i < n; i++) {
|
|
46
|
-
let listener = listeners[i];
|
|
47
|
-
if (listener === null) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
|
-
listener(data, this.value);
|
|
52
|
-
if (listener.once !== undefined) {
|
|
53
|
-
listeners[i] = null;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
listeners[i] = null;
|
|
58
|
-
}
|
|
8
|
+
if (isArray(node.cleanup)) {
|
|
9
|
+
for (let i = 0; i < node.cleanup.length; i++) {
|
|
10
|
+
node.cleanup[i]();
|
|
59
11
|
}
|
|
60
12
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
this.dispatch('cleanup', this);
|
|
66
|
-
this.dispatch('dispose', this);
|
|
67
|
-
removeSourceObservers(this, 0);
|
|
68
|
-
this.listeners = null;
|
|
69
|
-
this.observers = null;
|
|
70
|
-
this.sources = null;
|
|
71
|
-
this.state = DISPOSED;
|
|
72
|
-
}
|
|
73
|
-
get() {
|
|
74
|
-
if (this.state === DISPOSED) {
|
|
75
|
-
return this.value;
|
|
76
|
-
}
|
|
77
|
-
if (observer !== null) {
|
|
78
|
-
if (observers === null) {
|
|
79
|
-
if (observer.sources !== null && observer.sources[index] == this) {
|
|
80
|
-
index++;
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
observers = [this];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
observers.push(this);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (this.type === COMPUTED || this.type === EFFECT) {
|
|
91
|
-
sync(this);
|
|
92
|
-
}
|
|
93
|
-
return this.value;
|
|
13
|
+
else {
|
|
14
|
+
node.cleanup();
|
|
94
15
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
16
|
+
node.cleanup = null;
|
|
17
|
+
}
|
|
18
|
+
function deleteFromHeap(n) {
|
|
19
|
+
let state = n.state;
|
|
20
|
+
if (!(state & STATE_IN_HEAP)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
n.state = state & ~STATE_IN_HEAP;
|
|
24
|
+
let height = n.height;
|
|
25
|
+
if (n.prevHeap === n) {
|
|
26
|
+
dirtyHeap[height] = undefined;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
let next = n.nextHeap, dhh = dirtyHeap[height], end = next ?? dhh;
|
|
30
|
+
if (n === dhh) {
|
|
31
|
+
dirtyHeap[height] = next;
|
|
104
32
|
}
|
|
105
33
|
else {
|
|
106
|
-
|
|
107
|
-
if (listeners === undefined) {
|
|
108
|
-
this.listeners[event] = [listener];
|
|
109
|
-
}
|
|
110
|
-
else if (listeners.indexOf(listener) === -1) {
|
|
111
|
-
let i = listeners.indexOf(null);
|
|
112
|
-
if (i === -1) {
|
|
113
|
-
listeners.push(listener);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
listeners[i] = listener;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
34
|
+
n.prevHeap.nextHeap = next;
|
|
119
35
|
}
|
|
36
|
+
end.prevHeap = n.prevHeap;
|
|
37
|
+
}
|
|
38
|
+
n.nextHeap = undefined;
|
|
39
|
+
n.prevHeap = n;
|
|
40
|
+
}
|
|
41
|
+
function insertIntoHeap(n) {
|
|
42
|
+
let state = n.state;
|
|
43
|
+
if (state & STATE_IN_HEAP) {
|
|
44
|
+
return;
|
|
120
45
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
46
|
+
n.state = state | STATE_IN_HEAP;
|
|
47
|
+
let height = n.height, heapAtHeight = dirtyHeap[height];
|
|
48
|
+
if (heapAtHeight === undefined) {
|
|
49
|
+
dirtyHeap[height] = n;
|
|
124
50
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
51
|
+
else {
|
|
52
|
+
let tail = heapAtHeight.prevHeap;
|
|
53
|
+
tail.nextHeap = n;
|
|
54
|
+
n.prevHeap = tail;
|
|
55
|
+
heapAtHeight.prevHeap = n;
|
|
56
|
+
}
|
|
57
|
+
if (height > maxDirty) {
|
|
58
|
+
maxDirty = height;
|
|
59
|
+
if (height >= dirtyHeap.length) {
|
|
60
|
+
dirtyHeap.length += 250;
|
|
132
61
|
}
|
|
133
|
-
return this.value;
|
|
134
62
|
}
|
|
135
63
|
}
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
function notify(nodes, state) {
|
|
140
|
-
if (nodes === null) {
|
|
64
|
+
function link(dep, sub) {
|
|
65
|
+
let prevDep = sub.depsTail;
|
|
66
|
+
if (prevDep !== null && prevDep.dep === dep) {
|
|
141
67
|
return;
|
|
142
68
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
node.state = state;
|
|
150
|
-
notify(node.observers, CHECK);
|
|
69
|
+
let nextDep = null;
|
|
70
|
+
if (sub.state & STATE_RECOMPUTING) {
|
|
71
|
+
nextDep = prevDep !== null ? prevDep.nextDep : sub.deps;
|
|
72
|
+
if (nextDep !== null && nextDep.dep === dep) {
|
|
73
|
+
sub.depsTail = nextDep;
|
|
74
|
+
return;
|
|
151
75
|
}
|
|
152
76
|
}
|
|
77
|
+
let prevSub = dep.subsTail, newLink = sub.depsTail =
|
|
78
|
+
dep.subsTail = {
|
|
79
|
+
dep,
|
|
80
|
+
sub,
|
|
81
|
+
nextDep,
|
|
82
|
+
prevSub,
|
|
83
|
+
nextSub: null,
|
|
84
|
+
};
|
|
85
|
+
if (prevDep !== null) {
|
|
86
|
+
prevDep.nextDep = newLink;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
sub.deps = newLink;
|
|
90
|
+
}
|
|
91
|
+
if (prevSub !== null) {
|
|
92
|
+
prevSub.nextSub = newLink;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
dep.subs = newLink;
|
|
96
|
+
}
|
|
153
97
|
}
|
|
154
|
-
function
|
|
155
|
-
if (
|
|
98
|
+
function markHeap() {
|
|
99
|
+
if (markedHeap) {
|
|
156
100
|
return;
|
|
157
101
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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);
|
|
162
106
|
}
|
|
163
|
-
observers[observers.indexOf(node)] = observers[observers.length - 1];
|
|
164
|
-
observers.pop();
|
|
165
107
|
}
|
|
166
108
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
109
|
+
function markNode(el, newState = STATE_DIRTY) {
|
|
110
|
+
let state = el.state;
|
|
111
|
+
if ((state & (STATE_CHECK | STATE_DIRTY)) >= newState) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
el.state = state | newState;
|
|
115
|
+
for (let link = el.subs; link !== null; link = link.nextSub) {
|
|
116
|
+
markNode(link.sub, STATE_CHECK);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function recompute(el, del) {
|
|
120
|
+
if (del) {
|
|
121
|
+
deleteFromHeap(el);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
el.nextHeap = undefined;
|
|
125
|
+
el.prevHeap = el;
|
|
126
|
+
}
|
|
127
|
+
cleanup(el);
|
|
128
|
+
let o = observer, ok = true, value;
|
|
129
|
+
observer = el;
|
|
130
|
+
el.depsTail = null;
|
|
131
|
+
el.state = STATE_RECOMPUTING;
|
|
132
|
+
try {
|
|
133
|
+
value = el.fn(oncleanup);
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
ok = false;
|
|
137
|
+
}
|
|
138
|
+
observer = o;
|
|
139
|
+
el.state = STATE_NONE;
|
|
140
|
+
let depsTail = el.depsTail, toRemove = depsTail !== null ? depsTail.nextDep : el.deps;
|
|
141
|
+
if (toRemove !== null) {
|
|
142
|
+
do {
|
|
143
|
+
toRemove = unlink(toRemove);
|
|
144
|
+
} while (toRemove !== null);
|
|
145
|
+
if (depsTail !== null) {
|
|
146
|
+
depsTail.nextDep = null;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
el.deps = null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (ok && value !== el.value) {
|
|
153
|
+
el.value = value;
|
|
154
|
+
for (let s = el.subs; s !== null; s = s.nextSub) {
|
|
155
|
+
let o = s.sub, state = o.state;
|
|
156
|
+
if (state & STATE_CHECK) {
|
|
157
|
+
o.state = state | STATE_DIRTY;
|
|
173
158
|
}
|
|
159
|
+
insertIntoHeap(o);
|
|
174
160
|
}
|
|
175
161
|
}
|
|
176
|
-
|
|
177
|
-
|
|
162
|
+
}
|
|
163
|
+
function unlink(link) {
|
|
164
|
+
let dep = link.dep, nextDep = link.nextDep, nextSub = link.nextSub, prevSub = link.prevSub;
|
|
165
|
+
if (nextSub !== null) {
|
|
166
|
+
nextSub.prevSub = prevSub;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
dep.subsTail = prevSub;
|
|
170
|
+
}
|
|
171
|
+
if (prevSub !== null) {
|
|
172
|
+
prevSub.nextSub = nextSub;
|
|
178
173
|
}
|
|
179
174
|
else {
|
|
180
|
-
|
|
175
|
+
dep.subs = nextSub;
|
|
176
|
+
if (nextSub === null && 'fn' in dep) {
|
|
177
|
+
dispose(dep);
|
|
178
|
+
}
|
|
181
179
|
}
|
|
180
|
+
return nextDep;
|
|
182
181
|
}
|
|
183
|
-
function update(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
node.dispatch('cleanup');
|
|
190
|
-
node.dispatch('update');
|
|
191
|
-
let value = node.fn.call(null, node);
|
|
192
|
-
if (observers) {
|
|
193
|
-
removeSourceObservers(node, index);
|
|
194
|
-
if (node.sources !== null && index > 0) {
|
|
195
|
-
node.sources.length = index + observers.length;
|
|
196
|
-
for (let i = 0, n = observers.length; i < n; i++) {
|
|
197
|
-
node.sources[index + i] = observers[i];
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
node.sources = observers;
|
|
182
|
+
function update(el) {
|
|
183
|
+
if (el.state & STATE_CHECK) {
|
|
184
|
+
for (let d = el.deps; d; d = d.nextDep) {
|
|
185
|
+
let dep = d.dep;
|
|
186
|
+
if ('fn' in dep) {
|
|
187
|
+
update(dep);
|
|
202
188
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (source.observers === null) {
|
|
206
|
-
source.observers = [node];
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
source.observers.push(node);
|
|
210
|
-
}
|
|
189
|
+
if (el.state & STATE_DIRTY) {
|
|
190
|
+
break;
|
|
211
191
|
}
|
|
212
192
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
193
|
+
}
|
|
194
|
+
if (el.state & STATE_DIRTY) {
|
|
195
|
+
recompute(el, true);
|
|
196
|
+
}
|
|
197
|
+
el.state = STATE_NONE;
|
|
198
|
+
}
|
|
199
|
+
const computed = (fn) => {
|
|
200
|
+
let self = {
|
|
201
|
+
[REACTIVE]: true,
|
|
202
|
+
cleanup: null,
|
|
203
|
+
deps: null,
|
|
204
|
+
depsTail: null,
|
|
205
|
+
fn: fn,
|
|
206
|
+
height: 0,
|
|
207
|
+
nextHeap: undefined,
|
|
208
|
+
prevHeap: null,
|
|
209
|
+
state: STATE_NONE,
|
|
210
|
+
subs: null,
|
|
211
|
+
subsTail: null,
|
|
212
|
+
value: undefined,
|
|
213
|
+
};
|
|
214
|
+
self.prevHeap = self;
|
|
215
|
+
if (observer) {
|
|
216
|
+
if (observer.depsTail === null) {
|
|
217
|
+
self.height = observer.height;
|
|
218
|
+
recompute(self, false);
|
|
216
219
|
}
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
else {
|
|
221
|
+
self.height = observer.height + 1;
|
|
222
|
+
insertIntoHeap(self);
|
|
219
223
|
}
|
|
224
|
+
link(self, observer);
|
|
220
225
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
observer = o;
|
|
224
|
-
observers = os;
|
|
226
|
+
else {
|
|
227
|
+
recompute(self, false);
|
|
225
228
|
}
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
const computed = (fn, options) => {
|
|
229
|
-
let instance = new Reactive(DIRTY, COMPUTED, undefined);
|
|
230
|
-
instance.changed = options?.changed || changed;
|
|
231
|
-
instance.fn = fn;
|
|
232
|
-
return instance;
|
|
229
|
+
return self;
|
|
233
230
|
};
|
|
234
|
-
const dispose = (
|
|
235
|
-
|
|
231
|
+
const dispose = (el) => {
|
|
232
|
+
deleteFromHeap(el);
|
|
233
|
+
let dep = el.deps;
|
|
234
|
+
while (dep !== null) {
|
|
235
|
+
dep = unlink(dep);
|
|
236
236
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
el.deps = null;
|
|
238
|
+
cleanup(el);
|
|
239
|
+
};
|
|
240
|
+
const isComputed = (value) => {
|
|
241
|
+
return isObject(value) && REACTIVE in value && 'fn' in value;
|
|
242
|
+
};
|
|
243
|
+
const isReactive = (value) => {
|
|
244
|
+
return isObject(value) && REACTIVE in value;
|
|
245
|
+
};
|
|
246
|
+
const isSignal = (value) => {
|
|
247
|
+
return isObject(value) && REACTIVE in value && 'fn' in value === false;
|
|
248
|
+
};
|
|
249
|
+
const oncleanup = (fn) => {
|
|
250
|
+
if (!observer) {
|
|
251
|
+
return fn;
|
|
252
|
+
}
|
|
253
|
+
let node = observer;
|
|
254
|
+
if (!node.cleanup) {
|
|
255
|
+
node.cleanup = fn;
|
|
256
|
+
}
|
|
257
|
+
else if (isArray(node.cleanup)) {
|
|
258
|
+
node.cleanup.push(fn);
|
|
241
259
|
}
|
|
242
260
|
else {
|
|
243
|
-
|
|
261
|
+
node.cleanup = [node.cleanup, fn];
|
|
244
262
|
}
|
|
245
|
-
return
|
|
246
|
-
};
|
|
247
|
-
const effect = (fn) => {
|
|
248
|
-
let instance = new Reactive(DIRTY, EFFECT, null);
|
|
249
|
-
instance.fn = fn;
|
|
250
|
-
instance.task = () => instance.get();
|
|
251
|
-
update(instance);
|
|
252
|
-
return instance;
|
|
263
|
+
return fn;
|
|
253
264
|
};
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
265
|
+
const read = (el) => {
|
|
266
|
+
if (observer) {
|
|
267
|
+
link(el, observer);
|
|
268
|
+
if ('fn' in el) {
|
|
269
|
+
let height = el.height;
|
|
270
|
+
if (height >= observer.height) {
|
|
271
|
+
observer.height = height + 1;
|
|
272
|
+
}
|
|
273
|
+
if (height >= minDirty ||
|
|
274
|
+
el.state & (STATE_DIRTY | STATE_CHECK)) {
|
|
275
|
+
markHeap();
|
|
276
|
+
update(el);
|
|
277
|
+
}
|
|
262
278
|
}
|
|
263
|
-
scheduler = scope.scheduler;
|
|
264
279
|
}
|
|
280
|
+
return el.value;
|
|
281
|
+
};
|
|
282
|
+
const root = (fn) => {
|
|
283
|
+
let o = observer;
|
|
265
284
|
observer = null;
|
|
266
|
-
|
|
267
|
-
scope.scheduler = scheduler;
|
|
268
|
-
scope.tracking = fn.length > 0;
|
|
269
|
-
let result = fn.call(null, scope);
|
|
285
|
+
let value = fn();
|
|
270
286
|
observer = o;
|
|
271
|
-
|
|
272
|
-
|
|
287
|
+
return value;
|
|
288
|
+
};
|
|
289
|
+
const signal = (value) => {
|
|
290
|
+
return {
|
|
291
|
+
[REACTIVE]: true,
|
|
292
|
+
subs: null,
|
|
293
|
+
subsTail: null,
|
|
294
|
+
value,
|
|
295
|
+
};
|
|
273
296
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
297
|
+
signal.set = (el, v) => {
|
|
298
|
+
if (el.value === v) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
el.value = v;
|
|
302
|
+
for (let link = el.subs; link !== null; link = link.nextSub) {
|
|
303
|
+
markedHeap = false;
|
|
304
|
+
insertIntoHeap(link.sub);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const stabilize = () => {
|
|
308
|
+
for (minDirty = 0; minDirty <= maxDirty; minDirty++) {
|
|
309
|
+
let el = dirtyHeap[minDirty];
|
|
310
|
+
dirtyHeap[minDirty] = undefined;
|
|
311
|
+
while (el !== undefined) {
|
|
312
|
+
let next = el.nextHeap;
|
|
313
|
+
recompute(el, false);
|
|
314
|
+
el = next;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
278
317
|
};
|
|
279
|
-
export { computed, dispose,
|
|
280
|
-
export { Reactive };
|
|
318
|
+
export { computed, dispose, isComputed, isReactive, isSignal, oncleanup, read, root, signal, stabilize };
|
package/build/types.d.ts
CHANGED
|
@@ -1,43 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants.js';
|
|
2
|
+
import { oncleanup } from './signal.js';
|
|
2
3
|
import { ReactiveArray } from './reactive/array.js';
|
|
3
4
|
import { ReactiveObject } from './reactive/object.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
task: Function;
|
|
17
|
-
} & Omit<Base<void>, 'value'>;
|
|
18
|
-
type Infer<T> = T extends (...args: unknown[]) => unknown ? ReturnType<T> : T extends (infer U)[] ? ReactiveArray<U> : T extends ReactiveObject<T> ? ReactiveObject<T> : T extends Record<PropertyKey, unknown> ? {
|
|
5
|
+
interface Computed<T> extends Signal<T> {
|
|
6
|
+
[REACTIVE]: true;
|
|
7
|
+
cleanup: VoidFunction | VoidFunction[] | null;
|
|
8
|
+
deps: Link | null;
|
|
9
|
+
depsTail: Link | null;
|
|
10
|
+
fn: (oc?: typeof oncleanup) => T;
|
|
11
|
+
height: number;
|
|
12
|
+
nextHeap: Computed<unknown> | undefined;
|
|
13
|
+
prevHeap: Computed<unknown>;
|
|
14
|
+
state: typeof STATE_CHECK | typeof STATE_DIRTY | typeof STATE_IN_HEAP | typeof STATE_NONE | typeof STATE_RECOMPUTING;
|
|
15
|
+
}
|
|
16
|
+
type Infer<T> = T extends (...args: unknown[]) => unknown ? ReturnType<T> : T extends (infer U)[] ? ReactiveArray<U> : T extends ReactiveObject<any> ? T : T extends Record<PropertyKey, unknown> ? {
|
|
19
17
|
[K in keyof T]: T[K];
|
|
20
18
|
} : T;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
19
|
+
interface Link {
|
|
20
|
+
dep: Signal<unknown> | Computed<unknown>;
|
|
21
|
+
sub: Computed<unknown>;
|
|
22
|
+
nextDep: Link | null;
|
|
23
|
+
nextSub: Link | null;
|
|
24
|
+
prevSub: Link | null;
|
|
25
|
+
}
|
|
29
26
|
type Reactive<T> = T extends Record<PropertyKey, unknown> ? ReactiveObject<T> : ReactiveArray<T>;
|
|
30
|
-
type Root = {
|
|
31
|
-
scheduler: Scheduler;
|
|
32
|
-
tracking: boolean;
|
|
33
|
-
value: void;
|
|
34
|
-
} & Omit<ReactiveBase<void>, 'root'>;
|
|
35
|
-
type Scheduler = (fn: Function) => unknown;
|
|
36
27
|
type Signal<T> = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
type
|
|
43
|
-
export type { Changed, Computed, Effect, Event, Function, Infer, Listener, NeverAsync, Options, Prettify, Reactive, ReactiveArray, ReactiveObject, Root, Scheduler, Signal, State, Type };
|
|
28
|
+
[REACTIVE]: true;
|
|
29
|
+
subs: Link | null;
|
|
30
|
+
subsTail: Link | null;
|
|
31
|
+
value: T;
|
|
32
|
+
};
|
|
33
|
+
export type { Computed, Infer, Link, Signal, Reactive, ReactiveArray, ReactiveObject };
|
package/build/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import { REACTIVE } from './constants.js';
|