@esportsplus/reactivity 0.4.7 → 0.5.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/.github/dependabot.yml +2 -0
- package/.github/workflows/bump.yml +2 -0
- package/.github/workflows/dependabot.yml +12 -0
- package/.github/workflows/publish.yml +2 -0
- 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 +2 -2
- package/build/reactive/index.js +3 -3
- package/build/reactive/object.d.ts +12 -7
- package/build/reactive/object.js +42 -19
- package/build/signal.d.ts +15 -31
- package/build/signal.js +273 -235
- 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 +4 -4
- package/src/reactive/object.ts +56 -24
- 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/src/signal.ts
CHANGED
|
@@ -1,372 +1,447 @@
|
|
|
1
|
-
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import {
|
|
3
|
-
import { Computed,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let index = 0,
|
|
7
|
-
observer: Reactive<any> | null = null,
|
|
8
|
-
observers: Reactive<any>[] | null = null,
|
|
9
|
-
scope: Root | null = null;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Reactive<T> {
|
|
13
|
-
changed: Changed | null = null;
|
|
14
|
-
fn: Computed<T>['fn'] | Effect['fn'] | null = null;
|
|
15
|
-
listeners: Record<Event, (Listener<any> | null)[]> | null = null;
|
|
16
|
-
observers: Reactive<any>[] | null = null;
|
|
17
|
-
root: Root | null;
|
|
18
|
-
scheduler: Scheduler | null = null;
|
|
19
|
-
sources: Reactive<any>[] | null = null;
|
|
20
|
-
state: State;
|
|
21
|
-
task: Function | null = null;
|
|
22
|
-
tracking: boolean | null = null;
|
|
23
|
-
type: Type;
|
|
24
|
-
value: T;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
constructor(state: State, type: Type, value: T) {
|
|
28
|
-
let root = null;
|
|
29
|
-
|
|
30
|
-
if (type !== ROOT) {
|
|
31
|
-
if (scope !== null) {
|
|
32
|
-
root = scope;
|
|
33
|
-
}
|
|
34
|
-
else if (observer !== null) {
|
|
35
|
-
root = observer.root;
|
|
36
|
-
}
|
|
1
|
+
import { isArray, isObject } from '@esportsplus/utilities';
|
|
2
|
+
import { REACTIVE, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants';
|
|
3
|
+
import { Computed, Link, Signal, } from './types';
|
|
37
4
|
|
|
38
|
-
if (root == null) {
|
|
39
|
-
if (type === EFFECT) {
|
|
40
|
-
throw new Error(`@esportsplus/reactivity: 'effect' cannot be created without a reactive root`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
else if (root.tracking) {
|
|
44
|
-
root.on('dispose', () => this.dispose());
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
5
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
6
|
+
let context: Computed<unknown> | null = null,
|
|
7
|
+
dirtyHeap: (Computed<unknown> | undefined)[] = new Array(2000),
|
|
8
|
+
maxDirty = 0,
|
|
9
|
+
markedHeap = false,
|
|
10
|
+
minDirty = 0;
|
|
53
11
|
|
|
54
12
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
13
|
+
function cleanup(node: Computed<unknown>): void {
|
|
14
|
+
if (!node.cleanup) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (isArray(node.cleanup)) {
|
|
19
|
+
for (let i = 0; i < node.cleanup.length; i++) {
|
|
20
|
+
node.cleanup[i]();
|
|
58
21
|
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
node.cleanup();
|
|
25
|
+
}
|
|
59
26
|
|
|
60
|
-
|
|
27
|
+
node.cleanup = null;
|
|
28
|
+
}
|
|
61
29
|
|
|
62
|
-
|
|
63
|
-
|
|
30
|
+
function deleteFromHeap(n: Computed<unknown>) {
|
|
31
|
+
let state = n.state;
|
|
64
32
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
33
|
+
if (!(state & STATE_IN_HEAP)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
68
36
|
|
|
69
|
-
|
|
70
|
-
listener(data, this.value);
|
|
37
|
+
n.state = state & ~STATE_IN_HEAP;
|
|
71
38
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
catch {
|
|
77
|
-
listeners[i] = null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
39
|
+
let height = n.height;
|
|
40
|
+
|
|
41
|
+
if (n.prevHeap === n) {
|
|
42
|
+
dirtyHeap[height] = undefined;
|
|
80
43
|
}
|
|
44
|
+
else {
|
|
45
|
+
let next = n.nextHeap,
|
|
46
|
+
dhh = dirtyHeap[height]!,
|
|
47
|
+
end = next ?? dhh;
|
|
81
48
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
49
|
+
if (n === dhh) {
|
|
50
|
+
dirtyHeap[height] = next;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
n.prevHeap.nextHeap = next;
|
|
85
54
|
}
|
|
86
55
|
|
|
87
|
-
|
|
88
|
-
|
|
56
|
+
end.prevHeap = n.prevHeap;
|
|
57
|
+
}
|
|
89
58
|
|
|
90
|
-
|
|
59
|
+
n.nextHeap = undefined;
|
|
60
|
+
n.prevHeap = n;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function insertIntoHeap(n: Computed<unknown>) {
|
|
64
|
+
let state = n.state;
|
|
91
65
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.sources = null;
|
|
95
|
-
this.state = DISPOSED;
|
|
66
|
+
if (state & STATE_IN_HEAP) {
|
|
67
|
+
return;
|
|
96
68
|
}
|
|
97
69
|
|
|
98
|
-
|
|
99
|
-
if (this.state === DISPOSED) {
|
|
100
|
-
return this.value;
|
|
101
|
-
}
|
|
70
|
+
n.state = state | STATE_IN_HEAP;
|
|
102
71
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (observer.sources !== null && observer.sources[index] == this) {
|
|
106
|
-
index++;
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
observers = [this];
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
observers.push(this);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
72
|
+
let height = n.height,
|
|
73
|
+
heapAtHeight = dirtyHeap[height];
|
|
116
74
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
75
|
+
if (heapAtHeight === undefined) {
|
|
76
|
+
dirtyHeap[height] = n;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
let tail = heapAtHeight.prevHeap;
|
|
120
80
|
|
|
121
|
-
|
|
81
|
+
tail.nextHeap = n;
|
|
82
|
+
n.prevHeap = tail;
|
|
83
|
+
heapAtHeight.prevHeap = n;
|
|
122
84
|
}
|
|
123
85
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (event !== 'cleanup') {
|
|
127
|
-
throw new Error(`@esportsplus/reactivity: events set within computed or effects must use the 'cleanup' event name`);
|
|
128
|
-
}
|
|
86
|
+
if (height > maxDirty) {
|
|
87
|
+
maxDirty = height;
|
|
129
88
|
|
|
130
|
-
|
|
89
|
+
// Simple auto adjust to avoid manual management within apps.
|
|
90
|
+
if (height >= dirtyHeap.length) {
|
|
91
|
+
dirtyHeap.length += 250;
|
|
131
92
|
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
132
95
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
else {
|
|
137
|
-
let listeners = this.listeners[event];
|
|
96
|
+
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L52
|
|
97
|
+
function link(dep: Signal<unknown> | Computed<unknown>, sub: Computed<unknown>) {
|
|
98
|
+
let prevDep = sub.depsTail;
|
|
138
99
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
else if (listeners.indexOf(listener) === -1) {
|
|
143
|
-
let i = listeners.indexOf(null);
|
|
144
|
-
|
|
145
|
-
if (i === -1) {
|
|
146
|
-
listeners.push(listener);
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
listeners[i] = listener;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
100
|
+
if (prevDep !== null && prevDep.dep === dep) {
|
|
101
|
+
return;
|
|
153
102
|
}
|
|
154
103
|
|
|
155
|
-
|
|
156
|
-
listener.once = true;
|
|
157
|
-
this.on(event, listener);
|
|
158
|
-
}
|
|
104
|
+
let nextDep: Link | null = null;
|
|
159
105
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
throw new Error(`@esportsplus/reactivity: 'set' method is only available on signals`);
|
|
163
|
-
}
|
|
106
|
+
if (sub.state & STATE_RECOMPUTING) {
|
|
107
|
+
nextDep = prevDep !== null ? prevDep.nextDep : sub.deps;
|
|
164
108
|
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
109
|
+
if (nextDep !== null && nextDep.dep === dep) {
|
|
110
|
+
sub.depsTail = nextDep;
|
|
111
|
+
return;
|
|
168
112
|
}
|
|
169
|
-
|
|
170
|
-
return this.value;
|
|
171
113
|
}
|
|
172
|
-
}
|
|
173
114
|
|
|
115
|
+
let prevSub = dep.subsTail,
|
|
116
|
+
newLink =
|
|
117
|
+
sub.depsTail =
|
|
118
|
+
dep.subsTail = {
|
|
119
|
+
dep,
|
|
120
|
+
sub,
|
|
121
|
+
nextDep,
|
|
122
|
+
prevSub,
|
|
123
|
+
nextSub: null,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (prevDep !== null) {
|
|
127
|
+
prevDep.nextDep = newLink;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
sub.deps = newLink;
|
|
131
|
+
}
|
|
174
132
|
|
|
175
|
-
|
|
176
|
-
|
|
133
|
+
if (prevSub !== null) {
|
|
134
|
+
prevSub.nextSub = newLink;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
dep.subs = newLink;
|
|
138
|
+
}
|
|
177
139
|
}
|
|
178
140
|
|
|
179
|
-
function
|
|
180
|
-
if (
|
|
141
|
+
function markHeap() {
|
|
142
|
+
if (markedHeap) {
|
|
181
143
|
return;
|
|
182
144
|
}
|
|
183
145
|
|
|
184
|
-
|
|
185
|
-
let node = nodes[i];
|
|
146
|
+
markedHeap = true;
|
|
186
147
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
node.state = state;
|
|
193
|
-
notify(node.observers, CHECK);
|
|
148
|
+
for (let i = 0; i <= maxDirty; i++) {
|
|
149
|
+
for (let el = dirtyHeap[i]; el !== undefined; el = el.nextHeap) {
|
|
150
|
+
markNode(el);
|
|
194
151
|
}
|
|
195
152
|
}
|
|
196
153
|
}
|
|
197
154
|
|
|
198
|
-
function
|
|
199
|
-
|
|
155
|
+
function markNode(el: Computed<unknown>, newState = STATE_DIRTY) {
|
|
156
|
+
let state = el.state;
|
|
157
|
+
|
|
158
|
+
if ((state & (STATE_CHECK | STATE_DIRTY)) >= newState) {
|
|
200
159
|
return;
|
|
201
160
|
}
|
|
202
161
|
|
|
203
|
-
|
|
204
|
-
|
|
162
|
+
el.state = state | newState;
|
|
163
|
+
|
|
164
|
+
for (let link = el.subs; link !== null; link = link.nextSub) {
|
|
165
|
+
markNode(link.sub, STATE_CHECK);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function recompute(el: Computed<unknown>, del: boolean) {
|
|
170
|
+
if (del) {
|
|
171
|
+
deleteFromHeap(el);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
el.nextHeap = undefined;
|
|
175
|
+
el.prevHeap = el;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
cleanup(el);
|
|
179
|
+
|
|
180
|
+
let oldcontext = context,
|
|
181
|
+
ok = true,
|
|
182
|
+
value;
|
|
205
183
|
|
|
206
|
-
|
|
207
|
-
|
|
184
|
+
context = el;
|
|
185
|
+
el.depsTail = null;
|
|
186
|
+
el.state = STATE_RECOMPUTING;
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
value = el.fn(oncleanup);
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
ok = false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
context = oldcontext;
|
|
196
|
+
el.state = STATE_NONE;
|
|
197
|
+
|
|
198
|
+
let depsTail = el.depsTail as Link | null,
|
|
199
|
+
toRemove = depsTail !== null ? depsTail.nextDep : el.deps;
|
|
200
|
+
|
|
201
|
+
if (toRemove !== null) {
|
|
202
|
+
do {
|
|
203
|
+
toRemove = unlink(toRemove);
|
|
208
204
|
}
|
|
205
|
+
while (toRemove !== null);
|
|
209
206
|
|
|
210
|
-
|
|
211
|
-
|
|
207
|
+
if (depsTail !== null) {
|
|
208
|
+
depsTail.nextDep = null;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
el.deps = null;
|
|
212
|
+
}
|
|
212
213
|
}
|
|
213
|
-
}
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
for (let i = 0, n = node.sources.length; i < n; i++) {
|
|
218
|
-
sync(node.sources[i]);
|
|
215
|
+
if (ok && value !== el.value) {
|
|
216
|
+
el.value = value;
|
|
219
217
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
218
|
+
for (let s = el.subs; s !== null; s = s.nextSub) {
|
|
219
|
+
let o = s.sub,
|
|
220
|
+
state = o.state;
|
|
221
|
+
|
|
222
|
+
if (state & STATE_CHECK) {
|
|
223
|
+
o.state = state | STATE_DIRTY;
|
|
225
224
|
}
|
|
225
|
+
|
|
226
|
+
insertIntoHeap(o);
|
|
226
227
|
}
|
|
227
228
|
}
|
|
229
|
+
}
|
|
228
230
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
+
// https://github.com/stackblitz/alien-signals/blob/v2.0.3/src/system.ts#L100
|
|
232
|
+
function unlink(link: Link): Link | null {
|
|
233
|
+
let dep = link.dep,
|
|
234
|
+
nextDep = link.nextDep,
|
|
235
|
+
nextSub = link.nextSub,
|
|
236
|
+
prevSub = link.prevSub;
|
|
237
|
+
|
|
238
|
+
if (nextSub !== null) {
|
|
239
|
+
nextSub.prevSub = prevSub;
|
|
231
240
|
}
|
|
232
241
|
else {
|
|
233
|
-
|
|
242
|
+
dep.subsTail = prevSub;
|
|
234
243
|
}
|
|
235
|
-
}
|
|
236
244
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
index = 0;
|
|
243
|
-
observer = node;
|
|
244
|
-
observers = null as typeof observers;
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
node.dispatch('cleanup');
|
|
248
|
-
node.dispatch('update');
|
|
245
|
+
if (prevSub !== null) {
|
|
246
|
+
prevSub.nextSub = nextSub;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
dep.subs = nextSub;
|
|
249
250
|
|
|
250
|
-
|
|
251
|
-
|
|
251
|
+
if (nextSub === null && 'fn' in dep) {
|
|
252
|
+
dispose(dep);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
252
255
|
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
return nextDep;
|
|
257
|
+
}
|
|
255
258
|
|
|
256
|
-
|
|
257
|
-
|
|
259
|
+
function update(el: Computed<unknown>): void {
|
|
260
|
+
if (el.state & STATE_CHECK) {
|
|
261
|
+
for (let d = el.deps; d; d = d.nextDep) {
|
|
262
|
+
let dep = d.dep;
|
|
258
263
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
264
|
+
if ('fn' in dep) {
|
|
265
|
+
update(dep);
|
|
262
266
|
}
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
|
|
268
|
+
if (el.state & STATE_DIRTY) {
|
|
269
|
+
break;
|
|
265
270
|
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
266
273
|
|
|
267
|
-
|
|
268
|
-
|
|
274
|
+
if (el.state & STATE_DIRTY) {
|
|
275
|
+
recompute(el, true);
|
|
276
|
+
}
|
|
269
277
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
278
|
+
el.state = STATE_NONE;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
const computed = <T>(fn: Computed<T>['fn']): Computed<T> => {
|
|
283
|
+
let self: Computed<T> = {
|
|
284
|
+
[REACTIVE]: true,
|
|
285
|
+
cleanup: null,
|
|
286
|
+
deps: null,
|
|
287
|
+
depsTail: null,
|
|
288
|
+
fn: fn,
|
|
289
|
+
height: 0,
|
|
290
|
+
nextHeap: undefined,
|
|
291
|
+
prevHeap: null as any,
|
|
292
|
+
state: STATE_NONE,
|
|
293
|
+
subs: null,
|
|
294
|
+
subsTail: null,
|
|
295
|
+
value: undefined as T,
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
self.prevHeap = self;
|
|
299
|
+
|
|
300
|
+
if (context) {
|
|
301
|
+
if (context.depsTail === null) {
|
|
302
|
+
self.height = context.height;
|
|
303
|
+
recompute(self, false);
|
|
277
304
|
}
|
|
278
|
-
else
|
|
279
|
-
|
|
280
|
-
|
|
305
|
+
else {
|
|
306
|
+
self.height = context.height + 1;
|
|
307
|
+
insertIntoHeap(self);
|
|
281
308
|
}
|
|
282
309
|
|
|
283
|
-
|
|
284
|
-
node.set(value as T);
|
|
285
|
-
}
|
|
310
|
+
link(self, context);
|
|
286
311
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
observer = o;
|
|
290
|
-
observers = os;
|
|
312
|
+
else {
|
|
313
|
+
recompute(self, false);
|
|
291
314
|
}
|
|
292
315
|
|
|
293
|
-
|
|
294
|
-
}
|
|
316
|
+
return self;
|
|
317
|
+
};
|
|
295
318
|
|
|
319
|
+
const dispose = (el: Computed<unknown>) => {
|
|
320
|
+
deleteFromHeap(el);
|
|
296
321
|
|
|
297
|
-
|
|
298
|
-
let instance = new Reactive(DIRTY, COMPUTED, undefined as T);
|
|
322
|
+
let dep = el.deps;
|
|
299
323
|
|
|
300
|
-
|
|
301
|
-
|
|
324
|
+
while (dep !== null) {
|
|
325
|
+
dep = unlink(dep);
|
|
326
|
+
}
|
|
302
327
|
|
|
303
|
-
|
|
328
|
+
el.deps = null;
|
|
329
|
+
|
|
330
|
+
cleanup(el);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const isComputed = (value: unknown): value is Computed<unknown> => {
|
|
334
|
+
return isObject(value) && REACTIVE in value && 'fn' in value;
|
|
304
335
|
};
|
|
305
336
|
|
|
306
|
-
const
|
|
307
|
-
|
|
337
|
+
const isReactive = (value: unknown): value is Computed<unknown> | Signal<unknown> => {
|
|
338
|
+
return isObject(value) && REACTIVE in value;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const isSignal = (value: unknown): value is Signal<unknown> => {
|
|
342
|
+
return isObject(value) && REACTIVE in value && 'fn' in value === false;
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const oncleanup = (fn: VoidFunction): typeof fn => {
|
|
346
|
+
if (!context) {
|
|
347
|
+
return fn;
|
|
308
348
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
349
|
+
|
|
350
|
+
let node = context;
|
|
351
|
+
|
|
352
|
+
if (!node.cleanup) {
|
|
353
|
+
node.cleanup = fn;
|
|
354
|
+
}
|
|
355
|
+
else if (isArray(node.cleanup)) {
|
|
356
|
+
node.cleanup.push(fn);
|
|
313
357
|
}
|
|
314
358
|
else {
|
|
315
|
-
|
|
359
|
+
node.cleanup = [node.cleanup, fn];
|
|
316
360
|
}
|
|
317
361
|
|
|
318
|
-
return
|
|
362
|
+
return fn;
|
|
319
363
|
};
|
|
320
364
|
|
|
321
|
-
const
|
|
322
|
-
|
|
365
|
+
const read = <T>(el: Signal<T> | Computed<T>): T => {
|
|
366
|
+
if (context) {
|
|
367
|
+
link(el, context);
|
|
323
368
|
|
|
324
|
-
|
|
325
|
-
|
|
369
|
+
if ('fn' in el) {
|
|
370
|
+
let height = el.height;
|
|
326
371
|
|
|
327
|
-
|
|
372
|
+
if (height >= context.height) {
|
|
373
|
+
context.height = height + 1;
|
|
374
|
+
}
|
|
328
375
|
|
|
329
|
-
|
|
376
|
+
if (
|
|
377
|
+
height >= minDirty ||
|
|
378
|
+
el.state & (STATE_DIRTY | STATE_CHECK)
|
|
379
|
+
) {
|
|
380
|
+
markHeap();
|
|
381
|
+
update(el);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return el.value;
|
|
330
387
|
};
|
|
331
388
|
|
|
332
|
-
const root = <T>(fn:
|
|
333
|
-
let
|
|
334
|
-
s = scope;
|
|
389
|
+
const root = <T>(fn: () => T) => {
|
|
390
|
+
let c = context;
|
|
335
391
|
|
|
336
|
-
|
|
337
|
-
if (o?.type === EFFECT) {
|
|
338
|
-
scope = o.root;
|
|
339
|
-
}
|
|
392
|
+
context = null;
|
|
340
393
|
|
|
341
|
-
|
|
342
|
-
throw new Error('@esportsplus/reactivity: `root` cannot be created without a task scheduler');
|
|
343
|
-
}
|
|
394
|
+
let value = fn();
|
|
344
395
|
|
|
345
|
-
|
|
346
|
-
}
|
|
396
|
+
context = c;
|
|
347
397
|
|
|
348
|
-
|
|
398
|
+
return value;
|
|
399
|
+
};
|
|
349
400
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
401
|
+
const signal = <T>(value: T): Signal<T> => {
|
|
402
|
+
return {
|
|
403
|
+
[REACTIVE]: true,
|
|
404
|
+
subs: null,
|
|
405
|
+
subsTail: null,
|
|
406
|
+
value,
|
|
407
|
+
};
|
|
408
|
+
};
|
|
353
409
|
|
|
354
|
-
|
|
410
|
+
signal.set = (el: Signal<unknown>, v: unknown) => {
|
|
411
|
+
if (el.value === v) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
355
414
|
|
|
356
|
-
|
|
357
|
-
scope = s;
|
|
415
|
+
el.value = v;
|
|
358
416
|
|
|
359
|
-
|
|
417
|
+
for (let link = el.subs; link !== null; link = link.nextSub) {
|
|
418
|
+
markedHeap = false;
|
|
419
|
+
insertIntoHeap(link.sub);
|
|
420
|
+
}
|
|
360
421
|
};
|
|
361
422
|
|
|
362
|
-
const
|
|
363
|
-
|
|
423
|
+
const stabilize = () => {
|
|
424
|
+
for (minDirty = 0; minDirty <= maxDirty; minDirty++) {
|
|
425
|
+
let el = dirtyHeap[minDirty];
|
|
364
426
|
|
|
365
|
-
|
|
427
|
+
dirtyHeap[minDirty] = undefined;
|
|
366
428
|
|
|
367
|
-
|
|
429
|
+
while (el !== undefined) {
|
|
430
|
+
let next = el.nextHeap;
|
|
431
|
+
|
|
432
|
+
recompute(el, false);
|
|
433
|
+
|
|
434
|
+
el = next;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
368
437
|
};
|
|
369
438
|
|
|
370
439
|
|
|
371
|
-
export {
|
|
372
|
-
|
|
440
|
+
export {
|
|
441
|
+
computed,
|
|
442
|
+
dispose,
|
|
443
|
+
isComputed, isReactive, isSignal,
|
|
444
|
+
oncleanup,
|
|
445
|
+
read, root,
|
|
446
|
+
signal, stabilize
|
|
447
|
+
};
|