@esportsplus/reactivity 0.34.0 → 0.36.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 +9 -7
- package/bench/reactive/array.bench.ts +17 -17
- package/build/compiler/array.d.ts +2 -2
- package/build/compiler/array.js +10 -52
- package/build/compiler/constants.d.ts +4 -4
- package/build/compiler/constants.js +20 -4
- package/build/compiler/index.js +25 -38
- package/build/compiler/object.d.ts +2 -2
- package/build/compiler/object.js +5 -16
- package/build/compiler/primitives.d.ts +6 -2
- package/build/compiler/primitives.js +31 -38
- package/build/compiler/types.d.ts +3 -1
- package/build/constants.d.ts +2 -2
- package/build/constants.js +2 -2
- package/build/reactive/array.d.ts +1 -1
- package/build/reactive/array.js +26 -15
- package/build/reactive/index.js +5 -14
- package/build/reactive/object.js +1 -1
- package/build/system.d.ts +1 -4
- package/build/system.js +105 -83
- package/build/types.d.ts +2 -7
- package/package.json +5 -5
- package/pnpm-workspace.yaml +2 -1
- package/src/compiler/array.ts +12 -62
- package/src/compiler/constants.ts +21 -5
- package/src/compiler/index.ts +38 -69
- package/src/compiler/object.ts +7 -24
- package/src/compiler/primitives.ts +51 -49
- package/src/compiler/types.ts +4 -1
- package/src/constants.ts +4 -4
- package/src/reactive/array.ts +33 -17
- package/src/reactive/index.ts +5 -17
- package/src/reactive/object.ts +1 -1
- package/src/system.ts +138 -101
- package/src/types.ts +2 -9
- package/test/async-computed.test.ts +2 -2
- package/test/compiler/compiler.test.ts +38 -22
- package/test/effects.test.ts +37 -1
- package/test/lib/uncaught.ts +26 -0
- package/test/reactive/array.test.ts +169 -99
- package/test/reactive/nested.test.ts +14 -14
- package/test/reactive/objects.test.ts +1 -1
- package/test/reactive/reactive.test.ts +49 -0
- package/test/system.test.ts +130 -22
package/build/constants.js
CHANGED
|
@@ -3,11 +3,11 @@ const PACKAGE_NAME = '@esportsplus/reactivity';
|
|
|
3
3
|
const REACTIVE_ARRAY = Symbol('reactivity.reactive.array');
|
|
4
4
|
const REACTIVE_OBJECT = Symbol('reactivity.reactive.object');
|
|
5
5
|
const SIGNAL = Symbol('reactivity.signal');
|
|
6
|
+
const STABILIZER_DEFERRED = 4;
|
|
6
7
|
const STABILIZER_IDLE = 0;
|
|
7
8
|
const STABILIZER_RESCHEDULE = 1;
|
|
8
9
|
const STABILIZER_RUNNING = 2;
|
|
9
10
|
const STABILIZER_SCHEDULED = 3;
|
|
10
|
-
const STATE_NONE = 0;
|
|
11
11
|
const STATE_CHECK = 1 << 0;
|
|
12
12
|
const STATE_DIRTY = 1 << 1;
|
|
13
13
|
const STATE_RECOMPUTING = 1 << 2;
|
|
@@ -16,4 +16,4 @@ const STATE_COMPUTED = 1 << 4;
|
|
|
16
16
|
const STATE_ERROR = 1 << 5;
|
|
17
17
|
const STATE_EFFECT = 1 << 6;
|
|
18
18
|
const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
|
|
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,
|
|
19
|
+
export { COMPUTED, PACKAGE_NAME, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_DEFERRED, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NOTIFY_MASK, STATE_RECOMPUTING };
|
|
@@ -40,7 +40,7 @@ type Listeners<T> = {
|
|
|
40
40
|
declare class ReactiveArray<T> extends Array<T> {
|
|
41
41
|
private _length;
|
|
42
42
|
listeners: Listeners<T>;
|
|
43
|
-
constructor(
|
|
43
|
+
constructor(items?: readonly T[]);
|
|
44
44
|
static get [Symbol.species](): ArrayConstructor;
|
|
45
45
|
get $length(): number;
|
|
46
46
|
set $length(value: number);
|
package/build/reactive/array.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isArray } from '@esportsplus/utilities';
|
|
2
|
-
import { REACTIVE_ARRAY } from '../constants.js';
|
|
2
|
+
import { PACKAGE_NAME, REACTIVE_ARRAY } from '../constants.js';
|
|
3
3
|
import { read, signal, write } from '../system.js';
|
|
4
4
|
import { isReactiveObject } from './object.js';
|
|
5
5
|
function dispose(value) {
|
|
@@ -10,9 +10,13 @@ function dispose(value) {
|
|
|
10
10
|
class ReactiveArray extends Array {
|
|
11
11
|
_length;
|
|
12
12
|
listeners = {};
|
|
13
|
-
constructor(
|
|
14
|
-
super(
|
|
15
|
-
|
|
13
|
+
constructor(items) {
|
|
14
|
+
super();
|
|
15
|
+
let n = items ? items.length : 0;
|
|
16
|
+
for (let i = 0; i < n; i++) {
|
|
17
|
+
this[i] = items[i];
|
|
18
|
+
}
|
|
19
|
+
this._length = signal(n);
|
|
16
20
|
}
|
|
17
21
|
static get [Symbol.species]() {
|
|
18
22
|
return Array;
|
|
@@ -37,6 +41,7 @@ class ReactiveArray extends Array {
|
|
|
37
41
|
write(this._length, i + 1);
|
|
38
42
|
}
|
|
39
43
|
this.dispatch('set', { index: i, item: value });
|
|
44
|
+
dispose(prev);
|
|
40
45
|
}
|
|
41
46
|
clear() {
|
|
42
47
|
this.dispose();
|
|
@@ -69,7 +74,7 @@ class ReactiveArray extends Array {
|
|
|
69
74
|
if (!listeners) {
|
|
70
75
|
return;
|
|
71
76
|
}
|
|
72
|
-
let dirty = false;
|
|
77
|
+
let dirty = false, errors = null;
|
|
73
78
|
for (let i = 0, n = listeners.length; i < n; i++) {
|
|
74
79
|
let listener = listeners[i];
|
|
75
80
|
if (listener === null) {
|
|
@@ -82,9 +87,10 @@ class ReactiveArray extends Array {
|
|
|
82
87
|
listeners[i] = null;
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
|
-
catch {
|
|
90
|
+
catch (e) {
|
|
86
91
|
dirty = true;
|
|
87
92
|
listeners[i] = null;
|
|
93
|
+
(errors ??= []).push(e);
|
|
88
94
|
}
|
|
89
95
|
}
|
|
90
96
|
if (dirty) {
|
|
@@ -92,6 +98,14 @@ class ReactiveArray extends Array {
|
|
|
92
98
|
listeners.pop();
|
|
93
99
|
}
|
|
94
100
|
}
|
|
101
|
+
if (errors !== null) {
|
|
102
|
+
let error = errors.length === 1
|
|
103
|
+
? errors[0]
|
|
104
|
+
: new AggregateError(errors, `${PACKAGE_NAME}: dispatch produced multiple errors`);
|
|
105
|
+
queueMicrotask(() => {
|
|
106
|
+
throw error;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
dispose() {
|
|
97
111
|
while (this.length) {
|
|
@@ -169,20 +183,17 @@ class ReactiveArray extends Array {
|
|
|
169
183
|
super.sort(fn);
|
|
170
184
|
let buckets = new Map(), order = new Array(n);
|
|
171
185
|
for (let i = 0; i < n; i++) {
|
|
172
|
-
let value = before[i],
|
|
173
|
-
if (
|
|
174
|
-
buckets.set(value, [i]);
|
|
186
|
+
let value = before[i], bucket = buckets.get(value);
|
|
187
|
+
if (bucket === undefined) {
|
|
188
|
+
buckets.set(value, { indices: [i], next: 0 });
|
|
175
189
|
}
|
|
176
190
|
else {
|
|
177
|
-
|
|
191
|
+
bucket.indices.push(i);
|
|
178
192
|
}
|
|
179
193
|
}
|
|
180
194
|
for (let i = 0; i < n; i++) {
|
|
181
|
-
let
|
|
182
|
-
order[i] =
|
|
183
|
-
if (list.length > 1) {
|
|
184
|
-
list.pop();
|
|
185
|
-
}
|
|
195
|
+
let bucket = buckets.get(this[i]);
|
|
196
|
+
order[i] = bucket.indices[bucket.next++];
|
|
186
197
|
}
|
|
187
198
|
this.dispatch('sort', { order });
|
|
188
199
|
}
|
package/build/reactive/index.js
CHANGED
|
@@ -4,25 +4,16 @@ import { PACKAGE_NAME } from '../constants.js';
|
|
|
4
4
|
import { ReactiveArray } from './array.js';
|
|
5
5
|
import { ReactiveObject } from './object.js';
|
|
6
6
|
function reactive(input) {
|
|
7
|
-
let
|
|
8
|
-
let response;
|
|
7
|
+
let value = root(() => {
|
|
9
8
|
if (isObject(input)) {
|
|
10
|
-
|
|
9
|
+
return new ReactiveObject(input);
|
|
11
10
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
if (response) {
|
|
16
|
-
if (root.disposables) {
|
|
17
|
-
dispose = true;
|
|
18
|
-
}
|
|
19
|
-
return response;
|
|
11
|
+
if (isArray(input)) {
|
|
12
|
+
return new ReactiveArray(input);
|
|
20
13
|
}
|
|
21
14
|
throw new Error(`${PACKAGE_NAME}: 'reactive' received invalid input - ${JSON.stringify(input)}`);
|
|
22
15
|
});
|
|
23
|
-
|
|
24
|
-
onCleanup(() => value.dispose());
|
|
25
|
-
}
|
|
16
|
+
onCleanup(() => value.dispose());
|
|
26
17
|
return value;
|
|
27
18
|
}
|
|
28
19
|
export default reactive;
|
package/build/reactive/object.js
CHANGED
package/build/system.d.ts
CHANGED
|
@@ -12,10 +12,7 @@ declare const isSignal: (value: unknown) => value is Signal<unknown>;
|
|
|
12
12
|
declare const onCleanup: (fn: VoidFunction) => typeof fn;
|
|
13
13
|
declare const peek: <T>(node: Signal<T> | Computed<T>) => T;
|
|
14
14
|
declare const read: <T>(node: Signal<T> | Computed<T>) => T;
|
|
15
|
-
declare
|
|
16
|
-
declare namespace root {
|
|
17
|
-
var disposables: number;
|
|
18
|
-
}
|
|
15
|
+
declare const root: <T>(fn: ((dispose: VoidFunction) => T) | (() => T)) => T;
|
|
19
16
|
declare function signal<T>(value: T, equals?: ((a: T, b: T) => boolean) | null): Signal<T>;
|
|
20
17
|
declare namespace signal {
|
|
21
18
|
var selector: <T>(node: Signal<T>, key: T) => boolean;
|
package/build/system.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { PACKAGE_NAME, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NOTIFY_MASK, STATE_RECOMPUTING } from './constants.js';
|
|
1
|
+
import { PACKAGE_NAME, SIGNAL, STABILIZER_DEFERRED, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_COMPUTED, STATE_DIRTY, STATE_EFFECT, STATE_ERROR, STATE_IN_HEAP, STATE_NOTIFY_MASK, STATE_RECOMPUTING } from './constants.js';
|
|
2
2
|
import { isObject, isPromise } from '@esportsplus/utilities';
|
|
3
|
-
let asyncMeta = new WeakMap(), depth = 0, disposeHead = null, draining = false, heap = new Array(64), heap_i = 0, heap_n = 0, linkPoolHead = null, microtask = queueMicrotask, notified = false, observer = null, pendingHead = null, scope = null, stabilizer = STABILIZER_IDLE, version = 0, walkPoolHead = null, writes = 0;
|
|
3
|
+
let asyncMeta = new WeakMap(), depth = 0, disposeHead = null, draining = false, heap = new Array(64), heap_i = 0, heap_n = 0, linkPoolHead = null, microtask = queueMicrotask, notified = false, observer = null, pendingHead = null, pulled = null, puller = null, scope = null, stabilizer = STABILIZER_IDLE, version = 0, walkPoolHead = null, writes = 0;
|
|
4
|
+
function noop() {
|
|
5
|
+
}
|
|
4
6
|
function walkPop(walk) {
|
|
5
7
|
let prev = walk.prev;
|
|
6
8
|
walk.computed = null;
|
|
@@ -105,6 +107,9 @@ function insertIntoHeap(computed) {
|
|
|
105
107
|
heap.length = Math.max(height + 1, Math.ceil(heap.length * 2));
|
|
106
108
|
}
|
|
107
109
|
}
|
|
110
|
+
else if (height < heap_i) {
|
|
111
|
+
stabilizer = STABILIZER_RESCHEDULE;
|
|
112
|
+
}
|
|
108
113
|
}
|
|
109
114
|
function link(dep, sub) {
|
|
110
115
|
if (dep.rv === version) {
|
|
@@ -204,12 +209,24 @@ function pull(node) {
|
|
|
204
209
|
}
|
|
205
210
|
let o = observer;
|
|
206
211
|
observer = null;
|
|
212
|
+
pulled = node;
|
|
213
|
+
puller = o;
|
|
207
214
|
update(node);
|
|
208
215
|
observer = o;
|
|
216
|
+
pulled = null;
|
|
217
|
+
puller = null;
|
|
209
218
|
}
|
|
210
219
|
function propagate(computed) {
|
|
211
|
-
|
|
220
|
+
let c = computed.subs;
|
|
221
|
+
if (c === null) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
let skip = computed === pulled ? puller : null;
|
|
225
|
+
for (; c; c = c.nextSub) {
|
|
212
226
|
let s = c.sub, state = s.state;
|
|
227
|
+
if (s === skip) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
213
230
|
if (state & STATE_CHECK) {
|
|
214
231
|
s.state = state | STATE_DIRTY;
|
|
215
232
|
}
|
|
@@ -217,14 +234,10 @@ function propagate(computed) {
|
|
|
217
234
|
}
|
|
218
235
|
schedule();
|
|
219
236
|
}
|
|
220
|
-
function recompute(computed
|
|
221
|
-
if (
|
|
237
|
+
function recompute(computed) {
|
|
238
|
+
if (computed.state & STATE_IN_HEAP) {
|
|
222
239
|
deleteFromHeap(computed);
|
|
223
240
|
}
|
|
224
|
-
else {
|
|
225
|
-
computed.nextHeap = undefined;
|
|
226
|
-
computed.prevHeap = computed;
|
|
227
|
-
}
|
|
228
241
|
if (computed.cleanup) {
|
|
229
242
|
try {
|
|
230
243
|
cleanup(computed);
|
|
@@ -251,7 +264,7 @@ function recompute(computed, del) {
|
|
|
251
264
|
depth--;
|
|
252
265
|
version++;
|
|
253
266
|
observer = o;
|
|
254
|
-
computed.state = STATE_COMPUTED | flags;
|
|
267
|
+
computed.state = STATE_COMPUTED | flags | (computed.state & STATE_IN_HEAP);
|
|
255
268
|
computed.gv = w;
|
|
256
269
|
let depsTail = computed.depsTail, remove = depsTail ? depsTail.nextDep : computed.deps;
|
|
257
270
|
if (remove) {
|
|
@@ -287,46 +300,44 @@ function recompute(computed, del) {
|
|
|
287
300
|
propagate(computed);
|
|
288
301
|
}
|
|
289
302
|
}
|
|
303
|
+
if (!depth && stabilizer === STABILIZER_DEFERRED) {
|
|
304
|
+
stabilizer = STABILIZER_SCHEDULED;
|
|
305
|
+
microtask(stabilize);
|
|
306
|
+
}
|
|
290
307
|
}
|
|
291
308
|
function schedule() {
|
|
292
|
-
if (stabilizer
|
|
309
|
+
if (stabilizer !== STABILIZER_IDLE) {
|
|
293
310
|
return;
|
|
294
311
|
}
|
|
295
|
-
if (
|
|
312
|
+
if (depth) {
|
|
313
|
+
stabilizer = STABILIZER_DEFERRED;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
296
316
|
stabilizer = STABILIZER_SCHEDULED;
|
|
297
317
|
microtask(stabilize);
|
|
298
318
|
}
|
|
299
|
-
else if (stabilizer === STABILIZER_RUNNING) {
|
|
300
|
-
stabilizer = STABILIZER_RESCHEDULE;
|
|
301
|
-
}
|
|
302
319
|
}
|
|
303
320
|
function stabilize() {
|
|
304
321
|
let o = observer;
|
|
305
322
|
observer = null;
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
323
|
+
do {
|
|
324
|
+
stabilizer = STABILIZER_RUNNING;
|
|
325
|
+
for (heap_i = 0; heap_i <= heap_n; heap_i++) {
|
|
326
|
+
if (pendingHead !== null) {
|
|
327
|
+
drainPending();
|
|
328
|
+
}
|
|
329
|
+
let computed;
|
|
330
|
+
while ((computed = heap[heap_i]) !== undefined) {
|
|
331
|
+
recompute(computed);
|
|
332
|
+
}
|
|
310
333
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
while (computed !== undefined) {
|
|
314
|
-
let next = computed.nextHeap;
|
|
315
|
-
recompute(computed, false);
|
|
316
|
-
computed = next;
|
|
334
|
+
while (heap_n > 0 && heap[heap_n] === undefined) {
|
|
335
|
+
heap_n--;
|
|
317
336
|
}
|
|
318
|
-
|
|
319
|
-
while (
|
|
320
|
-
|
|
321
|
-
}
|
|
337
|
+
heap_i = 0;
|
|
338
|
+
} while (pendingHead !== null || stabilizer === STABILIZER_RESCHEDULE);
|
|
339
|
+
stabilizer = STABILIZER_IDLE;
|
|
322
340
|
observer = o;
|
|
323
|
-
if (stabilizer === STABILIZER_RESCHEDULE) {
|
|
324
|
-
stabilizer = STABILIZER_SCHEDULED;
|
|
325
|
-
microtask(stabilize);
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
stabilizer = STABILIZER_IDLE;
|
|
329
|
-
}
|
|
330
341
|
}
|
|
331
342
|
function unlink(link) {
|
|
332
343
|
let dep = link.dep, nextDep = link.nextDep, nextSub = link.nextSub, prevSub = link.prevSub;
|
|
@@ -369,7 +380,7 @@ function update(root) {
|
|
|
369
380
|
resuming = true;
|
|
370
381
|
}
|
|
371
382
|
else if (node.state & STATE_DIRTY) {
|
|
372
|
-
recompute(node
|
|
383
|
+
recompute(node);
|
|
373
384
|
node.state &= ~STATE_NOTIFY_MASK;
|
|
374
385
|
}
|
|
375
386
|
else {
|
|
@@ -394,7 +405,7 @@ function update(root) {
|
|
|
394
405
|
continue;
|
|
395
406
|
}
|
|
396
407
|
if (node.state & STATE_DIRTY) {
|
|
397
|
-
recompute(node
|
|
408
|
+
recompute(node);
|
|
398
409
|
}
|
|
399
410
|
else {
|
|
400
411
|
node.gv = w;
|
|
@@ -414,18 +425,23 @@ function update(root) {
|
|
|
414
425
|
function makeAsyncComputed(factory) {
|
|
415
426
|
let error = signal(undefined), node = signal(undefined), pending = signal(false), v = 0;
|
|
416
427
|
let stop = effect(() => {
|
|
417
|
-
let
|
|
418
|
-
if (
|
|
428
|
+
let id = ++v, stale = () => {
|
|
429
|
+
if (pendingHead !== null) {
|
|
430
|
+
drainPending();
|
|
431
|
+
}
|
|
432
|
+
return id !== v || (factory.state & (STATE_IN_HEAP | STATE_NOTIFY_MASK)) !== 0;
|
|
433
|
+
}, fail = (e) => {
|
|
434
|
+
if (!stale()) {
|
|
419
435
|
write(error, e === undefined ? new Error('reactivity: async computed rejected with undefined') : e);
|
|
420
436
|
write(pending, false);
|
|
421
437
|
}
|
|
422
|
-
},
|
|
438
|
+
}, result = read(factory);
|
|
423
439
|
if (isPromise(result)) {
|
|
424
|
-
if (
|
|
440
|
+
if (!stale()) {
|
|
425
441
|
write(pending, true);
|
|
426
442
|
}
|
|
427
443
|
result.then((value) => {
|
|
428
|
-
if (
|
|
444
|
+
if (!stale()) {
|
|
429
445
|
write(error, undefined);
|
|
430
446
|
write(node, value);
|
|
431
447
|
write(pending, false);
|
|
@@ -438,7 +454,7 @@ function makeAsyncComputed(factory) {
|
|
|
438
454
|
it.return?.();
|
|
439
455
|
});
|
|
440
456
|
let step = (r) => {
|
|
441
|
-
if (
|
|
457
|
+
if (stale()) {
|
|
442
458
|
return;
|
|
443
459
|
}
|
|
444
460
|
if (!r.done) {
|
|
@@ -451,7 +467,7 @@ function makeAsyncComputed(factory) {
|
|
|
451
467
|
write(pending, false);
|
|
452
468
|
}
|
|
453
469
|
};
|
|
454
|
-
if (
|
|
470
|
+
if (!stale()) {
|
|
455
471
|
write(pending, true);
|
|
456
472
|
}
|
|
457
473
|
untrack(() => it.next()).then(step, fail);
|
|
@@ -475,33 +491,15 @@ function makeAsyncComputed(factory) {
|
|
|
475
491
|
return wrapper;
|
|
476
492
|
}
|
|
477
493
|
function makeComputed(fn, eager = false) {
|
|
478
|
-
let self =
|
|
479
|
-
cleanup: null,
|
|
480
|
-
deps: null,
|
|
481
|
-
depsTail: null,
|
|
482
|
-
disposal: null,
|
|
483
|
-
equals: null,
|
|
484
|
-
error: null,
|
|
485
|
-
fn: fn,
|
|
486
|
-
gv: 0,
|
|
487
|
-
height: 0,
|
|
488
|
-
nextHeap: undefined,
|
|
489
|
-
prevHeap: null,
|
|
490
|
-
rv: 0,
|
|
491
|
-
state: STATE_COMPUTED,
|
|
492
|
-
subs: null,
|
|
493
|
-
subsTail: null,
|
|
494
|
-
value: undefined,
|
|
495
|
-
};
|
|
496
|
-
self.prevHeap = self;
|
|
494
|
+
let self = makeNode(fn);
|
|
497
495
|
if (observer) {
|
|
498
496
|
if (observer.depsTail === null) {
|
|
499
497
|
self.height = observer.height;
|
|
500
|
-
recompute(self
|
|
498
|
+
recompute(self);
|
|
501
499
|
}
|
|
502
500
|
else if (eager) {
|
|
503
501
|
self.height = observer.height + 1;
|
|
504
|
-
recompute(self
|
|
502
|
+
recompute(self);
|
|
505
503
|
}
|
|
506
504
|
else {
|
|
507
505
|
self.height = observer.height + 1;
|
|
@@ -512,14 +510,36 @@ function makeComputed(fn, eager = false) {
|
|
|
512
510
|
onCleanup(() => dispose(self));
|
|
513
511
|
}
|
|
514
512
|
else {
|
|
515
|
-
recompute(self
|
|
516
|
-
root.disposables++;
|
|
513
|
+
recompute(self);
|
|
517
514
|
if (scope) {
|
|
518
515
|
onCleanup(() => dispose(self));
|
|
519
516
|
}
|
|
520
517
|
}
|
|
521
518
|
return self;
|
|
522
519
|
}
|
|
520
|
+
function makeNode(fn) {
|
|
521
|
+
let self = {
|
|
522
|
+
cleanup: null,
|
|
523
|
+
deps: null,
|
|
524
|
+
depsTail: null,
|
|
525
|
+
disposal: null,
|
|
526
|
+
equals: null,
|
|
527
|
+
error: null,
|
|
528
|
+
fn,
|
|
529
|
+
gv: 0,
|
|
530
|
+
height: 0,
|
|
531
|
+
nextHeap: undefined,
|
|
532
|
+
pending: null,
|
|
533
|
+
prevHeap: null,
|
|
534
|
+
rv: 0,
|
|
535
|
+
state: STATE_COMPUTED,
|
|
536
|
+
subs: null,
|
|
537
|
+
subsTail: null,
|
|
538
|
+
value: undefined,
|
|
539
|
+
};
|
|
540
|
+
self.prevHeap = self;
|
|
541
|
+
return self;
|
|
542
|
+
}
|
|
523
543
|
const batch = (fn) => {
|
|
524
544
|
depth++;
|
|
525
545
|
try {
|
|
@@ -527,8 +547,9 @@ const batch = (fn) => {
|
|
|
527
547
|
}
|
|
528
548
|
finally {
|
|
529
549
|
depth--;
|
|
530
|
-
if (!depth) {
|
|
531
|
-
|
|
550
|
+
if (!depth && stabilizer === STABILIZER_DEFERRED) {
|
|
551
|
+
stabilizer = STABILIZER_SCHEDULED;
|
|
552
|
+
microtask(stabilize);
|
|
532
553
|
}
|
|
533
554
|
}
|
|
534
555
|
};
|
|
@@ -610,7 +631,7 @@ const effect = (fn, apply) => {
|
|
|
610
631
|
};
|
|
611
632
|
};
|
|
612
633
|
const flush = () => {
|
|
613
|
-
|
|
634
|
+
if (stabilizer === STABILIZER_SCHEDULED) {
|
|
614
635
|
stabilize();
|
|
615
636
|
}
|
|
616
637
|
};
|
|
@@ -671,26 +692,27 @@ const read = (node) => {
|
|
|
671
692
|
return node.value;
|
|
672
693
|
};
|
|
673
694
|
const root = (fn) => {
|
|
674
|
-
let c,
|
|
695
|
+
let c, o = observer, s = scope, self = null, tracking = fn.length, value;
|
|
675
696
|
observer = null;
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
697
|
+
try {
|
|
698
|
+
if (tracking) {
|
|
699
|
+
scope = self = makeNode(noop);
|
|
700
|
+
value = fn(c = () => dispose(self));
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
scope = null;
|
|
704
|
+
value = fn();
|
|
705
|
+
}
|
|
680
706
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
707
|
+
finally {
|
|
708
|
+
observer = o;
|
|
709
|
+
scope = s;
|
|
684
710
|
}
|
|
685
|
-
observer = o;
|
|
686
|
-
root.disposables = d;
|
|
687
|
-
scope = s;
|
|
688
711
|
if (c) {
|
|
689
712
|
onCleanup(c);
|
|
690
713
|
}
|
|
691
714
|
return value;
|
|
692
715
|
};
|
|
693
|
-
root.disposables = 0;
|
|
694
716
|
const signal = (value, equals = null) => {
|
|
695
717
|
return {
|
|
696
718
|
equals: equals,
|
package/build/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ts } from '@esportsplus/typescript';
|
|
2
1
|
import { SIGNAL } from './constants.js';
|
|
3
2
|
import { ReactiveArray } from './reactive/index.js';
|
|
4
3
|
interface Computed<T> {
|
|
@@ -12,6 +11,7 @@ interface Computed<T> {
|
|
|
12
11
|
gv: number;
|
|
13
12
|
height: number;
|
|
14
13
|
nextHeap: Computed<unknown> | undefined;
|
|
14
|
+
pending: Signal<boolean> | null;
|
|
15
15
|
prevHeap: Computed<unknown>;
|
|
16
16
|
rv: number;
|
|
17
17
|
state: number;
|
|
@@ -56,9 +56,4 @@ type Signal<T> = {
|
|
|
56
56
|
type: typeof SIGNAL;
|
|
57
57
|
value: T;
|
|
58
58
|
};
|
|
59
|
-
|
|
60
|
-
changed: boolean;
|
|
61
|
-
code: string;
|
|
62
|
-
sourceFile: ts.SourceFile;
|
|
63
|
-
}
|
|
64
|
-
export type { Computed, ComputedResult, Link, Reactive, SelectorSignal, Settled, Signal, TransformResult };
|
|
59
|
+
export type { Computed, ComputedResult, Link, Reactive, SelectorSignal, Settled, Signal };
|
package/package.json
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
"@esportsplus/utilities": "^0.28.0"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"@esportsplus/typescript": "^0.
|
|
8
|
-
"@types/node": "^26.
|
|
9
|
-
"vite": "^8.
|
|
10
|
-
"vitest": "^4.1.
|
|
7
|
+
"@esportsplus/typescript": "^0.32.0",
|
|
8
|
+
"@types/node": "^26.4.1",
|
|
9
|
+
"vite": "^8.2.2",
|
|
10
|
+
"vitest": "^4.1.11"
|
|
11
11
|
},
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"type": "module",
|
|
38
38
|
"types": "build/index.d.ts",
|
|
39
|
-
"version": "0.
|
|
39
|
+
"version": "0.36.0",
|
|
40
40
|
"scripts": {
|
|
41
41
|
"agent:bench": "vitest bench --run",
|
|
42
42
|
"agent:test": "tsc --noEmit && vitest run",
|
package/pnpm-workspace.yaml
CHANGED