2023-11-08 20:31:03 +00:00
|
|
|
import { ReadableStream, TransformStream } from "stream/web";
|
2020-04-14 23:40:00 +00:00
|
|
|
|
2024-02-17 03:57:21 +00:00
|
|
|
export async function asyncIteratorToArray<T>(iterator: AsyncIterable<T>): Promise<Array<T>> {
|
2023-10-02 13:01:55 +00:00
|
|
|
const result: T[] = [];
|
|
|
|
for await (const it of iterator) {
|
|
|
|
result.push(it);
|
|
|
|
}
|
|
|
|
return result;
|
2020-04-14 23:40:00 +00:00
|
|
|
}
|
2020-12-24 04:57:46 +00:00
|
|
|
|
2023-10-02 13:01:55 +00:00
|
|
|
export async function* arrayToAsyncIterator<T>(array: T[]): AsyncGenerator<T, void, void> {
|
|
|
|
for (const it of array) {
|
|
|
|
yield it;
|
|
|
|
}
|
2020-12-24 04:57:46 +00:00
|
|
|
}
|
|
|
|
|
2023-10-02 13:01:55 +00:00
|
|
|
export function asyncIteratorToStream<T>(iterator: AsyncGenerator<T, void, void>): ReadableStream<T> {
|
|
|
|
return new ReadableStream<T>({
|
|
|
|
async pull(controller) {
|
|
|
|
const { value, done } = await iterator.next();
|
|
|
|
if (done) {
|
|
|
|
controller.close();
|
|
|
|
} else {
|
|
|
|
controller.enqueue(value);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
2020-12-24 04:57:46 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 20:31:03 +00:00
|
|
|
export function streamPromiseToStream<T>(streamPromise: Promise<ReadableStream<T>>): ReadableStream<T> {
|
|
|
|
const transform = new TransformStream({
|
|
|
|
async start() {
|
|
|
|
const stream = await streamPromise;
|
2024-01-22 03:40:13 +00:00
|
|
|
stream.pipeTo(transform.writable).catch(() => {}); // Catch error to avoid unhandled rejection, see https://github.com/nodejs/node/issues/50707
|
2023-11-08 20:31:03 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return transform.readable;
|
|
|
|
}
|
|
|
|
|
2023-10-06 23:13:51 +00:00
|
|
|
export function jsonStream(template: any, data: Record<string, AsyncGenerator<any, any, void> | Promise<any> | any | (() => AsyncGenerator<any, any, void> | Promise<any> | any)>): ReadableStream<string> {
|
|
|
|
return asyncIteratorToStream((async function*() {
|
|
|
|
let lastIndent = '';
|
2020-12-24 04:57:46 +00:00
|
|
|
|
2023-10-06 23:13:51 +00:00
|
|
|
const parts = JSON.stringify(template, undefined, "\t").split(/"%([a-zA-Z0-9-_]+)%"/);
|
|
|
|
for (let i = 0; i < parts.length; i++) {
|
|
|
|
const part = parts[i];
|
2020-12-24 04:57:46 +00:00
|
|
|
|
2023-10-06 23:13:51 +00:00
|
|
|
if (i % 2 == 0) {
|
|
|
|
const lastLineBreak = part.lastIndexOf('\n');
|
|
|
|
if (lastLineBreak != -1)
|
|
|
|
lastIndent = part.slice(lastLineBreak + 1).match(/^(\t*)/)![1];
|
2020-12-24 04:57:46 +00:00
|
|
|
|
2023-10-06 23:13:51 +00:00
|
|
|
yield part;
|
|
|
|
} else {
|
|
|
|
const value = await (typeof data[part] === 'function' ? data[part]() : data[part]);
|
|
|
|
|
|
|
|
if (typeof value === 'object' && value && Symbol.asyncIterator in value) {
|
|
|
|
let first = true;
|
|
|
|
const indent = lastIndent + "\t";
|
|
|
|
yield '[\n';
|
|
|
|
for await (const obj of value) {
|
|
|
|
const prefix = first ? '' : ',\n';
|
|
|
|
first = false;
|
|
|
|
yield prefix + JSON.stringify(obj, undefined, "\t").replace(/^/gm, indent);
|
|
|
|
}
|
|
|
|
yield '\n' + lastIndent + ']';
|
|
|
|
} else {
|
|
|
|
const indent = lastIndent;
|
|
|
|
yield JSON.stringify(value, undefined, "\t").replace(/\n/g, '\n' + indent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})());
|
2020-12-24 04:57:46 +00:00
|
|
|
}
|