-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
// This module "extends" ef.js with a helper function named `series`
import {
derived,
type Computation,
effect,
signal,
type ReactiveValue,
} from "../../src/ef.js";
export * from "../../src/ef.js";
function abortPromise(signal: AbortSignal) {
return new Promise<never>((_, reject) => {
signal.addEventListener(
"abort",
(e) => {
reject(e);
},
{ once: true },
);
});
}
/**
* Helper function to write async value with async generator function disguising
* pure async + algebraic effect function. This improves code readability by reducing
* code jumps (you can think in stream)
*/
export function series<T>(
initialValue: T,
f: (
ctx: Computation,
abortSignal: AbortSignal,
) => AsyncGenerator<T, void, undefined>,
): ReactiveValue<T> {
const $s = signal<T>(initialValue);
effect((ctx) => {
$s.set(initialValue);
const abortController = new AbortController();
const i = f(ctx, abortController.signal);
const consume = async () => {
try {
const iter = await Promise.race([
i.next(),
abortPromise(abortController.signal),
]);
if (iter.done) {
return;
}
$s.set(iter.value);
consume();
} catch {}
};
consume();
return () => {
abortController.abort();
};
});
return derived(() => $s.get());
}