UNPKG

univ-conv

Version:

The universal binary and text converter

195 lines 7.05 kB
import { AbstractConverter, _ } from "./AbstractConverter"; import { EMPTY_UINT8_ARRAY, getStartEnd, } from "./core"; import { closeStream, fileURLToReadable, handleReadable, handleReadableStream, hasStreamOnBlob, isBrowser, isReadableStream, } from "./Environment"; function createReadableStream(u8) { return new ReadableStream({ start: (controller) => { controller.enqueue(u8); }, }); } export function createPartialReadableStream(source, startEnd) { const reader = source.getReader(); const start = startEnd.start; const end = startEnd.end ?? Number.MAX_SAFE_INTEGER; return new ReadableStream({ start: async (controller) => { let iStart = 0; let res; do { res = await reader.read(); const value = res.value; if (value) { const u8 = value; const length = u8.byteLength; const iEnd = iStart + length; const u8End = (iEnd < end ? iEnd : end) - iStart; let chunk; if (iStart <= start && start < iEnd) { chunk = u8.subarray(start - iStart, u8End); } else if (start < iStart && iStart < end) { chunk = u8.subarray(0, u8End); } if (chunk) { controller.enqueue(chunk); } iStart += length; } } while (!res.done && iStart < end); controller.close(); reader.releaseLock(); closeStream(source); }, cancel: (e) => { reader.releaseLock(); closeStream(source, e); }, }); } function createReadableStreamOfReader(readable, options) { const startEnd = getStartEnd(options); const start = startEnd.start; const end = startEnd.end ?? Number.MAX_SAFE_INTEGER; const bufferSize = options.bufferSize; const converter = _()._of("uint8array"); let iStart = 0; return new ReadableStream({ start: async (controller) => { await handleReadable(readable, async (value) => { const u8 = await converter.from(value, { bufferSize }); const size = u8.byteLength; const iEnd = iStart + size; const u8End = (iEnd < end ? iEnd : end) - iStart; let chunk; if (iStart <= start && start < iEnd) { chunk = u8.subarray(start - iStart, u8End); } else if (start < iStart && iStart < end) { chunk = u8.subarray(0, u8End); } if (chunk) { controller.enqueue(chunk); } iStart += size; return iStart < end; }); }, cancel: (err) => { readable.destroy(err); }, }); } export class ReadableStreamConverter extends AbstractConverter { constructor() { super(...arguments); this.type = "readablestream"; } empty() { return new ReadableStream({ start: (converter) => { converter.enqueue(EMPTY_UINT8_ARRAY); converter.close(); }, }); } is(input) { return isReadableStream(input); } async _from(input, options) { if (typeof input === "string" && options.inputStringType === "url") { if (input.startsWith("http:") || input.startsWith("https:")) { const resp = await fetch(input); if (_().is("readable", resp.body, options)) { input = resp.body; } else { input = resp.body; } } else if (input.startsWith("file:") && fileURLToReadable) { input = await fileURLToReadable(input); } } if (_().is("readable", input, options)) { return createReadableStreamOfReader(input, options); } if (hasStreamOnBlob) { if (_().is("blob", input, options)) { input = input.stream(); } else { const blob = await _().convert("blob", input, options); input = blob.stream(); } } if (this.is(input)) { return createPartialReadableStream(input, await this._getStartEnd(input, options)); } const u8 = await _().convert("uint8array", input, options); const { start, end } = getStartEnd(options, u8.byteLength); return createReadableStream(u8.slice(start, end)); } _getStartEnd(_input, options) { return Promise.resolve(getStartEnd(options)); } _isEmpty() { return false; } _merge(streams) { const end = streams.length; const process = (controller, i) => { if (i < end) { const stream = streams[i]; handleReadableStream(stream, (chunk) => { controller.enqueue(chunk); return Promise.resolve(true); }) .then(() => process(controller, ++i)) .catch((e) => { controller.error(e); for (let j = i; j < end; j++) { const s = streams[j]; closeStream(s); } }); } else { controller.close(); } }; return Promise.resolve(new ReadableStream({ start: (converter) => { process(converter, 0); }, })); } _size() { throw new Error("Cannot get size of ReadableStream"); } async _toArrayBuffer(input, options) { const u8 = await this._toUint8Array(input, options); return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength); } async _toBase64(input, options) { const opts = { bufferSize: options.bufferSize }; const t = isBrowser ? "blob" : "uint8array"; const convertd = await _().convert(t, input, opts); return await _()._of(t).toBase64(convertd, options); } async _toText(input, options) { const opts = { bufferSize: options.bufferSize }; const t = isBrowser ? "blob" : "uint8array"; const convertd = await _().convert(t, input, opts); return await _()._of(t).toText(convertd, options); } async _toUint8Array(input, options) { const chunks = []; await handleReadableStream(input, async (chunk) => { chunks.push(chunk); return Promise.resolve(true); }); return await _()._of("uint8array").merge(chunks, options); } } //# sourceMappingURL=ReadableStreamConverter.js.map