File size: 1,895 Bytes
21dd449 |
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 |
export async function* eventToGenerator<YieldType, ReturnType>(
cb: (
yieldCallback: (y: YieldType) => void,
returnCallback: (r: ReturnType) => void,
rejectCallack: (reason: unknown) => void
) => unknown
): AsyncGenerator<YieldType, ReturnType> {
const promises: Array<{
p: Promise<{ done: true; value: ReturnType } | { done: false; value: YieldType }>;
resolve: (value: { done: true; value: ReturnType } | { done: false; value: YieldType }) => void;
reject: (reason?: unknown) => void;
}> = [];
function addPromise() {
let resolve: (value: { done: true; value: ReturnType } | { done: false; value: YieldType }) => void;
let reject: (reason?: unknown) => void;
const p = new Promise<{ done: true; value: ReturnType } | { done: false; value: YieldType }>((res, rej) => {
resolve = res;
reject = rej;
});
// @ts-expect-error TS doesn't know that promise callback is executed immediately
promises.push({ p, resolve, reject });
}
addPromise();
const callbackRes = Promise.resolve()
.then(() =>
cb(
(y) => {
addPromise();
promises.at(-2)?.resolve({ done: false, value: y });
},
(r) => {
addPromise();
promises.at(-2)?.resolve({ done: true, value: r });
},
(err) => promises.shift()?.reject(err)
)
)
.catch((err) => promises.shift()?.reject(err));
while (1) {
const p = promises[0];
if (!p) {
throw new Error("Logic error in eventGenerator, promises should never be empty");
}
const result = await p.p;
promises.shift();
if (result.done) {
await callbackRes; // Clean up, may be removed in the future
// // Cleanup promises - shouldn't be needed due to above await
// for (const promise of promises) {
// promise.resolve(result);
// await promise.p;
// }
return result.value;
}
yield result.value;
}
// So TS doesn't complain
throw new Error("Unreachable");
}
|