@zeix/cause-effect 0.14.0 → 0.14.2
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 +68 -72
- package/biome.json +35 -0
- package/index.d.ts +6 -8
- package/index.dev.js +294 -0
- package/index.js +1 -1
- package/index.ts +26 -14
- package/package.json +5 -6
- package/src/computed.d.ts +11 -9
- package/src/computed.ts +138 -14
- package/src/effect.d.ts +7 -9
- package/src/effect.ts +43 -58
- package/src/scheduler.d.ts +15 -6
- package/src/scheduler.ts +39 -16
- package/src/signal.d.ts +5 -10
- package/src/signal.ts +10 -15
- package/src/state.d.ts +2 -1
- package/src/state.ts +1 -1
- package/src/util.d.ts +1 -5
- package/src/util.ts +3 -23
- package/test/batch.test.ts +13 -13
- package/test/benchmark.test.ts +79 -43
- package/test/computed.test.ts +76 -78
- package/test/effect.test.ts +24 -24
- package/test/state.test.ts +33 -33
- package/test/util/framework-types.ts +2 -2
- package/test/util/perf-tests.ts +2 -2
- package/test/util/reactive-framework.ts +1 -1
- package/src/memo.d.ts +0 -13
- package/src/memo.ts +0 -91
- package/src/task.d.ts +0 -17
- package/src/task.ts +0 -153
package/src/util.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
declare const isFunction: <T>(value: unknown) => value is (...args: unknown[]) => T;
|
|
2
|
-
declare const isAsyncFunction: <T>(value: unknown) => value is (...args: unknown[]) => Promise<T>;
|
|
3
2
|
declare const isObjectOfType: <T>(value: unknown, type: string) => value is T;
|
|
4
|
-
declare const isError: (value: unknown) => value is Error;
|
|
5
|
-
declare const isAbortError: (value: unknown) => value is DOMException;
|
|
6
|
-
declare const isPromise: <T>(value: unknown) => value is Promise<T>;
|
|
7
3
|
declare const toError: (reason: unknown) => Error;
|
|
8
4
|
declare class CircularDependencyError extends Error {
|
|
9
5
|
constructor(where: string);
|
|
10
6
|
}
|
|
11
|
-
export { isFunction,
|
|
7
|
+
export { isFunction, isObjectOfType, toError, CircularDependencyError };
|
package/src/util.ts
CHANGED
|
@@ -4,41 +4,21 @@ const isFunction = /*#__PURE__*/ <T>(
|
|
|
4
4
|
value: unknown,
|
|
5
5
|
): value is (...args: unknown[]) => T => typeof value === 'function'
|
|
6
6
|
|
|
7
|
-
const isAsyncFunction = /*#__PURE__*/ <T>(
|
|
8
|
-
value: unknown,
|
|
9
|
-
): value is (...args: unknown[]) => Promise<T> =>
|
|
10
|
-
isFunction(value) && value.constructor.name === 'AsyncFunction'
|
|
11
|
-
|
|
12
7
|
const isObjectOfType = /*#__PURE__*/ <T>(
|
|
13
8
|
value: unknown,
|
|
14
9
|
type: string,
|
|
15
10
|
): value is T => Object.prototype.toString.call(value) === `[object ${type}]`
|
|
16
11
|
|
|
17
|
-
const isError = /*#__PURE__*/ (value: unknown): value is Error =>
|
|
18
|
-
value instanceof Error
|
|
19
|
-
const isAbortError = /*#__PURE__*/ (value: unknown): value is DOMException =>
|
|
20
|
-
value instanceof DOMException && value.name === 'AbortError'
|
|
21
|
-
const isPromise = /*#__PURE__*/ <T>(value: unknown): value is Promise<T> =>
|
|
22
|
-
value instanceof Promise
|
|
23
12
|
const toError = (reason: unknown): Error =>
|
|
24
|
-
|
|
13
|
+
reason instanceof Error ? reason : Error(String(reason))
|
|
25
14
|
|
|
26
15
|
class CircularDependencyError extends Error {
|
|
27
16
|
constructor(where: string) {
|
|
28
17
|
super(`Circular dependency in ${where} detected`)
|
|
29
|
-
|
|
18
|
+
this.name = 'CircularDependencyError'
|
|
30
19
|
}
|
|
31
20
|
}
|
|
32
21
|
|
|
33
22
|
/* === Exports === */
|
|
34
23
|
|
|
35
|
-
export {
|
|
36
|
-
isFunction,
|
|
37
|
-
isAsyncFunction,
|
|
38
|
-
isObjectOfType,
|
|
39
|
-
isError,
|
|
40
|
-
isAbortError,
|
|
41
|
-
isPromise,
|
|
42
|
-
toError,
|
|
43
|
-
CircularDependencyError,
|
|
44
|
-
}
|
|
24
|
+
export { isFunction, isObjectOfType, toError, CircularDependencyError }
|
package/test/batch.test.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { describe,
|
|
2
|
-
import {
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { batch, computed, effect, state } from '../'
|
|
3
3
|
|
|
4
4
|
/* === Tests === */
|
|
5
5
|
|
|
6
|
-
describe('Batch',
|
|
7
|
-
test('should be triggered only once after repeated state change',
|
|
6
|
+
describe('Batch', () => {
|
|
7
|
+
test('should be triggered only once after repeated state change', () => {
|
|
8
8
|
const cause = state(0)
|
|
9
9
|
let result = 0
|
|
10
10
|
let count = 0
|
|
11
|
-
effect(() => {
|
|
11
|
+
effect((): undefined => {
|
|
12
12
|
result = cause.get()
|
|
13
13
|
count++
|
|
14
14
|
})
|
|
@@ -21,20 +21,20 @@ describe('Batch', function () {
|
|
|
21
21
|
expect(count).toBe(2) // + 1 for effect initialization
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
-
test('should be triggered only once when multiple signals are set',
|
|
24
|
+
test('should be triggered only once when multiple signals are set', () => {
|
|
25
25
|
const a = state(3)
|
|
26
26
|
const b = state(4)
|
|
27
27
|
const c = state(5)
|
|
28
|
-
const sum =
|
|
28
|
+
const sum = computed(() => a.get() + b.get() + c.get())
|
|
29
29
|
let result = 0
|
|
30
30
|
let count = 0
|
|
31
31
|
effect({
|
|
32
32
|
signals: [sum],
|
|
33
|
-
ok: res => {
|
|
33
|
+
ok: (res): undefined => {
|
|
34
34
|
result = res
|
|
35
35
|
count++
|
|
36
36
|
},
|
|
37
|
-
err: () => {},
|
|
37
|
+
err: (): undefined => {},
|
|
38
38
|
})
|
|
39
39
|
batch(() => {
|
|
40
40
|
a.set(6)
|
|
@@ -45,12 +45,12 @@ describe('Batch', function () {
|
|
|
45
45
|
expect(count).toBe(2) // + 1 for effect initialization
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
test('should prove example from README works',
|
|
48
|
+
test('should prove example from README works', () => {
|
|
49
49
|
// State: define an array of Signal<number>
|
|
50
50
|
const signals = [state(2), state(3), state(5)]
|
|
51
51
|
|
|
52
52
|
// Computed: derive a calculation ...
|
|
53
|
-
const sum =
|
|
53
|
+
const sum = computed(() => {
|
|
54
54
|
const v = signals.reduce((total, v) => total + v.get(), 0)
|
|
55
55
|
if (!Number.isFinite(v)) throw new Error('Invalid value')
|
|
56
56
|
return v
|
|
@@ -63,12 +63,12 @@ describe('Batch', function () {
|
|
|
63
63
|
// Effect: switch cases for the result
|
|
64
64
|
effect({
|
|
65
65
|
signals: [sum],
|
|
66
|
-
ok: v => {
|
|
66
|
+
ok: (v): undefined => {
|
|
67
67
|
result = v
|
|
68
68
|
okCount++
|
|
69
69
|
// console.log('Sum:', v)
|
|
70
70
|
},
|
|
71
|
-
err: _error => {
|
|
71
|
+
err: (_error): undefined => {
|
|
72
72
|
errCount++
|
|
73
73
|
// console.error('Error:', error)
|
|
74
74
|
},
|
package/test/benchmark.test.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import { describe,
|
|
2
|
-
import {
|
|
3
|
-
import { makeGraph, runGraph
|
|
4
|
-
import {
|
|
5
|
-
type ReactiveFramework,
|
|
6
|
-
type Computed,
|
|
7
|
-
} from './util/reactive-framework'
|
|
1
|
+
import { describe, expect, mock, test } from 'bun:test'
|
|
2
|
+
import { batch, computed, effect, state } from '../'
|
|
3
|
+
import { Counter, makeGraph, runGraph } from './util/dependency-graph'
|
|
4
|
+
import type { Computed, ReactiveFramework } from './util/reactive-framework'
|
|
8
5
|
|
|
9
6
|
/* === Utility Functions === */
|
|
10
7
|
|
|
@@ -25,13 +22,13 @@ const framework = {
|
|
|
25
22
|
}
|
|
26
23
|
},
|
|
27
24
|
computed: <T extends {}>(fn: () => T) => {
|
|
28
|
-
const c =
|
|
25
|
+
const c = computed(fn)
|
|
29
26
|
return {
|
|
30
27
|
read: () => c.get(),
|
|
31
28
|
}
|
|
32
29
|
},
|
|
33
|
-
effect: (fn: () =>
|
|
34
|
-
withBatch: (fn: () =>
|
|
30
|
+
effect: (fn: () => undefined) => effect(fn),
|
|
31
|
+
withBatch: (fn: () => undefined) => batch(fn),
|
|
35
32
|
withBuild: <T>(fn: () => T) => fn(),
|
|
36
33
|
}
|
|
37
34
|
const testPullCounts = true
|
|
@@ -53,7 +50,7 @@ function makeConfig() {
|
|
|
53
50
|
/** some basic tests to validate the reactive framework
|
|
54
51
|
* wrapper works and can run performance tests.
|
|
55
52
|
*/
|
|
56
|
-
describe('Basic test',
|
|
53
|
+
describe('Basic test', () => {
|
|
57
54
|
const name = framework.name
|
|
58
55
|
test(`${name} | simple dependency executes`, () => {
|
|
59
56
|
framework.withBuild(() => {
|
|
@@ -145,11 +142,11 @@ describe('Basic test', function () {
|
|
|
145
142
|
})
|
|
146
143
|
|
|
147
144
|
test(`${name} | effect`, () => {
|
|
148
|
-
const spy = _v => {}
|
|
145
|
+
const spy = (_v: number) => {}
|
|
149
146
|
const spyMock = mock(spy)
|
|
150
147
|
|
|
151
148
|
const s = framework.signal(2)
|
|
152
|
-
let c:
|
|
149
|
+
let c: { read: () => number } = { read: () => 0 }
|
|
153
150
|
|
|
154
151
|
framework.withBuild(() => {
|
|
155
152
|
c = framework.computed(() => s.read() * 2)
|
|
@@ -169,18 +166,22 @@ describe('Basic test', function () {
|
|
|
169
166
|
})
|
|
170
167
|
})
|
|
171
168
|
|
|
172
|
-
describe('Kairo tests',
|
|
169
|
+
describe('Kairo tests', () => {
|
|
173
170
|
const name = framework.name
|
|
174
171
|
|
|
175
172
|
test(`${name} | avoidable propagation`, () => {
|
|
176
173
|
const head = framework.signal(0)
|
|
177
174
|
const computed1 = framework.computed(() => head.read())
|
|
178
|
-
const computed2 = framework.computed(() =>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
182
|
-
const
|
|
183
|
-
|
|
175
|
+
const computed2 = framework.computed(() => {
|
|
176
|
+
computed1.read()
|
|
177
|
+
return 0
|
|
178
|
+
})
|
|
179
|
+
const computed3 = framework.computed(() => {
|
|
180
|
+
busy()
|
|
181
|
+
return computed2.read() + 1
|
|
182
|
+
}) // heavy computation
|
|
183
|
+
const computed4 = framework.computed(() => computed3.read() + 2)
|
|
184
|
+
const computed5 = framework.computed(() => computed4.read() + 3)
|
|
184
185
|
framework.effect(() => {
|
|
185
186
|
computed5.read()
|
|
186
187
|
busy() // heavy side effect
|
|
@@ -206,10 +207,10 @@ describe('Kairo tests', function () {
|
|
|
206
207
|
const callCounter = new Counter()
|
|
207
208
|
for (let i = 0; i < 50; i++) {
|
|
208
209
|
const current = framework.computed(() => {
|
|
209
|
-
return head.read()
|
|
210
|
+
return head.read() + i
|
|
210
211
|
})
|
|
211
212
|
const current2 = framework.computed(() => {
|
|
212
|
-
return current.read()
|
|
213
|
+
return current.read() + 1
|
|
213
214
|
})
|
|
214
215
|
framework.effect(() => {
|
|
215
216
|
current2.read()
|
|
@@ -267,7 +268,7 @@ describe('Kairo tests', function () {
|
|
|
267
268
|
}
|
|
268
269
|
})
|
|
269
270
|
|
|
270
|
-
test(`${name} | diamond`,
|
|
271
|
+
test(`${name} | diamond`, () => {
|
|
271
272
|
const width = 5
|
|
272
273
|
const head = framework.signal(0)
|
|
273
274
|
const current: { read(): number }[] = []
|
|
@@ -300,7 +301,7 @@ describe('Kairo tests', function () {
|
|
|
300
301
|
}
|
|
301
302
|
})
|
|
302
303
|
|
|
303
|
-
test(`${name} | mux`,
|
|
304
|
+
test(`${name} | mux`, () => {
|
|
304
305
|
const heads = new Array(100).fill(null).map(_ => framework.signal(0))
|
|
305
306
|
const mux = framework.computed(() => {
|
|
306
307
|
return Object.fromEntries(heads.map(h => h.read()).entries())
|
|
@@ -310,7 +311,9 @@ describe('Kairo tests', function () {
|
|
|
310
311
|
.map(x => framework.computed(() => x.read() + 1))
|
|
311
312
|
|
|
312
313
|
splited.forEach(x => {
|
|
313
|
-
framework.effect(() =>
|
|
314
|
+
framework.effect(() => {
|
|
315
|
+
x.read()
|
|
316
|
+
})
|
|
314
317
|
})
|
|
315
318
|
|
|
316
319
|
return () => {
|
|
@@ -329,7 +332,7 @@ describe('Kairo tests', function () {
|
|
|
329
332
|
}
|
|
330
333
|
})
|
|
331
334
|
|
|
332
|
-
test(`${name} | repeated observers`,
|
|
335
|
+
test(`${name} | repeated observers`, () => {
|
|
333
336
|
const size = 30
|
|
334
337
|
const head = framework.signal(0)
|
|
335
338
|
const current = framework.computed(() => {
|
|
@@ -362,7 +365,7 @@ describe('Kairo tests', function () {
|
|
|
362
365
|
}
|
|
363
366
|
})
|
|
364
367
|
|
|
365
|
-
test(`${name} | triangle`,
|
|
368
|
+
test(`${name} | triangle`, () => {
|
|
366
369
|
const width = 10
|
|
367
370
|
const head = framework.signal(0)
|
|
368
371
|
let current = head as { read: () => number }
|
|
@@ -407,7 +410,7 @@ describe('Kairo tests', function () {
|
|
|
407
410
|
}
|
|
408
411
|
})
|
|
409
412
|
|
|
410
|
-
test(`${name} | unstable`,
|
|
413
|
+
test(`${name} | unstable`, () => {
|
|
411
414
|
const head = framework.signal(0)
|
|
412
415
|
const double = framework.computed(() => head.read() * 2)
|
|
413
416
|
const inverse = framework.computed(() => -head.read())
|
|
@@ -442,10 +445,10 @@ describe('Kairo tests', function () {
|
|
|
442
445
|
})
|
|
443
446
|
})
|
|
444
447
|
|
|
445
|
-
describe('$mol_wire tests',
|
|
448
|
+
describe('$mol_wire tests', () => {
|
|
446
449
|
const name = framework.name
|
|
447
450
|
|
|
448
|
-
test(`${name} | $mol_wire benchmark`,
|
|
451
|
+
test(`${name} | $mol_wire benchmark`, () => {
|
|
449
452
|
const fib = (n: number) => {
|
|
450
453
|
if (n < 2) return 1
|
|
451
454
|
return fib(n - 1) + fib(n - 2)
|
|
@@ -454,7 +457,7 @@ describe('$mol_wire tests', function () {
|
|
|
454
457
|
return n + fib(16)
|
|
455
458
|
}
|
|
456
459
|
const numbers = Array.from({ length: 5 }, (_, i) => i)
|
|
457
|
-
const res: (() =>
|
|
460
|
+
const res: (() => unknown)[] = []
|
|
458
461
|
framework.withBuild(() => {
|
|
459
462
|
const A = framework.signal(0)
|
|
460
463
|
const B = framework.signal(0)
|
|
@@ -475,12 +478,24 @@ describe('$mol_wire tests', function () {
|
|
|
475
478
|
D.read()[4].x +
|
|
476
479
|
F.read(),
|
|
477
480
|
)
|
|
478
|
-
framework.effect(() =>
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
framework.effect(() =>
|
|
482
|
-
|
|
483
|
-
|
|
481
|
+
framework.effect(() => {
|
|
482
|
+
res.push(hard(G.read(), 'H'))
|
|
483
|
+
})
|
|
484
|
+
framework.effect(() => {
|
|
485
|
+
res.push(G.read())
|
|
486
|
+
}) // I
|
|
487
|
+
framework.effect(() => {
|
|
488
|
+
res.push(hard(F.read(), 'J'))
|
|
489
|
+
})
|
|
490
|
+
framework.effect(() => {
|
|
491
|
+
res[0] = hard(G.read(), 'H')
|
|
492
|
+
})
|
|
493
|
+
framework.effect(() => {
|
|
494
|
+
res[1] = G.read()
|
|
495
|
+
}) // I
|
|
496
|
+
framework.effect(() => {
|
|
497
|
+
res[2] = hard(F.read(), 'J')
|
|
498
|
+
})
|
|
484
499
|
|
|
485
500
|
return (i: number) => {
|
|
486
501
|
res.length = 0
|
|
@@ -499,10 +514,10 @@ describe('$mol_wire tests', function () {
|
|
|
499
514
|
})
|
|
500
515
|
})
|
|
501
516
|
|
|
502
|
-
describe('CellX tests',
|
|
517
|
+
describe('CellX tests', () => {
|
|
503
518
|
const name = framework.name
|
|
504
519
|
|
|
505
|
-
test(`${name} | CellX benchmark`,
|
|
520
|
+
test(`${name} | CellX benchmark`, () => {
|
|
506
521
|
const expected = {
|
|
507
522
|
10: [
|
|
508
523
|
[3, 6, 2, -2],
|
|
@@ -540,10 +555,31 @@ describe('CellX tests', function () {
|
|
|
540
555
|
prop4: framework.computed(() => m.prop3.read()),
|
|
541
556
|
}
|
|
542
557
|
|
|
543
|
-
framework.effect(() =>
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
framework.effect(() =>
|
|
558
|
+
framework.effect(() => {
|
|
559
|
+
s.prop1.read()
|
|
560
|
+
})
|
|
561
|
+
framework.effect(() => {
|
|
562
|
+
s.prop2.read()
|
|
563
|
+
})
|
|
564
|
+
framework.effect(() => {
|
|
565
|
+
s.prop3.read()
|
|
566
|
+
})
|
|
567
|
+
framework.effect(() => {
|
|
568
|
+
s.prop4.read()
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
framework.effect(() => {
|
|
572
|
+
s.prop1.read()
|
|
573
|
+
})
|
|
574
|
+
framework.effect(() => {
|
|
575
|
+
s.prop2.read()
|
|
576
|
+
})
|
|
577
|
+
framework.effect(() => {
|
|
578
|
+
s.prop3.read()
|
|
579
|
+
})
|
|
580
|
+
framework.effect(() => {
|
|
581
|
+
s.prop4.read()
|
|
582
|
+
})
|
|
547
583
|
|
|
548
584
|
s.prop1.read()
|
|
549
585
|
s.prop2.read()
|