export function streamiterator(stream: PromiseLike
): AsyncGenerator
export function streamiterator(stream: Body): AsyncGenerator
export function streamiterator(stream: ReadableStream): AsyncGenerator
export function streamiterator(stream: ReadableStreamDefaultReader): AsyncGenerator
export function streamiterator(stream: Blob): AsyncGenerator
export function streamiterator(stream: AsyncIterable): AsyncGenerator
export function streamiterator(stream: Iterable | T>): AsyncGenerator
export async function* streamiterator(
stream:
| PromiseLike
| Body
| ReadableStream
| ReadableStreamDefaultReader
| Blob
| Iterable | T>
| AsyncIterable,
): AsyncGenerator {
const resolved = await stream
const reader = getStream(resolved) ?? getStream((resolved as Body)?.body)
if (!reader) {
throw new TypeError("argument is not a ReadableStream")
} else if (isIterable(reader)) {
// do not use async iteration over sync iterator
// https://github.com/tc39/ecma262/issues/1849
for (const chunk of reader) yield chunk
} else if (isAsyncIterable(reader)) {
for await (const chunk of reader) yield chunk
} else if (isReader(reader)) {
let needClose
try {
for (;;) {
needClose = true
const x = await reader.read()
if (x.done) break
needClose = false
yield x.value
}
} finally {
if (!needClose) await reader.cancel?.()
}
} else {
throw new TypeError("argument is not a ReadableStream")
}
}
function getStream(value: unknown): Iterable | AsyncIterable | ReadableStreamDefaultReader | undefined {
if (!value) {
return undefined
}
if (isReadable(value)) {
return value
}
if (isReadableStream(value)) {
return value.getReader()
}
if (isBlob(value)) {
return value.stream()?.getReader?.()
}
return undefined
}
function isIterable(value: unknown): value is Iterable {
return typeof (value as Iterable)[Symbol.iterator] === "function"
}
function isAsyncIterable(value: unknown): value is AsyncIterable {
return typeof (value as AsyncIterable)[Symbol.asyncIterator] === "function"
}
function isReadableStream(value: unknown): value is ReadableStream {
return typeof (value as ReadableStream).getReader === "function"
}
function isBlob(value: unknown): value is Blob {
return typeof (value as Blob).stream === "function"
}
function isReader(value: unknown): value is ReadableStreamDefaultReader {
return typeof (value as ReadableStreamDefaultReader).read === "function"
}
function isReadable(value: unknown): value is Iterable | AsyncIterable | ReadableStreamDefaultReader {
return isIterable(value) || isAsyncIterable(value) || isReader(value)
}