UNPKG

@loaders.gl/core

Version:

The core API for working with loaders.gl loaders and writers

126 lines (125 loc) 4.58 kB
// loaders.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import { concatenateArrayBuffersAsync } from '@loaders.gl/loader-utils'; import { isResponse, isReadableStream, isAsyncIterable, isIterable, isIterator, isBlob, isBuffer } from "../../javascript-utils/is-type.js"; import { makeIterator } from "../../iterators/make-iterator/make-iterator.js"; import { checkResponse, makeResponse } from "../utils/response-utils.js"; const ERR_DATA = 'Cannot convert supplied data type'; // eslint-disable-next-line complexity export function getArrayBufferOrStringFromDataSync(data, loader, options) { if (loader.text && typeof data === 'string') { return data; } if (isBuffer(data)) { // @ts-ignore data = data.buffer; } if (data instanceof ArrayBuffer) { const arrayBuffer = data; if (loader.text && !loader.binary) { const textDecoder = new TextDecoder('utf8'); return textDecoder.decode(arrayBuffer); } return arrayBuffer; } // We may need to handle offsets if (ArrayBuffer.isView(data)) { // TextDecoder is invoked on typed arrays and will handle offsets if (loader.text && !loader.binary) { const textDecoder = new TextDecoder('utf8'); return textDecoder.decode(data); } let arrayBuffer = data.buffer; // Since we are returning the underlying arrayBuffer, we must create a new copy // if this typed array / Buffer is a partial view into the ArryayBuffer // TODO - this is a potentially unnecessary copy const byteLength = data.byteLength || data.length; if (data.byteOffset !== 0 || byteLength !== arrayBuffer.byteLength) { // console.warn(`loaders.gl copying arraybuffer of length ${byteLength}`); arrayBuffer = arrayBuffer.slice(data.byteOffset, data.byteOffset + byteLength); } return arrayBuffer; } throw new Error(ERR_DATA); } // Convert async iterator to a promise export async function getArrayBufferOrStringFromData(data, loader, options) { const isArrayBuffer = data instanceof ArrayBuffer || ArrayBuffer.isView(data); if (typeof data === 'string' || isArrayBuffer) { return getArrayBufferOrStringFromDataSync(data, loader, options); } // Blobs and files are FileReader compatible if (isBlob(data)) { data = await makeResponse(data); } if (isResponse(data)) { const response = data; await checkResponse(response); return loader.binary ? await response.arrayBuffer() : await response.text(); } if (isReadableStream(data)) { // @ts-expect-error TS2559 options type data = makeIterator(data, options); } if (isIterable(data) || isAsyncIterable(data)) { // Assume arrayBuffer iterator - attempt to concatenate return concatenateArrayBuffersAsync(data); } throw new Error(ERR_DATA); } export async function getAsyncIterableFromData(data, options) { if (isIterator(data)) { return data; } if (isResponse(data)) { const response = data; // Note Since this function is not async, we currently can't load error message, just status await checkResponse(response); // TODO - bug in polyfill, body can be a Promise under Node.js // eslint-disable-next-line @typescript-eslint/await-thenable const body = await response.body; // TODO - body can be null? return makeIterator(body, options); } if (isBlob(data) || isReadableStream(data)) { return makeIterator(data, options); } if (isAsyncIterable(data)) { return data; } return getIterableFromData(data); } export async function getReadableStream(data) { if (isReadableStream(data)) { return data; } if (isResponse(data)) { // @ts-ignore return data.body; } const response = await makeResponse(data); // @ts-ignore return response.body; } // HELPERS function getIterableFromData(data) { // generate an iterator that emits a single chunk if (ArrayBuffer.isView(data)) { return (function* oneChunk() { yield data.buffer; })(); } if (data instanceof ArrayBuffer) { return (function* oneChunk() { yield data; })(); } if (isIterator(data)) { return data; } if (isIterable(data)) { return data[Symbol.iterator](); } throw new Error(ERR_DATA); }