diff --git a/examples/benchmarks/package.json b/examples/benchmarks/package.json index 767f5664ee..5663dea98e 100644 --- a/examples/benchmarks/package.json +++ b/examples/benchmarks/package.json @@ -14,7 +14,7 @@ "@probe.gl/react-bench": "^4.0.2" }, "devDependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", "@babel/cli": "^7.0.0", "@babel/core": "^7.4.0", "@babel/preset-react": "^7.0.0", diff --git a/examples/experimental/3d-tiles-with-cesium/package.json b/examples/experimental/3d-tiles-with-cesium/package.json index 500cce9c01..e15ec136f5 100644 --- a/examples/experimental/3d-tiles-with-cesium/package.json +++ b/examples/experimental/3d-tiles-with-cesium/package.json @@ -9,8 +9,8 @@ "start-local": "webpack-dev-server --env.local --env.esnext --progress --hot --open" }, "dependencies": { - "@loaders.gl/3d-tiles": "4.0.0-alpha.23", - "@loaders.gl/core": "4.0.0-alpha.23", + "@loaders.gl/3d-tiles": "4.0.0-beta.3", + "@loaders.gl/core": "4.0.0-beta.3", "@math.gl/culling": "^4.0.0", "@math.gl/core": "^4.0.0" }, diff --git a/examples/experimental/3d-tiles-with-three.js/package.json b/examples/experimental/3d-tiles-with-three.js/package.json index b7fcd2aeac..1c8bab3e94 100644 --- a/examples/experimental/3d-tiles-with-three.js/package.json +++ b/examples/experimental/3d-tiles-with-three.js/package.json @@ -11,8 +11,8 @@ "start-local": "webpack-dev-server --env.local --progress --hot --open" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/3d-tiles": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/3d-tiles": "4.0.0-beta.3", "@math.gl/culling": "^4.0.0", "mapbox-gl": "^1.1.1", "three": "^0.106.2" diff --git a/examples/experimental/basis/package.json b/examples/experimental/basis/package.json index a1e1f3df94..4701f8e230 100644 --- a/examples/experimental/basis/package.json +++ b/examples/experimental/basis/package.json @@ -9,8 +9,8 @@ "start-local": "webpack-dev-server --env.local --progress --hot --open" }, "dependencies": { - "@loaders.gl/textures": "4.0.0-alpha.23", - "@loaders.gl/core": "^4.0.0-alpha.8" + "@loaders.gl/textures": "4.0.0-beta.3", + "@loaders.gl/core": "4.0.0-beta.3" }, "devDependencies": { "babel-plugin-inline-import": "^3.0.0", diff --git a/examples/experimental/gltf-with-deck.gl/package.json b/examples/experimental/gltf-with-deck.gl/package.json index ba0247e8a8..27007da04c 100644 --- a/examples/experimental/gltf-with-deck.gl/package.json +++ b/examples/experimental/gltf-with-deck.gl/package.json @@ -11,8 +11,8 @@ "@deck.gl/core": "^8.9.28", "@deck.gl/mesh-layers": "^8.9.28", "@deck.gl/react": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/gltf": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/gltf": "4.0.0-beta.3", "@luma.gl/constants": "^8.5.21", "@luma.gl/experimental": "^8.5.21", "maplibre-gl": "^2.4.0", diff --git a/examples/experimental/terrain/package.json b/examples/experimental/terrain/package.json index 49f6ff1084..d1e9643f4a 100644 --- a/examples/experimental/terrain/package.json +++ b/examples/experimental/terrain/package.json @@ -14,10 +14,10 @@ "@deck.gl/react": "^8.9.28", "@deck.gl/mesh-layers": "^8.9.28", "@deck.gl/layers": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/loader-utils": "4.0.0-alpha.23", - "@loaders.gl/mvt": "4.0.0-alpha.23", - "@loaders.gl/terrain": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/loader-utils": "4.0.0-beta.3", + "@loaders.gl/mvt": "4.0.0-beta.3", + "@loaders.gl/terrain": "4.0.0-beta.3", "maplibre-gl": "^2.4.0", "react": "^18.0.0", "react-dom": "^18.0.0", diff --git a/examples/get-started/bundle-with-nextjs/package.json b/examples/get-started/bundle-with-nextjs/package.json index 3e740b05e8..e5828b7471 100644 --- a/examples/get-started/bundle-with-nextjs/package.json +++ b/examples/get-started/bundle-with-nextjs/package.json @@ -8,8 +8,8 @@ "@deck.gl/geo-layers": "^8.9.28", "@deck.gl/layers": "^8.9.28", "@deck.gl/react": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/worker-utils": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/worker-utils": "4.0.0-beta.3", "@next/font": "13.1.6", "@types/node": "18.11.18", "@types/react": "18.0.27", diff --git a/examples/get-started/bundle-with-rollup/package.json b/examples/get-started/bundle-with-rollup/package.json index a9146d3c27..cc03ea0b2f 100644 --- a/examples/get-started/bundle-with-rollup/package.json +++ b/examples/get-started/bundle-with-rollup/package.json @@ -14,8 +14,8 @@ "serve": "serve public" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/obj": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/obj": "4.0.0-beta.3" }, "devDependencies": { "@rollup/plugin-alias": "^4.0.3", diff --git a/examples/get-started/bundle-with-vite/package.json b/examples/get-started/bundle-with-vite/package.json index d65db5702e..31f24bd98f 100644 --- a/examples/get-started/bundle-with-vite/package.json +++ b/examples/get-started/bundle-with-vite/package.json @@ -9,8 +9,8 @@ "serve": "vite preview" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/gltf": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/gltf": "4.0.0-beta.3" }, "devDependencies": { "typescript": "^5.0.4", diff --git a/examples/get-started/bundle-with-webpack-4/package.json b/examples/get-started/bundle-with-webpack-4/package.json index e4c4ba238a..f6a9f39e45 100644 --- a/examples/get-started/bundle-with-webpack-4/package.json +++ b/examples/get-started/bundle-with-webpack-4/package.json @@ -7,8 +7,8 @@ "start": "webpack-dev-server --progress --hot --open -d" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/obj": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/obj": "4.0.0-beta.3" }, "devDependencies": { "webpack": "^4.42.0", diff --git a/examples/get-started/bundle-with-webpack-5/package.json b/examples/get-started/bundle-with-webpack-5/package.json index 55f7397cbd..792229338f 100644 --- a/examples/get-started/bundle-with-webpack-5/package.json +++ b/examples/get-started/bundle-with-webpack-5/package.json @@ -9,8 +9,8 @@ "build": "webpack build" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/obj": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/obj": "4.0.0-beta.3" }, "devDependencies": { "html-webpack-plugin": "^5.5.0", diff --git a/examples/website/3d-tiles/package.json b/examples/website/3d-tiles/package.json index 05232e37a9..15bca85d5d 100644 --- a/examples/website/3d-tiles/package.json +++ b/examples/website/3d-tiles/package.json @@ -16,9 +16,9 @@ "@deck.gl/layers": "^8.9.28", "@deck.gl/mesh-layers": "^8.9.28", "@deck.gl/react": "^8.9.28", - "@loaders.gl/3d-tiles": "4.0.0-alpha.23", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/gltf": "4.0.0-alpha.23", + "@loaders.gl/3d-tiles": "4.0.0-beta.3", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/gltf": "4.0.0-beta.3", "@math.gl/core": "^4.0.0", "@math.gl/geospatial": "^4.0.0", "@probe.gl/stats-widget": "^4.0.2", diff --git a/examples/website/geospatial/package.json b/examples/website/geospatial/package.json index 8c1235211d..3b09704ee2 100644 --- a/examples/website/geospatial/package.json +++ b/examples/website/geospatial/package.json @@ -13,10 +13,10 @@ "@deck.gl/core": "^8.9.28", "@deck.gl/layers": "^8.9.28", "@deck.gl/react": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/flatgeobuf": "4.0.0-alpha.23", - "@loaders.gl/geopackage": "4.0.0-alpha.23", - "@loaders.gl/parquet": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/flatgeobuf": "4.0.0-beta.3", + "@loaders.gl/geopackage": "4.0.0-beta.3", + "@loaders.gl/parquet": "4.0.0-beta.3", "mapbox-gl": "npm:empty-npm-package@^1.0.0", "maplibre-gl": "^2.4.0", "react": "^18.0.0", diff --git a/examples/website/gltf/package.json b/examples/website/gltf/package.json index e2e5072158..abdeefbd6e 100644 --- a/examples/website/gltf/package.json +++ b/examples/website/gltf/package.json @@ -13,8 +13,8 @@ "serve": "vite preview" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/gltf": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/gltf": "4.0.0-beta.3", "@luma.gl/constants": "^8.5.21", "@luma.gl/core": "^8.5.21", "@luma.gl/experimental": "^8.5.21", diff --git a/examples/website/i3s-arcgis/package.json b/examples/website/i3s-arcgis/package.json index 5a5392874f..c58ca2568d 100644 --- a/examples/website/i3s-arcgis/package.json +++ b/examples/website/i3s-arcgis/package.json @@ -17,8 +17,8 @@ "@deck.gl/layers": "^8.9.28", "@deck.gl/mesh-layers": "^8.9.28", "@esri/react-arcgis": "^5.2.0", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/i3s": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/i3s": "4.0.0-beta.3", "react": "^18.0.0", "react-dom": "^18.0.0" }, diff --git a/examples/website/i3s/package.json b/examples/website/i3s/package.json index 8836ee76b8..3f5b39fba4 100644 --- a/examples/website/i3s/package.json +++ b/examples/website/i3s/package.json @@ -19,11 +19,11 @@ "@fortawesome/fontawesome-svg-core": "^1.2.34", "@fortawesome/free-solid-svg-icons": "^5.15.2", "@fortawesome/react-fontawesome": "^0.1.14", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/draco": "4.0.0-alpha.23", - "@loaders.gl/gltf": "4.0.0-alpha.23", - "@loaders.gl/i3s": "4.0.0-alpha.23", - "@loaders.gl/images": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/draco": "4.0.0-beta.3", + "@loaders.gl/gltf": "4.0.0-beta.3", + "@loaders.gl/i3s": "4.0.0-beta.3", + "@loaders.gl/images": "4.0.0-beta.3", "@luma.gl/constants": "^8.5.21", "@luma.gl/core": "^8.5.21", "@luma.gl/engine": "^8.5.21", diff --git a/examples/website/pointcloud/package.json b/examples/website/pointcloud/package.json index 3d2351c624..79dad06e6b 100644 --- a/examples/website/pointcloud/package.json +++ b/examples/website/pointcloud/package.json @@ -12,12 +12,12 @@ "@deck.gl/react": "^8.9.28", "@deck.gl/core": "^8.9.28", "@deck.gl/layers": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/draco": "4.0.0-alpha.23", - "@loaders.gl/las": "4.0.0-alpha.23", - "@loaders.gl/obj": "4.0.0-alpha.23", - "@loaders.gl/pcd": "4.0.0-alpha.23", - "@loaders.gl/ply": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/draco": "4.0.0-beta.3", + "@loaders.gl/las": "4.0.0-beta.3", + "@loaders.gl/obj": "4.0.0-beta.3", + "@loaders.gl/pcd": "4.0.0-beta.3", + "@loaders.gl/ply": "4.0.0-beta.3", "prop-types": "^15.7.2", "react": "^16.3.0", "react-dom": "^16.3.0", diff --git a/examples/website/textures/package.json b/examples/website/textures/package.json index d655ec8b29..6ea04e59ab 100644 --- a/examples/website/textures/package.json +++ b/examples/website/textures/package.json @@ -9,9 +9,9 @@ "serve": "vite preview" }, "dependencies": { - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/images": "4.0.0-alpha.23", - "@loaders.gl/textures": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/images": "4.0.0-beta.3", + "@loaders.gl/textures": "4.0.0-beta.3", "@luma.gl/core": "^8.5.21", "prop-types": "^15.7.2", "react": "^16.3.0", diff --git a/examples/website/tiles/package.json b/examples/website/tiles/package.json index b8a8671be9..7a578c7115 100644 --- a/examples/website/tiles/package.json +++ b/examples/website/tiles/package.json @@ -16,7 +16,7 @@ "@deck.gl/mesh-layers": "^8.9.28", "@deck.gl/extensions": "8.9.28", "@deck.gl/react": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.26", + "@loaders.gl/core": "4.0.0-beta.3", "@monaco-editor/react": "^4.5.0", "mapbox-gl": "npm:empty-npm-package@^1.0.0", "maplibre-gl": "^2.4.0", diff --git a/examples/website/wms/package.json b/examples/website/wms/package.json index 960d280610..9c4b5b8d3a 100644 --- a/examples/website/wms/package.json +++ b/examples/website/wms/package.json @@ -12,8 +12,8 @@ "dependencies": { "@deck.gl/core": "^8.9.28", "@deck.gl/geo-layers": "^8.9.28", - "@loaders.gl/core": "4.0.0-alpha.23", - "@loaders.gl/wms": "4.0.0-alpha.23", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/wms": "4.0.0-beta.3", "@monaco-editor/react": "^4.5.0", "deck.gl": "^8.9.0", "mapbox-gl": "npm:empty-npm-package@1.0.0", diff --git a/modules/3d-tiles/package.json b/modules/3d-tiles/package.json index 9a511feea5..35298f9d0a 100644 --- a/modules/3d-tiles/package.json +++ b/modules/3d-tiles/package.json @@ -54,7 +54,7 @@ "long": "^5.2.1" }, "peerDependencies": { - "@loaders.gl/core": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3" }, "gitHead": "c95a4ff72512668a93d9041ce8636bac09333fd5" } diff --git a/modules/core/src/core-addons/write-file-browser.ts b/modules/core/src/core-addons/write-file-browser.ts index 745a41d40d..f7a7a633cd 100644 --- a/modules/core/src/core-addons/write-file-browser.ts +++ b/modules/core/src/core-addons/write-file-browser.ts @@ -8,9 +8,9 @@ import {isBrowser} from '@loaders.gl/core'; // TODO hack - trick filesaver.js to skip loading under node const savedNavigatorExists = 'navigator' in global; -const savedNavigator = global.navigator; +const savedNavigator = globalThis.navigator; if (!isBrowser) { - global.navigator = {userAgent: 'MSIE 9.'}; + globalThis.navigator = {userAgent: 'MSIE 9.'}; } // Need to use `require` to ensure our modification of global code above happens first @@ -18,9 +18,9 @@ const saveAs = require('filesaver.js'); if (!isBrowser) { if (savedNavigatorExists) { - global.navigator = savedNavigator; + globalThis.navigator = savedNavigator; } else { - delete global.navigator; + delete globalThis.navigator; } } // END hack diff --git a/modules/core/src/lib/loader-utils/option-utils.ts b/modules/core/src/lib/loader-utils/option-utils.ts index ced16bf6d6..1d558016f1 100644 --- a/modules/core/src/lib/loader-utils/option-utils.ts +++ b/modules/core/src/lib/loader-utils/option-utils.ts @@ -6,7 +6,7 @@ import {probeLog, NullLog} from './loggers'; import {DEFAULT_LOADER_OPTIONS, REMOVED_LOADER_OPTIONS} from './option-defaults'; /** - * Global state for loaders.gl. Stored on `global.loaders._state` + * Global state for loaders.gl. Stored on `globalThis.loaders._state` */ type GlobalLoaderState = { loaderRegistry: Loader[]; diff --git a/modules/geopackage/test/index.js b/modules/geopackage/test/index.js deleted file mode 100644 index 3a4caf52fd..0000000000 --- a/modules/geopackage/test/index.js +++ /dev/null @@ -1 +0,0 @@ -import './geopackage-loader.spec'; diff --git a/modules/geopackage/test/index.ts b/modules/geopackage/test/index.ts new file mode 100644 index 0000000000..c2b8b135ce --- /dev/null +++ b/modules/geopackage/test/index.ts @@ -0,0 +1,2 @@ +// TODO v4.0 restore these tests +// import './geopackage-loader.spec'; diff --git a/modules/gltf/test/lib/api/gltf-scenegraph-accessors.spec.ts b/modules/gltf/test/lib/api/gltf-scenegraph-accessors.spec.ts index f97ef96673..f7d67a0a25 100644 --- a/modules/gltf/test/lib/api/gltf-scenegraph-accessors.spec.ts +++ b/modules/gltf/test/lib/api/gltf-scenegraph-accessors.spec.ts @@ -80,7 +80,7 @@ test('GLTFScenegraph#BufferView indices resolve correctly', async (t) => { t.end(); }); -test('GLTFScenegraph#Typed Arrays sgould be taken by Accessor', async (t) => { +test('GLTFScenegraph#Typed Arrays should be taken by Accessor', async (t) => { const GLB_ACCESSOR_URL = '@loaders.gl/gltf/test/data/glb/DamagedHelmet.glb'; const testDataSet = [ { diff --git a/modules/i3s/package.json b/modules/i3s/package.json index 5daa990718..4da0f9a31b 100644 --- a/modules/i3s/package.json +++ b/modules/i3s/package.json @@ -55,7 +55,7 @@ "@math.gl/geospatial": "^4.0.0" }, "peerDependencies": { - "@loaders.gl/core": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3" }, "gitHead": "c95a4ff72512668a93d9041ce8636bac09333fd5" } diff --git a/modules/images/src/lib/category-api/image-format.ts b/modules/images/src/lib/category-api/image-format.ts index af84ed4aaf..7dd7f76bd4 100644 --- a/modules/images/src/lib/category-api/image-format.ts +++ b/modules/images/src/lib/category-api/image-format.ts @@ -61,9 +61,9 @@ export function isImageFormatSupported(mimeType: string): boolean { function checkNodeImageFormatSupport(mimeType: string): boolean { /** @deprecated Remove these in 4.0 and rely on polyfills to inject them */ const NODE_FORMAT_SUPPORT = ['image/png', 'image/jpeg', 'image/gif']; - // @ts-ignore - const {_parseImageNode, _imageFormatsNode = NODE_FORMAT_SUPPORT} = globalThis; - return Boolean(_parseImageNode) && _imageFormatsNode.includes(mimeType); + const parseImageNode = globalThis.loaders?.parseImageNode; + const imageFormatsNode = globalThis.loaders?.imageFormatsNode || NODE_FORMAT_SUPPORT; + return Boolean(parseImageNode) && imageFormatsNode.includes(mimeType); } /** Checks image format support synchronously. diff --git a/modules/images/src/lib/category-api/image-type.ts b/modules/images/src/lib/category-api/image-type.ts index 4e7015c83a..0da02a0a8a 100644 --- a/modules/images/src/lib/category-api/image-type.ts +++ b/modules/images/src/lib/category-api/image-type.ts @@ -2,11 +2,11 @@ import {isBrowser} from '@loaders.gl/loader-utils'; import type {ImageTypeEnum} from '../../types'; // @ts-ignore TS2339: Property does not exist on type -const {_parseImageNode} = globalThis; +const parseImageNode = globalThis.loaders?.parseImageNode; const IMAGE_SUPPORTED = typeof Image !== 'undefined'; // NOTE: "false" positives if jsdom is installed const IMAGE_BITMAP_SUPPORTED = typeof ImageBitmap !== 'undefined'; -const NODE_IMAGE_SUPPORTED = Boolean(_parseImageNode); +const NODE_IMAGE_SUPPORTED = Boolean(parseImageNode); const DATA_SUPPORTED = isBrowser ? true : NODE_IMAGE_SUPPORTED; /** diff --git a/modules/images/src/lib/encoders/encode-image.ts b/modules/images/src/lib/encoders/encode-image.ts index e8c28dc621..34128487a0 100644 --- a/modules/images/src/lib/encoders/encode-image.ts +++ b/modules/images/src/lib/encoders/encode-image.ts @@ -3,7 +3,7 @@ import {ImageDataType} from '../../types'; import {getImageSize} from '../category-api/parsed-image-api'; // @ts-ignore TS2339: Property does not exist on type -const {_encodeImageNode} = globalThis; +const encodeImageNode = globalThis.loaders?.encodeImageNode; /** * Returns data bytes representing a compressed image in PNG or JPG format, @@ -20,8 +20,8 @@ export async function encodeImage( options = options || {}; options.image = options.image || ({} as {[key: string]: any}); - return _encodeImageNode - ? _encodeImageNode(image, {type: options.image.mimeType}) + return encodeImageNode + ? encodeImageNode(image, {type: options.image.mimeType}) : encodeImageInBrowser(image, options); } diff --git a/modules/images/src/lib/parsers/parse-to-node-image.ts b/modules/images/src/lib/parsers/parse-to-node-image.ts index 8178a0ffe8..68fb50c16b 100644 --- a/modules/images/src/lib/parsers/parse-to-node-image.ts +++ b/modules/images/src/lib/parsers/parse-to-node-image.ts @@ -24,9 +24,9 @@ export async function parseToNodeImage( const {mimeType} = getBinaryImageMetadata(arrayBuffer) || {}; // @ts-ignore - const _parseImageNode: ParseImageNode = globalThis._parseImageNode; - assert(_parseImageNode); // '@loaders.gl/polyfills not installed' + const parseImageNode: ParseImageNode = globalThis.loaders?.parseImageNode; + assert(parseImageNode); // '@loaders.gl/polyfills not installed' // @ts-expect-error TODO should we throw error in this case? - return await _parseImageNode(arrayBuffer, mimeType); + return await parseImageNode(arrayBuffer, mimeType); } diff --git a/modules/polyfills/src/fetch/utils/decode-data-uri.node.ts b/modules/polyfills/src/fetch/utils/decode-data-uri.node.ts new file mode 100644 index 0000000000..7f6f2dbeb9 --- /dev/null +++ b/modules/polyfills/src/fetch/utils/decode-data-uri.node.ts @@ -0,0 +1,69 @@ +// Based on binary-gltf-utils under MIT license: Copyright (c) 2016-17 Karl Cheng + +const isArrayBuffer = (x) => x && x instanceof ArrayBuffer; +const isBuffer = (x) => x && x instanceof Buffer; + +/** + * Parses a data URI into a buffer, as well as retrieving its declared MIME type. + * + * @param {string} uri - a data URI (assumed to be valid) + * @returns {Object} { buffer, mimeType } + */ +export function decodeDataUri(uri: string): {arrayBuffer: ArrayBuffer; mimeType: string} { + const dataIndex = uri.indexOf(','); + + let buffer; + let mimeType; + if (uri.slice(dataIndex - 7, dataIndex) === ';base64') { + buffer = Buffer.from(uri.slice(dataIndex + 1), 'base64'); + mimeType = uri.slice(5, dataIndex - 7).trim(); + } else { + buffer = Buffer.from(decodeURIComponent(uri.slice(dataIndex + 1))); + mimeType = uri.slice(5, dataIndex).trim(); + } + + if (!mimeType) { + mimeType = 'text/plain;charset=US-ASCII'; + } else if (mimeType.startsWith(';')) { + mimeType = `text/plain${mimeType}`; + } + + return {arrayBuffer: toArrayBuffer(buffer), mimeType}; +} + +/** + * @param data + * @todo Duplicate of core + */ +export function toArrayBuffer(data: unknown): ArrayBuffer { + if (isArrayBuffer(data)) { + return data as ArrayBuffer; + } + + // TODO - per docs we should just be able to call buffer.buffer, but there are issues + if (isBuffer(data)) { + // @ts-expect-error + const typedArray = new Uint8Array(data); + return typedArray.buffer; + } + + // Careful - Node Buffers will look like ArrayBuffers (keep after isBuffer) + if (ArrayBuffer.isView(data)) { + return data.buffer; + } + + if (typeof data === 'string') { + const text = data; + const uint8Array = new TextEncoder().encode(text); + return uint8Array.buffer; + } + + // HACK to support Blob polyfill + // @ts-expect-error + if (data && typeof data === 'object' && data._toArrayBuffer) { + // @ts-expect-error + return data._toArrayBuffer(); + } + + throw new Error(`toArrayBuffer(${JSON.stringify(data, null, 2).slice(10)})`); +} diff --git a/modules/polyfills/src/images/encode-image-node.ts b/modules/polyfills/src/images/encode-image-node.ts new file mode 100644 index 0000000000..12e2512106 --- /dev/null +++ b/modules/polyfills/src/images/encode-image-node.ts @@ -0,0 +1,41 @@ +// Use stackgl modules for DOM-less reading and writing of images + +import savePixels from 'save-pixels'; +import ndarray from 'ndarray'; +import {bufferToArrayBuffer} from '../buffer/to-array-buffer.node'; + +/** + * Returns data bytes representing a compressed image in PNG or JPG format, + * This data can be saved using file system (f) methods or + * used in a request. + * @param image to save + * @param options + * @param options.type='png' - png, jpg or image/png, image/jpg are valid + * @param options.dataURI - Whether to include a data URI header + * @return {*} bytes + */ +export function encodeImageToStreamNode( + image: {data: any; width: number; height: number}, + options: {type?: string; dataURI?: string} +) { + // Support MIME type strings + const type = options.type ? options.type.replace('image/', '') : 'jpeg'; + const pixels = ndarray(image.data, [image.width, image.height, 4], [4, image.width * 4, 1], 0); + + // Note: savePixels returns a stream + return savePixels(pixels, type, options); +} + +export function encodeImageNode(image, options) { + const imageStream = encodeImageToStreamNode(image, options); + + return new Promise((resolve) => { + const buffers: any[] = []; + imageStream.on('data', (buffer) => buffers.push(buffer)); + // TODO - convert to arraybuffer? + imageStream.on('end', () => { + const buffer = Buffer.concat(buffers); + resolve(bufferToArrayBuffer(buffer)); + }); + }); +} diff --git a/modules/polyfills/src/images/parse-image-node.ts b/modules/polyfills/src/images/parse-image-node.ts new file mode 100644 index 0000000000..68959e6245 --- /dev/null +++ b/modules/polyfills/src/images/parse-image-node.ts @@ -0,0 +1,53 @@ +// loaders.gl, MIT license + +import getPixels from 'get-pixels'; + +/** Declares which image format mime types this loader polyfill supports */ +export const NODE_FORMAT_SUPPORT = ['image/png', 'image/jpeg', 'image/gif']; + +// Note: These types are also defined in @loaders.gl/images and need to be kept in sync +type NDArray = { + shape: number[]; + data: Uint8Array; + width: number; + height: number; + components: number; + layers: number[]; +}; + +export async function parseImageNode(arrayBuffer: ArrayBuffer, mimeType: string): Promise { + if (!mimeType) { + throw new Error('MIMEType is required to parse image under Node.js'); + } + + const buffer = arrayBuffer instanceof Buffer ? arrayBuffer : Buffer.from(arrayBuffer); + const ndarray = await getPixelsAsync(buffer, mimeType); + return ndarray; +} + +// TODO - check if getPixels callback is asynchronous if provided with buffer input +// if not, parseImage can be a sync function +function getPixelsAsync(buffer: Buffer, mimeType: string): Promise { + return new Promise((resolve) => + getPixels(buffer, mimeType, (err, ndarray) => { + if (err) { + throw err; + } + + const shape = [...ndarray.shape]; + const layers = ndarray.shape.length === 4 ? ndarray.shape.shift() : 1; + const data = ndarray.data instanceof Buffer ? new Uint8Array(ndarray.data) : ndarray.data; + + // extract width/height etc + resolve({ + shape, + data, + width: ndarray.shape[0], + height: ndarray.shape[1], + components: ndarray.shape[2], + // TODO - error + layers: layers ? [layers] : [] + }); + }) + ); +} diff --git a/modules/polyfills/src/index.ts b/modules/polyfills/src/index.ts index 55c648fe9b..6fa1a3f2cc 100644 --- a/modules/polyfills/src/index.ts +++ b/modules/polyfills/src/index.ts @@ -6,8 +6,8 @@ import {TextDecoder, TextEncoder} from './text-encoder/text-encoder'; // Node specific import {atob, btoa} from './buffer/btoa.node'; -import {encodeImageNode} from './images/encode-image.node'; -import {parseImageNode, NODE_FORMAT_SUPPORT} from './images/parse-image.node'; +import {encodeImageNode} from './images/encode-image-node'; +import {parseImageNode, NODE_FORMAT_SUPPORT} from './images/parse-image-node'; // FILESYSTEM POLYFILLS import {NodeFile} from './filesystems/node-file'; @@ -72,14 +72,27 @@ if (!('btoa' in globalThis) && btoa) { // These are not official polyfills but used by the @loaders.gl/images module if installed // TODO - is there an appropriate Image API we could polyfill using an adapter? -if (!('_encodeImageNode' in globalThis) && encodeImageNode) { - globalThis['_encodeImageNode'] = encodeImageNode; -} +globalThis.loaders.encodeImageNode = encodeImageNode; +globalThis.loaders.parseImageNode = parseImageNode; +globalThis.loaders.imageFormatsNode = NODE_FORMAT_SUPPORT; -if (!('_parseImageNode' in globalThis) && parseImageNode) { - globalThis['_parseImageNode'] = parseImageNode; - globalThis['_imageFormatsNode'] = NODE_FORMAT_SUPPORT; -} +// Deprecated, remove after republish +globalThis._parseImageNode = parseImageNode; +globalThis._imageFormatsNode = NODE_FORMAT_SUPPORT; + +// LOAD LIBRARY + +import { + readFileAsArrayBuffer, + readFileAsText, + requireFromFile, + requireFromString +} from './load-library/require-utils.node'; + +globalThis.loaders.readFileAsArrayBuffer = readFileAsArrayBuffer; +globalThis.loaders.readFileAsText = readFileAsText; +globalThis.loaders.requireFromFile = requireFromFile; +globalThis.loaders.requireFromString = requireFromString; // DEPRECATED POLYFILL: // - Node v18+: No, not needed diff --git a/modules/polyfills/src/load-library/require-utils.node.ts b/modules/polyfills/src/load-library/require-utils.node.ts new file mode 100644 index 0000000000..4238b689e9 --- /dev/null +++ b/modules/polyfills/src/load-library/require-utils.node.ts @@ -0,0 +1,101 @@ +// Fork of https://github.com/floatdrop/require-from-string/blob/master/index.js +// Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop) +// MIT license + +// this file is not visible to webpack (it is excluded in the package.json "browser" field). + +import Module from 'module'; +import path from 'path'; +import fs from 'fs'; + +/** + * Load a file from local file system + * @param filename + * @returns + */ +export async function readFileAsArrayBuffer(filename: string): Promise { + if (filename.startsWith('http')) { + const response = await fetch(filename); + return await response.arrayBuffer(); + } + const buffer = fs.readFileSync(filename); + return buffer.buffer; +} + +/** + * Load a file from local file system + * @param filename + * @returns + */ +export async function readFileAsText(filename: string): Promise { + if (filename.startsWith('http')) { + const response = await fetch(filename); + return await response.text(); + } + const text = fs.readFileSync(filename, 'utf8'); + return text; +} + +// Node.js Dynamically require from file +// Relative names are resolved relative to cwd +// This indirect function is provided because webpack will try to bundle `module.require`. +// this file is not visible to webpack (it is excluded in the package.json "browser" field). +export async function requireFromFile(filename: string): Promise { + if (filename.startsWith('http')) { + const response = await fetch(filename); + const code = await response.text(); + return requireFromString(code); + } + + if (!filename.startsWith('/')) { + filename = `${process.cwd()}/${filename}`; + } + const code = await fs.readFileSync(filename, 'utf8'); + return requireFromString(code); +} + +// Dynamically require from string +// - `code` - Required - Type: string - Module code. +// - `filename` - Type: string - Default: '' - Optional filename. +// - `options.appendPaths` Type: Array List of paths, that will be appended to module paths. +// Useful, when you want to be able require modules from these paths. +// - `options.prependPaths` Type: Array Same as appendPaths, but paths will be prepended. +export function requireFromString( + code: string, + filename = '', + options?: { + prependPaths?: string[]; + appendPaths?: string[]; + } +): any { + if (typeof filename === 'object') { + options = filename; + filename = ''; + } + filename = filename.replace('file://', ''); + + if (typeof code !== 'string') { + throw new Error(`code must be a string, not ${typeof code}`); + } + + // @ts-ignore + const paths = Module._nodeModulePaths(path.dirname(filename)); + + const parent = typeof module !== 'undefined' && module?.parent; + + // @ts-ignore + const newModule = new Module(filename, parent); + newModule.filename = filename; + newModule.paths = ([] as string[]) + .concat(options?.prependPaths || []) + .concat(paths) + .concat(options?.appendPaths || []); + // @ts-ignore + newModule._compile(code, filename); + + if (parent && parent.children) { + parent.children.splice(parent.children.indexOf(newModule), 1); + } + + return newModule.exports; +} diff --git a/modules/polyfills/test/images-node/images-node.spec.js b/modules/polyfills/test/images-node/images-node.spec.js index 8ca23ab2ef..8dcdbe0566 100644 --- a/modules/polyfills/test/images-node/images-node.spec.js +++ b/modules/polyfills/test/images-node/images-node.spec.js @@ -1,7 +1,7 @@ /* eslint-disable max-len */ import test from 'tape-promise/tape'; import {isBrowser, fetchFile} from '@loaders.gl/core'; -import {parseImageNode} from '../../src/images/parse-image.node'; +import {parseImageNode} from '../../src/images/parse-image-node'; const images = [ ['@loaders.gl/images/test/data/img1-preview.png', 'image/png'], @@ -12,9 +12,17 @@ const images = [ if (!isBrowser) { test('Node image polyfills', (t) => { // @ts-ignore - t.equals(typeof _encodeImageNode, 'function', 'global._encodeImageNode successfully installed'); + t.equals( + typeof globalThis.loaders?.encodeImageNode, + 'function', + 'encodeImageNode successfully installed' + ); // @ts-ignore - t.equals(typeof _parseImageNode, 'function', 'global._parseImageNode successfully installed'); + t.equals( + typeof globalThis.loaders?.parseImageNode, + 'function', + 'parseImageNode successfully installed' + ); t.end(); }); diff --git a/modules/polyfills/test/index.ts b/modules/polyfills/test/index.ts index de588fd805..def4d2c105 100644 --- a/modules/polyfills/test/index.ts +++ b/modules/polyfills/test/index.ts @@ -14,3 +14,5 @@ import './filesystems/fetch-node.spec'; import './filesystems/node-file.spec'; import './filesystems/node-filesystem.spec'; import './filesystems/fetch-node.spec'; + +import './load-library/require-utils.spec'; diff --git a/modules/polyfills/test/load-library/fixture/module.js b/modules/polyfills/test/load-library/fixture/module.js new file mode 100644 index 0000000000..568f6b3104 --- /dev/null +++ b/modules/polyfills/test/load-library/fixture/module.js @@ -0,0 +1 @@ +module.exports = require('./submodule.js'); diff --git a/modules/polyfills/test/load-library/fixture/submodule.js b/modules/polyfills/test/load-library/fixture/submodule.js new file mode 100644 index 0000000000..e8802c6c5f --- /dev/null +++ b/modules/polyfills/test/load-library/fixture/submodule.js @@ -0,0 +1,3 @@ +// loaders.gl, MIT license +module.exports = {}; +// export const module = {}; diff --git a/modules/polyfills/test/load-library/require-utils.spec.ts b/modules/polyfills/test/load-library/require-utils.spec.ts new file mode 100644 index 0000000000..0a9b2c82a3 --- /dev/null +++ b/modules/polyfills/test/load-library/require-utils.spec.ts @@ -0,0 +1,94 @@ +// Fork of https://github.com/floatdrop/require-from-string/blob/master/index.js +// Copyright (c) Vsevolod Strukchinsky (github.com/floatdrop) +// MIT license + +import test from 'tape-promise/tape'; +import * as fs from 'fs'; +import * as path from 'path'; +import {isBrowser} from '@loaders.gl/core'; +import {requireFromFile, requireFromString} from '../../src/load-library/require-utils.node'; + +const DIR = path?.dirname?.(import.meta.url)?.replace('file://', '') || '.'; +const MODULE_URL = `${DIR}/fixture/module.js`; +const SUBMODULE_URL = `${DIR}/fixture/submodule.js`; + +test('polyfills#require-utils', (tt) => { + if (isBrowser) { + tt.end(); + return; + } + + test.skip('polyfills#requireFromFile#', (t) => { + t.ok(requireFromFile(MODULE_URL), 'Require from file worked'); + t.ok(requireFromFile(SUBMODULE_URL), 'Require from file worked'); + t.end(); + }); + + test('polyfills#requireFromString#should accept only string as code', (t) => { + // @ts-expect-error + t.throws(() => requireFromString(), /code must be a string, not undefined/); + t.end(); + }); + + test('polyfills#requireFromString#should require from string', (t) => { + t.equal(requireFromString('module.exports = 1;'), 1); + t.end(); + }); + + test('polyfills#requireFromString#should accept filename', (t) => { + t.throws(() => requireFromString('module.exports = ', 'bug.js'), /bug\.js|Unexpected/); + t.end(); + }); + + test.skip('polyfills#requireFromString#should work with relative require in file', (t) => { + const code = fs.readFileSync(MODULE_URL, 'utf8'); + const result = requireFromString(code, MODULE_URL); + + t.ok(result); + // TODO + // t.equal(module, result.parent.parent); + t.end(); + }); + + test.skip('polyfills#requireFromString#should have appended and preppended paths', (t) => { + const code = fs.readFileSync(SUBMODULE_URL, 'utf8'); + const result = requireFromString(code, SUBMODULE_URL, { + appendPaths: ['append'], + prependPaths: ['prepend'] + }); + + console.error(result); + t.ok(result); + t.equal(result.paths.indexOf('append'), result.paths.length - 1); + t.equal(result.paths.indexOf('prepend'), 0); + t.end(); + }); + + // TODO + test.skip('requireFromString#should have meaningful error message', (t) => { + try { + requireFromString('throw new Error("Boom!");'); + } catch (error) { + // @ts-ignore + t.ok(/\(:1:69\)/.test(error.stack), 'should contain (:1:69) in stack'); + } + + try { + requireFromString('throw new Error("Boom!");', ''); + } catch (error) { + // @ts-ignore + t.ok(/\(:1:69\)/.test(error.stack), 'should contain (:1:69) in stack'); + } + t.end(); + }); + + test.skip('polyfills#requireFromString#should cleanup parent.children', (t) => { + const code = fs.readFileSync(SUBMODULE_URL, 'utf8'); + const result = requireFromString(code, SUBMODULE_URL); + + t.ok(module.children.indexOf(result) === -1); + t.end(); + }); + + tt.end(); +}); diff --git a/modules/terrain/test/terrain-loader.spec.js b/modules/terrain/test/terrain-loader.spec.js index 2a7e4fcf08..460ec65c04 100644 --- a/modules/terrain/test/terrain-loader.spec.js +++ b/modules/terrain/test/terrain-loader.spec.js @@ -23,6 +23,7 @@ test('TerrainLoader#loader objects', async (t) => { }); test('TerrainLoader#parse mapbox martini', async (t) => { + console.error(globalThis.loaders); const data = await load(MAPBOX_TERRAIN_PNG_URL, TerrainLoader, { terrain: { elevationDecoder: { @@ -34,7 +35,8 @@ test('TerrainLoader#parse mapbox martini', async (t) => { meshMaxError: 5.0, bounds: [83, 329.5, 83.125, 329.625], // note: not the real tile bounds tesselator: 'martini' - } + }, + worker: false }); validateMeshCategoryData(t, data); // TODO: should there be a validateMeshCategoryData? diff --git a/modules/tile-converter/package.json b/modules/tile-converter/package.json index 91f52db7d6..c8264bbc7b 100644 --- a/modules/tile-converter/package.json +++ b/modules/tile-converter/package.json @@ -81,7 +81,7 @@ "uuid": "^9.0.0" }, "peerDependencies": { - "@loaders.gl/core": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3" }, "quarantinedDependencies": { "join-images": "^1.1.3", diff --git a/modules/tiles/package.json b/modules/tiles/package.json index 25aa9336aa..97cda49f5b 100644 --- a/modules/tiles/package.json +++ b/modules/tiles/package.json @@ -50,7 +50,7 @@ "@probe.gl/stats": "^4.0.2" }, "peerDependencies": { - "@loaders.gl/core": "^4.0.0-alpha.8" + "@loaders.gl/core": "4.0.0-beta.3" }, "devDependencies": { "@deck.gl/core": "^8.9.0" diff --git a/modules/worker-utils/src/lib/library-utils/library-utils.ts b/modules/worker-utils/src/lib/library-utils/library-utils.ts index 68e0b13b6c..6cd13aed65 100644 --- a/modules/worker-utils/src/lib/library-utils/library-utils.ts +++ b/modules/worker-utils/src/lib/library-utils/library-utils.ts @@ -1,5 +1,5 @@ /* global importScripts */ -import {global, isBrowser, isWorker} from '../env-utils/globals'; +import {isBrowser, isWorker} from '../env-utils/globals'; import * as node from '../node/require-utils.node'; import {assert} from '../env-utils/assert'; import {VERSION} from '../env-utils/version'; @@ -134,7 +134,7 @@ function loadLibraryFromString(scriptSource: string, id: string): null | any { if (isWorker) { // Use lvalue trick to make eval run in global scope - eval.call(global, scriptSource); // eslint-disable-line no-eval + eval.call(globalThis, scriptSource); // eslint-disable-line no-eval // https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript // http://perfectionkills.com/global-eval-what-are-the-options/ return null; diff --git a/package.json b/package.json index 818a5c6cef..19167d0ffa 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@types/tape-promise": "^4.0.1", "base64-inline-loader": "^1.1.1", "base64-loader": "^1.0.0", - "ocular-dev-tools": "2.0.0-alpha.16", + "ocular-dev-tools": "2.0.0-alpha.18", "pre-commit": "^1.2.2", "pre-push": "^0.1.1" }, diff --git a/test/apps/typescript-test/package.json b/test/apps/typescript-test/package.json index 2507ff72ea..ebd9aa5103 100644 --- a/test/apps/typescript-test/package.json +++ b/test/apps/typescript-test/package.json @@ -31,7 +31,7 @@ "typescript": "^5.0.4" }, "dependencies": { - "@loaders.gl/shapefile": "^4.0.0-alpha.8" + "@loaders.gl/shapefile": "4.0.0-beta.3" }, "gitHead": "c95a4ff72512668a93d9041ce8636bac09333fd5" } diff --git a/test/node.ts b/test/node.ts index adcc53b073..e31da96aeb 100644 --- a/test/node.ts +++ b/test/node.ts @@ -4,7 +4,7 @@ const packageInfo = JSON.parse(readFileSync('./lerna.json', 'utf-8')); // Note: This constant will be inlined by babel plugin during transpilation // But for node we read it from lerna.json // @ts-ignore TS2339: Property does not exist on type 'Global' -global.__VERSION__ = packageInfo.version; +globalThis.__VERSION__ = packageInfo.version; // Determine Node version let nodeVersion = 10; @@ -13,7 +13,7 @@ if (typeof process !== 'undefined') { nodeVersion = (matches && parseFloat(matches[1])) || nodeVersion; } // @ts-ignore TS2339: Property does not exist on type 'Global' -global.nodeVersion = nodeVersion; +globalThis.nodeVersion = nodeVersion; import '@loaders.gl/polyfills'; diff --git a/website/package.json b/website/package.json index 1026a91f7f..bd2f3076f1 100644 --- a/website/package.json +++ b/website/package.json @@ -28,12 +28,12 @@ "@fortawesome/fontawesome-svg-core": "^1.2.34", "@fortawesome/free-solid-svg-icons": "^5.15.2", "@fortawesome/react-fontawesome": "^0.1.14", - "@loaders.gl/core": "^4.0.0-alpha.8", - "@loaders.gl/i3s": "^4.0.0-alpha.8", - "@loaders.gl/las": "^4.0.0-alpha.8", - "@loaders.gl/loader-utils": "^4.0.0-alpha.8", - "@loaders.gl/obj": "^4.0.0-alpha.8", - "@loaders.gl/ply": "^4.0.0-alpha.8", + "@loaders.gl/core": "4.0.0-beta.3", + "@loaders.gl/i3s": "4.0.0-beta.3", + "@loaders.gl/las": "4.0.0-beta.3", + "@loaders.gl/loader-utils": "4.0.0-beta.3", + "@loaders.gl/obj": "4.0.0-beta.3", + "@loaders.gl/ply": "4.0.0-beta.3", "@luma.gl/experimental": "^8.5.0", "@material-ui/core": "^4.10.2", "@material-ui/icons": "^4.9.1", diff --git a/yarn.lock b/yarn.lock index 230ec96484..5b109065eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8834,10 +8834,10 @@ octokit-pagination-methods@^1.1.0: resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== -ocular-dev-tools@2.0.0-alpha.16: - version "2.0.0-alpha.16" - resolved "https://registry.yarnpkg.com/ocular-dev-tools/-/ocular-dev-tools-2.0.0-alpha.16.tgz#eafe33765ae6ca40b5d0b2b606c095829d572e38" - integrity sha512-4iTw4DFRnSt93zKsq1hVRD403U8SX0Srz5nYUlNevl8ZAsiKXrjJH1caCGzRsbwuZKMCutWYG8NCBlUXMONF1g== +ocular-dev-tools@2.0.0-alpha.18: + version "2.0.0-alpha.18" + resolved "https://registry.yarnpkg.com/ocular-dev-tools/-/ocular-dev-tools-2.0.0-alpha.18.tgz#6483afe6a54cb0293eba5487db798daed942e810" + integrity sha512-szLVQ/ViYU7RF0TvJ1NNCI3IxAvKavxZw/iltULUJsPLcJPxhcIEbx0e/SQTc97JbgGkxWcWmdWmpzthxuPSHg== dependencies: "@babel/cli" "^7.14.5" "@babel/core" "^7.14.5"