UNPKG

@loaders.gl/json

Version:

Framework-independent loader for JSON and streaming JSON formats

125 lines (109 loc) 3.52 kB
// loaders.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import type {Loader, LoaderWithParser} from '@loaders.gl/loader-utils'; import type {BinaryFeatureCollection, GeoJSONTable, TableBatch} from '@loaders.gl/schema'; import type {JSONLoaderOptions} from './json-loader'; import {geojsonToBinary} from '@loaders.gl/gis'; // import {parseJSONSync} from './lib/parsers/parse-json'; import {parseJSONInBatches} from './lib/parsers/parse-json-in-batches'; // __VERSION__ is injected by babel-plugin-version-inline // @ts-ignore TS2304: Cannot find name '__VERSION__'. const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest'; export type GeoJSONLoaderOptions = JSONLoaderOptions & { geojson?: { shape?: 'geojson-table'; }; gis?: { format?: 'geojson' | 'binary'; }; }; /** * GeoJSON loader */ export const GeoJSONWorkerLoader = { dataType: null as unknown as GeoJSONTable, batchType: null as unknown as TableBatch, name: 'GeoJSON', id: 'geojson', module: 'geojson', version: VERSION, worker: true, extensions: ['geojson'], mimeTypes: ['application/geo+json'], category: 'geometry', text: true, options: { geojson: { shape: 'geojson-table' }, json: { shape: 'object-row-table', jsonpaths: ['$', '$.features'] }, gis: { format: 'geojson' } } } as const satisfies Loader<GeoJSONTable, TableBatch, GeoJSONLoaderOptions>; export const GeoJSONLoader = { ...GeoJSONWorkerLoader, // @ts-expect-error parse, // @ts-expect-error parseTextSync, parseInBatches } as const satisfies LoaderWithParser<GeoJSONTable, TableBatch, GeoJSONLoaderOptions>; async function parse( arrayBuffer: ArrayBuffer, options?: GeoJSONLoaderOptions ): Promise<GeoJSONTable | BinaryFeatureCollection> { return parseTextSync(new TextDecoder().decode(arrayBuffer), options); } function parseTextSync( text: string, options?: GeoJSONLoaderOptions ): GeoJSONTable | BinaryFeatureCollection { // Apps can call the parse method directly, we so apply default options here options = {...GeoJSONLoader.options, ...options}; options.geojson = {...GeoJSONLoader.options.geojson, ...options.geojson}; options.gis = options.gis || {}; let geojson; try { geojson = JSON.parse(text); } catch { geojson = {}; } const table: GeoJSONTable = { shape: 'geojson-table', // TODO - deduce schema from geojson // TODO check that parsed data is of type FeatureCollection type: 'FeatureCollection', features: geojson?.features || [] }; switch (options.gis.format) { case 'binary': return geojsonToBinary(table.features); default: return table; } } function parseInBatches(asyncIterator, options): AsyncIterable<TableBatch> { // Apps can call the parse method directly, we so apply default options here options = {...GeoJSONLoader.options, ...options}; options.json = {...GeoJSONLoader.options.json, ...options.json}; options.geojson = {...GeoJSONLoader.options.geojson, ...options.geojson}; const geojsonIterator = parseJSONInBatches(asyncIterator, options); switch (options.gis.format) { case 'binary': return makeBinaryGeometryIterator(geojsonIterator); default: return geojsonIterator as AsyncIterable<TableBatch>; } } async function* makeBinaryGeometryIterator(geojsonIterator) { for await (const batch of geojsonIterator) { batch.data = geojsonToBinary(batch.data); yield batch; } }