js-hub / utils /eventToGenerator.ts
coyotte508's picture
coyotte508 HF Staff
Add 1 files
21dd449 verified
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");
}