-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathyieldify.ts
More file actions
44 lines (41 loc) · 1.37 KB
/
Copy pathyieldify.ts
File metadata and controls
44 lines (41 loc) · 1.37 KB
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
import { AsyncLocalStorage } from "node:async_hooks";
const generatorsStorage = new AsyncLocalStorage<Generator<unknown, any, any>>();
export function yieldifiedEnv(topLevelGenerator: () => Generator) {
const generator = topLevelGenerator();
generatorsStorage.run(generator, () => {
const { value } = generator.next();
consumePromise(value, generator);
});
}
function consumePromise(value: unknown, generator: Generator<unknown, any, any>) {
if (value instanceof Promise) {
value.then((v) => {
const { value: newValue } = generator.next(v);
if (newValue instanceof Promise) {
consumePromise(newValue, generator);
}
}).catch((e) => generator.throw(e));
}
}
// TODO: improve TS of this
export function yieldify(fn: (...args: any) => any) {
return (...args: any): any => {
fn(...args, (err: unknown, res: unknown): any => {
const generator = generatorsStorage.getStore();
if (assertGenerator(generator)) {
// @ts-ignore FIXME
if (err) generator.throw(err);
const { value } = generator.next(res);
consumePromise(value, generator);
}
});
};
}
function assertGenerator(iter: unknown): iter is Generator<unknown, any, any> {
if (!iter) {
throw new Error(
"`yieldify` must be used in context of generator function that is passed to `yieldifiedEnv`."
);
}
return true;
}