π File detail
utils/generators.ts
π§© .tsπ 89 linesπΎ 2,156 bytesπ text
β Back to All Filesπ― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes lastX, returnValue, and toArray β mainly functions, hooks, or classes.
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
const NO_VALUE = Symbol('NO_VALUE') export async function lastX<A>(as: AsyncGenerator<A>): Promise<A> { let lastValue: A | typeof NO_VALUE = NO_VALUE for await (const a of as) {
π€ Exports (heuristic)
lastXreturnValuetoArray
π₯οΈ Source preview
const NO_VALUE = Symbol('NO_VALUE')
export async function lastX<A>(as: AsyncGenerator<A>): Promise<A> {
let lastValue: A | typeof NO_VALUE = NO_VALUE
for await (const a of as) {
lastValue = a
}
if (lastValue === NO_VALUE) {
throw new Error('No items in generator')
}
return lastValue
}
export async function returnValue<A>(
as: AsyncGenerator<unknown, A>,
): Promise<A> {
let e
do {
e = await as.next()
} while (!e.done)
return e.value
}
type QueuedGenerator<A> = {
done: boolean | void
value: A | void
generator: AsyncGenerator<A, void>
promise: Promise<QueuedGenerator<A>>
}
// Run all generators concurrently up to a concurrency cap, yielding values as they come in
export async function* all<A>(
generators: AsyncGenerator<A, void>[],
concurrencyCap = Infinity,
): AsyncGenerator<A, void> {
const next = (generator: AsyncGenerator<A, void>) => {
const promise: Promise<QueuedGenerator<A>> = generator
.next()
.then(({ done, value }) => ({
done,
value,
generator,
promise,
}))
return promise
}
const waiting = [...generators]
const promises = new Set<Promise<QueuedGenerator<A>>>()
// Start initial batch up to concurrency cap
while (promises.size < concurrencyCap && waiting.length > 0) {
const gen = waiting.shift()!
promises.add(next(gen))
}
while (promises.size > 0) {
const { done, value, generator, promise } = await Promise.race(promises)
promises.delete(promise)
if (!done) {
promises.add(next(generator))
// TODO: Clean this up
if (value !== undefined) {
yield value
}
} else if (waiting.length > 0) {
// Start a new generator when one finishes
const nextGen = waiting.shift()!
promises.add(next(nextGen))
}
}
}
export async function toArray<A>(
generator: AsyncGenerator<A, void>,
): Promise<A[]> {
const result: A[] = []
for await (const a of generator) {
result.push(a)
}
return result
}
export async function* fromArray<T>(values: T[]): AsyncGenerator<T, void> {
for (const value of values) {
yield value
}
}