import type { MaybePromiseLike } from "@yume-chan/async"; import { isPromiseLike } from "@yume-chan/async"; function advance( iterator: Iterator, next: unknown, ): MaybePromiseLike { while (true) { const { done, value } = iterator.next(next); if (done) { return value; } if (isPromiseLike(value)) { return value.then( (value) => advance(iterator, { resolved: value }), (error: unknown) => advance(iterator, { error }), ); } next = value; } } export type BipedalGenerator = ( this: This, then: (value: MaybePromiseLike) => Iterable, ...args: A ) => Generator; /* #__NO_SIDE_EFFECTS__ */ export function bipedal( fn: BipedalGenerator, bindThis?: This, ): { (this: This, ...args: A): MaybePromiseLike } { function result(this: This, ...args: A): MaybePromiseLike { const iterator = fn.call( this, function* ( value: MaybePromiseLike, ): Generator< PromiseLike, U, { resolved: U } | { error: unknown } > { if (isPromiseLike(value)) { const result = yield value; if ("resolved" in result) { return result.resolved; } else { throw result.error; } } return value; }, ...args, ) as never; return advance(iterator, undefined); } if (bindThis) { return result.bind(bindThis); } else { return result; } }