diff --git a/.gitignore b/.gitignore index d4c2973..3e73cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ yarn.lock .build __coverage__ .gh-pages +.notes diff --git a/README.md b/README.md index bbb2311..c9e48be 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,122 @@ inspired by http://bl.ocks.org/Sumbera/c6fed35c377a46ff74c3 & need. - Remaining as simple as possible with current fastest libs - Providing the same sort of user experience one would get using standard html and elements +## GeoJSON & WGS84 Standard Compliance + +Leaflet.glify follows the **World Geodetic System (WGS84) standard** as defined by the National Geospatial-Intelligence Agency (NGA) and adopted by the GeoJSON specification. + +### **Default Coordinate Order** +- **Default format**: `[longitude, latitude]` (WGS84/GeoJSON standard) +- **Why this matters**: GeoJSON specification requires coordinates in `[lng, lat]` order +- **Reference**: [WGS84 Standard (NGA)](https://earth-info.nga.mil/php/download.php?file=coord-wgs84), [GeoJSON Specification](https://geojson.org/) + +### **Coordinate Order Methods** +```typescript +import glify from 'leaflet.glify'; + +// Check current coordinate order, "lngFirst" (default) +const currentOrder = glify.getCoordinateOrder(); + +// Set coordinate order +// WGS84/GeoJSON standard [longitude, latitude] +glify.setCoordinateOrder("lngFirst"); +// Legacy format [latitude, longitude] +glify.setCoordinateOrder("latFirst"); + +// Fluent API +// Same as setCoordinateOrder("lngFirst") +glify.longitudeFirst(); +// Same as setCoordinateOrder("latFirst") +glify.latitudeFirst(); +``` + +## TypeScript Support + +Leaflet.glify provides comprehensive TypeScript definitions for better development experience and type safety. The type system is organized to avoid circular dependencies while maintaining full type inference. + +### **Type Organization** +Types are organized into logical groups: +- **`types-base.ts`** - Base interfaces and utility types (no class references) +- **`types-glify.ts`** - Core library interface that references actual classes +- **`types.ts`** - Main export file that re-exports all types + +### **Importing Types** +```typescript +import glify, { + IGlify, + GlifyCoordinateOrder, + IPointsSettings, + GlifyClickCallback +} from 'leaflet.glify'; + +// Type-safe coordinate order configuration +const order: GlifyCoordinateOrder = "lngFirst"; +glify.setCoordinateOrder(order); + +// Type-safe settings with full type inference +const settings: Partial = { + map: leafletMap, + data: geoJsonData, + size: 5, + click: (e, feature) => { + console.log('Clicked:', feature); + return false; + } +}; + +// Full type inference - points is typed as Points class +const points = glify.points(settings); +``` + +### **Available Types** +- **Core**: `IGlify`, `IGlifyShader`, `GlifyInstance` +- **Settings**: `IPointsSettings`, `ILinesSettings`, `IShapesSettings`, `IBaseGlLayerSettings` +- **Events**: `GlifyClickCallback`, `GlifyHoverCallback`, `GlifyContextMenuCallback` +- **Coordinates**: `GlifyCoordinateOrder`, `IGlifyCoordinateConfig` +- **WebGL**: `IShaderVariable`, `ICanvasOverlayDrawEvent` +- **Utilities**: `IColor`, `IPixel`, `IPointVertex` +- **Callbacks**: `ColorCallback`, `WeightCallback`, `EventCallback`, `SetupHoverCallback` + +### **Type Safety Features** +- **Real class types** - No forward declarations, 100% type consistency +- **Full inheritance** - Settings interfaces properly extend base interfaces +- **Generic support** - Event callbacks support custom feature types +- **Method chaining** - Fluent API with proper return type inference + +### **Working with Types** +The type system is designed to provide maximum type safety while avoiding circular dependencies: + +```typescript +// Import the main library and types +import glify, { + IGlify, + IPointsSettings, + GlifyClickCallback +} from 'leaflet.glify'; + +// Create type-safe settings +const settings: Partial = { + map: leafletMap, + data: geoJsonData, + size: 5, + // Type-safe event handlers + click: (e, feature) => { + // feature is properly typed based on your data + console.log('Clicked:', feature); + return false; + } +}; + +// Get fully typed instance +const points = glify.points(settings); + +// TypeScript knows this is a Points instance +// All methods and properties are properly typed +points.update(newData, 0); +points.remove([1, 2]); +points.render(); +``` + ## Usage ### Browser @@ -56,6 +172,39 @@ L.glify.points({ }); ``` +### **Typed Points Usage** +```typescript +import glify, { IPointsSettings, GlifyClickCallback } from 'leaflet.glify'; + +// Type-safe click handler with custom feature type +interface MyPointFeature { + properties: { name: string; value: number }; + geometry: { coordinates: [number, number] }; +} + +const clickHandler: GlifyClickCallback = (e, feature, xy) => { + console.log('Clicked feature:', feature.properties.name); + return true; +}; + +const settings: Partial = { + map: leafletMap, + data: geoJsonData, + size: 5, + click: clickHandler, + hover: (e, feature) => { + console.log('Hovered:', feature); + } +}; + +// Full type inference - points is typed as Points class +const points = glify.points(settings); + +// Type-safe access to Points methods and properties +points.update(newData, 0); +points.remove([1, 2, 3]); +``` + ### Simple Lines Usage ```ts L.glify.lines({ @@ -75,6 +224,38 @@ L.glify.lines({ }); ``` +### **Typed Lines Usage** +```typescript +import glify, { ILinesSettings, GlifyHoverCallback } from 'leaflet.glify'; + +// Type-safe hover handler with custom feature type +interface LineFeature { + properties: { name: string; type: string }; + geometry: { coordinates: [number, number][] }; +} + +const hoverHandler: GlifyHoverCallback = (e, feature, xy) => { + console.log('Hovered line:', feature.properties.name); +}; + +const settings: Partial = { + map: leafletMap, + data: lineGeoJson, + weight: 2, + hover: hoverHandler, + hoverOff: (e, feature) => { + console.log('Hover off:', feature); + } +}; + +// Full type inference - lines is typed as Lines class +const lines = glify.lines(settings); + +// Type-safe access to Lines methods and properties +lines.update(newLineFeature, 0); +lines.remove([0, 1]); +``` + ### Simple Polygon Usage ```ts L.glify.shapes({ @@ -90,6 +271,37 @@ L.glify.shapes({ }); ``` +### **Typed Shapes Usage** +```typescript +import glify, { IShapesSettings, GlifyContextMenuCallback } from 'leaflet.glify'; + +// Type-safe context menu handler with custom feature type +interface PolygonFeature { + properties: { name: string; area: number }; + geometry: { coordinates: [number, number][][] }; +} + +const contextMenuHandler: GlifyContextMenuCallback = (e, feature) => { + console.log('Right-clicked polygon:', feature.properties.name); + return true; +}; + +const settings: Partial = { + map: leafletMap, + data: polygonGeoJson, + border: true, + borderOpacity: 0.8, + contextMenu: contextMenuHandler +}; + +// Full type inference - shapes is typed as Shapes class +const shapes = glify.shapes(settings); + +// Type-safe access to Shapes methods and properties +shapes.update(newPolygonFeature, 0); +shapes.remove([0, 1]); +``` + ## API **`L.glify` methods** * [`points(options)`](#lglifypointsoptions-object) @@ -97,20 +309,28 @@ L.glify.shapes({ * [`shapes(options)`](#lglifyshapesoptions-object) * [`longitudeFirst()`](#longitudefirst) * [`latitudeFirst()`](#latitudefirst) +* [`setCoordinateOrder(order)`](#setcoordinateorder) +* [`getCoordinateOrder()`](#getcoordinateorder) **`L.glify` properties** * [`pointsInstances`](#pointsinstances) * [`linesInstances`](#linesinstances) * [`shapesInstances`](#shapesinstances) +* [`longitudeKey`](#longitudekey) +* [`latitudeKey`](#latitudekey) +* [`instances`](#instances) --- ### `L.glify.points(options: object)` Adds point data passed in `options.data` to the Leaflet map instance passed in `options.map`. + +**Note**: By default, coordinates are expected in `[longitude, latitude]` format (WGS84/GeoJSON standard). + #### Returns `L.glify.Points` instance #### Options * `map` `{Object}` required leaflet map -* `data` `{Object}` required geojson `FeatureCollection` object or an array of `[lat: number, lng: number]` arrays +* `data` `{Object}` required geojson `FeatureCollection` object or an array of `[lng: number, lat: number]` arrays (WGS84 standard) * `vertexShaderSource` `{String|Function}` optional glsl vertex shader source, defaults to use `L.glify.shader.vertex` * `fragmentShaderSource` `{String|Function}` optional glsl fragment shader source, defaults to use `L.glify.shader.fragment.point` * `click` `{Function}` optional event handler for clicking a point @@ -130,11 +350,14 @@ Adds point data passed in `options.data` to the Leaflet map instance passed in ` --- ### `L.glify.lines(options: object)` Adds line data passed in `options.data` to the Leaflet map instance passed in `options.map`. + +**Note**: By default, coordinates are expected in `[longitude, latitude]` format (WGS84/GeoJSON standard). + #### Returns `L.glify.Lines` instance #### Options * `map` `{Object}` required leaflet map -* `data` `{Object}` required geojson `FeatureCollection` object with `geometry.coordinates` arrays being in a `[lat: number, lng: number]` format +* `data` `{Object}` required geojson `FeatureCollection` object with `geometry.coordinates` arrays being in a `[lng: number, lat: number]` format (WGS84 standard) * `vertexShaderSource` `{String|Function}` optional glsl vertex shader source, defaults to use `L.glify.shader.vertex` * `fragmentShaderSource` `{String|Function}` optional glsl fragment shader source, defaults to use `L.glify.shader.fragment.point` * `click` `{Function}` optional event handler for clicking a line @@ -156,11 +379,14 @@ Adds line data passed in `options.data` to the Leaflet map instance passed in `o --- ### `L.glify.shapes(options: object)` Adds polygon/multipolygon data passed in `options.data` to the Leaflet map instance passed in `options.map`. + +**Note**: By default, coordinates are expected in `[longitude, latitude]` format (WGS84/GeoJSON standard). + #### Returns `L.glify.Shapes` instance #### Options * `map` `{Object}` required leaflet map -* `data` `{Object}` required geojson `FeatureCollection` object with `geometry.coordinates` arrays being in a `[lng: number, lat: number]` format *Note: `lat` and `lng` are expected in a different order than in `.points()` and `.lines()`* +* `data` `{Object}` required geojson `FeatureCollection` object with `geometry.coordinates` arrays being in a `[lng: number, lat: number]` format (WGS84 standard) * `vertexShaderSource` `{String|Function}` optional glsl vertex shader source, defaults to use `L.glify.shader.vertex` * `fragmentShaderSource` `{String|Function}` optional glsl fragment shader source, defaults to use `L.glify.shader.fragment.polygon` * `click` `{Function}` optional event handler for clicking a shape @@ -177,16 +403,35 @@ Adds polygon/multipolygon data passed in `options.data` to the Leaflet map insta * `pane` `{String}` optional, default is `overlayPane`. Can be set to a custom pane. --- ### `longitudeFirst()` -Sets the expecetd order of arrays in the `coordinates` array of GeoJSON passed to `options.data` to be `[lng, lat]` +Sets the expected order of arrays in the `coordinates` array of GeoJSON passed to `options.data` to be `[lng, lat]` (WGS84/GeoJSON standard) + #### Returns The updated `L.glify` instance it was called on --- ### `latitudeFirst()` -Sets the expecetd order of arrays in the `coordinates` array of GeoJSON passed to `options.data` to be `[lat, lng]` +Sets the expected order of arrays in the `coordinates` array of GeoJSON passed to `options.data` to be `[lat, lng]` (legacy format) + #### Returns The updated `L.glify` instance it was called on +--- +### `setCoordinateOrder(order)` +Sets the coordinate order for data parsing. + +**Parameters:** +- `order` `{String}` - `"lngFirst"` for WGS84/GeoJSON standard `[longitude, latitude]`, `"latFirst"` for legacy format `[latitude, longitude]` + +#### Returns +The updated `L.glify` instance it was called on + +--- +### `getCoordinateOrder()` +Gets the current coordinate order setting. + +#### Returns +`{String}` - `"lngFirst"` for WGS84/GeoJSON standard, `"latFirst"` for legacy format + --- ### `pointsInstances` All of the `L.glify.Points` instances @@ -199,6 +444,20 @@ All of the `L.glify.Lines` instances ### `shapesInstances` All of the `L.glify.Shapes` instances +--- +### `longitudeKey` +The array index for longitude coordinates. Defaults to `0` (WGS84/GeoJSON standard). + +--- +### `latitudeKey` +The array index for latitude coordinates. Defaults to `1` (WGS84/GeoJSON standard). + +--- +### `instances` +Returns an array of all active layer instances (`Points`, `Lines`, and `Shapes`). + +#### Returns +`Array` - All active layer instances ## Building diff --git a/package-lock.json b/package-lock.json index c1444c1..3d374f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,7 +54,7 @@ "ts-loader": "^9.5.1", "ts-shader-loader": "^2.0.2", "typescript": "^5.4.5", - "webpack": "^5.94.0", + "webpack": "^5.101.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" }, @@ -1353,10 +1353,11 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -1443,6 +1444,7 @@ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -1675,9 +1677,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -2126,148 +2128,163 @@ "dev": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -2319,13 +2336,15 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/abab": { "version": "2.0.6", @@ -2338,7 +2357,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", @@ -2354,9 +2374,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", "bin": { @@ -2385,6 +2405,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -2502,15 +2535,6 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2588,10 +2612,11 @@ } }, "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "dev": true, + "license": "ISC" }, "node_modules/are-we-there-yet": { "version": "2.0.0", @@ -2599,6 +2624,7 @@ "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", "dev": true, + "license": "ISC", "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -3253,6 +3279,7 @@ "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.17.0", @@ -3316,6 +3343,7 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -3417,6 +3445,7 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, + "license": "ISC", "bin": { "color-support": "bin.js" } @@ -3572,7 +3601,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -3640,34 +3670,6 @@ "webpack": "^5.1.0" } }, - "node_modules/copy-webpack-plugin/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, "node_modules/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3700,12 +3702,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/copy-webpack-plugin/node_modules/path-type": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", @@ -3718,25 +3714,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/copy-webpack-plugin/node_modules/slash": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", @@ -3966,6 +3943,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dev": true, + "license": "MIT", "dependencies": { "mimic-response": "^2.0.0" }, @@ -4101,7 +4079,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/depd": { "version": "2.0.0", @@ -4123,10 +4102,11 @@ } }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -4307,9 +4287,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", "dev": true, "license": "MIT", "dependencies": { @@ -5540,6 +5520,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -5832,6 +5829,7 @@ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -5839,6 +5837,19 @@ "node": ">= 8" } }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5901,6 +5912,7 @@ "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", "dev": true, + "license": "ISC", "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -6482,7 +6494,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/hasown": { "version": "2.0.2", @@ -7324,6 +7337,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -8491,6 +8505,7 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -8529,13 +8544,11 @@ } }, "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "ISC", "engines": { "node": ">=8" } @@ -8545,6 +8558,7 @@ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -8553,11 +8567,25 @@ "node": ">= 8" } }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8600,10 +8628,11 @@ "dev": true }, "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", - "dev": true + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", + "dev": true, + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -8643,6 +8672,7 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -8685,6 +8715,7 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "1" }, @@ -8928,6 +8959,7 @@ "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", "dev": true, + "license": "ISC", "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -10068,14 +10100,16 @@ } }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -10085,6 +10119,43 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/scope-analyzer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/scope-analyzer/-/scope-analyzer-2.1.2.tgz", @@ -10291,7 +10362,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/set-function-length": { "version": "1.2.2", @@ -10421,13 +10493,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, + "license": "MIT", "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -10951,6 +11025,7 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -10963,23 +11038,15 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/terser": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", - "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -10991,16 +11058,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -11029,6 +11097,7 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -11043,6 +11112,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11058,6 +11128,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -11242,7 +11313,8 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tree-dump": { "version": "1.0.1", @@ -11801,24 +11873,27 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "version": "5.101.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.0.tgz", + "integrity": "sha512-B4t+nJqytPeuZlHuIKTbalhljIFXeNRqrUGAQgTGlfOl2lXXKXw+yZu6bicycP+PUlM44CxBjCFD6aciKFT3LQ==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.14.0", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", + "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -11828,11 +11903,11 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", + "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -11933,59 +12008,6 @@ } } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-dev-server": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", @@ -12045,34 +12067,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, "node_modules/webpack-dev-server/node_modules/glob": { "version": "10.4.1", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", @@ -12095,12 +12089,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/webpack-dev-server/node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -12128,25 +12116,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", @@ -12161,6 +12130,16 @@ "node": ">=10.0.0" } }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -12183,15 +12162,6 @@ "node": ">=4.0" } }, - "node_modules/webpack/node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -12253,6 +12223,7 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -12313,6 +12284,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -12444,7 +12416,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", diff --git a/package.json b/package.json index f1934e6..134fd7d 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "leaflet.glify", "version": "3.3.1", "description": "web gl renderer plugin for leaflet", + "types": "dist/index.d.ts", "main": "dist/glify.js", "browser": "dist/glify-browser.js", "module": "dist/glify-browser.js", @@ -11,7 +12,8 @@ ], "scripts": { "test": "jest", - "build": "webpack --config webpack.config.js", + "build": "npm run build:types && webpack --config webpack.config.js", + "build:types": "tsc --declaration --declarationMap --outDir dist --rootDir src", "coverage": "jest --coverage --coverage-provider v8 && codecov", "serve": "webpack-dev-server --config webpack.config.dev.js --open", "prepublish-gh-pages": "webpack --config webpack.config.gh-pages.js", @@ -78,7 +80,7 @@ "ts-loader": "^9.5.1", "ts-shader-loader": "^2.0.2", "typescript": "^5.4.5", - "webpack": "^5.94.0", + "webpack": "^5.101.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.0.4" }, diff --git a/src/base-gl-layer.ts b/src/base-gl-layer.ts index 06f9fa2..3524d1e 100644 --- a/src/base-gl-layer.ts +++ b/src/base-gl-layer.ts @@ -1,65 +1,17 @@ import { LeafletMouseEvent, Map } from "leaflet"; -import { IColor } from "./color"; +import { IColor, IBaseGlLayerSettings, IShaderVariable, ColorCallback, SetupHoverCallback, EventCallback } from "./types-base"; import { IPixel } from "./pixel"; import { CanvasOverlay, ICanvasOverlayDrawEvent } from "./canvas-overlay"; import { notProperlyDefined } from "./errors"; import { MapMatrix } from "./map-matrix"; -export interface IShaderVariable { - type: "FLOAT"; - start?: number; - size: number; - normalize?: boolean; -} - -export type EventCallback = ( - e: LeafletMouseEvent, - feature: any -) => boolean | void; - -export type SetupHoverCallback = ( - map: Map, - hoverWait?: number, - immediate?: false -) => void; - -export interface IBaseGlLayerSettings { - data: any; - longitudeKey: number; - latitudeKey: number; - pane: string; - map: Map; - shaderVariables?: { - [name: string]: IShaderVariable; - }; - setupClick?: (map: Map) => void; - setupContextMenu?: (map: Map) => void; - setupHover?: SetupHoverCallback; - sensitivity?: number; - sensitivityHover?: number; - vertexShaderSource?: (() => string) | string; - fragmentShaderSource?: (() => string) | string; - canvas?: HTMLCanvasElement; - click?: EventCallback; - contextMenu?: EventCallback; - hover?: EventCallback; - hoverOff?: EventCallback; - color?: ColorCallback | IColor | string | number[] | null; - className?: string; - opacity?: number; - preserveDrawingBuffer?: boolean; - hoverWait?: number; -} - export const defaultPane = "overlayPane"; export const defaultHoverWait = 250; export const defaults: Partial = { pane: defaultPane, }; -export type ColorCallback = (featureIndex: number, feature: any) => IColor; - export abstract class BaseGlLayer< T extends IBaseGlLayerSettings = IBaseGlLayerSettings, > { @@ -98,15 +50,8 @@ export abstract class BaseGlLayer< return this.settings.pane ?? defaultPane; } - get className(): string { - return this.settings.className ?? ""; - } - - get map(): Map { - if (!this.settings.map) { - throw new Error(notProperlyDefined("settings.map")); - } - return this.settings.map; + get hoverWait(): number { + return this.settings.hoverWait ?? defaultHoverWait; } get sensitivity(): number { @@ -123,8 +68,48 @@ export abstract class BaseGlLayer< return this.settings.sensitivityHover; } - get hoverWait(): number { - return this.settings.hoverWait ?? defaultHoverWait; + get color(): ColorCallback | IColor | string | number[] | null { + return this.settings.color ?? null; + } + + get opacity(): number { + return this.settings.opacity ?? 0.5; + } + + get className(): string { + return this.settings.className ?? ""; + } + + get preserveDrawingBuffer(): boolean { + return this.settings.preserveDrawingBuffer ?? false; + } + + get vertexShaderSource(): (() => string) | string { + if (!this.settings.vertexShaderSource) { + throw new Error(notProperlyDefined("settings.vertexShaderSource")); + } + return this.settings.vertexShaderSource; + } + + get fragmentShaderSource(): (() => string) | string { + if (!this.settings.fragmentShaderSource) { + throw new Error(notProperlyDefined("settings.fragmentShaderSource")); + } + return this.settings.fragmentShaderSource; + } + + get shaderVariables(): { [name: string]: IShaderVariable } { + if (!this.settings.shaderVariables) { + throw new Error(notProperlyDefined("settings.shaderVariables")); + } + return this.settings.shaderVariables; + } + + get map(): Map { + if (!this.settings.map) { + throw new Error(notProperlyDefined("settings.map")); + } + return this.settings.map; } get longitudeKey(): number { @@ -141,20 +126,8 @@ export abstract class BaseGlLayer< return this.settings.latitudeKey; } - get opacity(): number { - if (typeof this.settings.opacity !== "number") { - throw new Error(notProperlyDefined("settings.opacity")); - } - return this.settings.opacity; - } - - get color(): ColorCallback | IColor | string | number[] | null { - return this.settings.color ?? null; - } - constructor(settings: Partial) { - this.settings = { ...defaults, ...settings }; - this.mapMatrix = new MapMatrix(); + this.settings = { ...BaseGlLayer.defaults, ...settings }; this.active = true; this.vertexShader = null; this.fragmentShader = null; @@ -162,11 +135,14 @@ export abstract class BaseGlLayer< this.matrix = null; this.vertices = null; this.vertexLines = null; + try { this.mapCenterPixels = this.map.project(this.map.getCenter(), 0); } catch (err) { this.mapCenterPixels = { x: -0, y: -0 }; } + + this.mapMatrix = new MapMatrix(); const preserveDrawingBuffer = Boolean(settings.preserveDrawingBuffer); const layer = (this.layer = new CanvasOverlay( (context: ICanvasOverlayDrawEvent) => { @@ -174,21 +150,35 @@ export abstract class BaseGlLayer< }, this.pane ).addTo(this.map)); + if (!layer.canvas) { throw new Error(notProperlyDefined("layer.canvas")); } + const canvas = (this.canvas = layer.canvas); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; canvas.style.position = "absolute"; + if (this.className) { canvas.className += " " + this.className; } + this.gl = (canvas.getContext("webgl2", { preserveDrawingBuffer }) ?? canvas.getContext("webgl", { preserveDrawingBuffer }) ?? canvas.getContext("experimental-webgl", { preserveDrawingBuffer, })) as WebGLRenderingContext; + + if (this.settings.setupClick) { + this.settings.setupClick(this.map); + } + if (this.settings.setupContextMenu) { + this.settings.setupContextMenu(this.map); + } + if (this.settings.setupHover) { + this.settings.setupHover(this.map, this.hoverWait); + } } abstract drawOnCanvas(context: ICanvasOverlayDrawEvent): this; diff --git a/src/index.ts b/src/index.ts index a8fc471..919d180 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,10 @@ import { LeafletMouseEvent, Map } from "leaflet"; -import { Lines, ILinesSettings } from "./lines"; -import { Points, IPointsSettings } from "./points"; -import { Shapes, IShapesSettings } from "./shapes"; +import { Lines } from "./lines"; +import { Points } from "./points"; +import { Shapes } from "./shapes"; import { debounce } from "./utils"; +import { IPointsSettings, ILinesSettings, IShapesSettings } from "./types"; import vertex from "./shader/vertex/default.glsl"; import dot from "./shader/fragment/dot.glsl"; @@ -13,6 +14,8 @@ import simpleCircle from "./shader/fragment/simple-circle.glsl"; import square from "./shader/fragment/square.glsl"; import polygon from "./shader/fragment/polygon.glsl"; +export * from "./types"; + const shader = { vertex, fragment: { @@ -26,8 +29,18 @@ const shader = { }; export class Glify { - longitudeKey = 1; - latitudeKey = 0; + /** + * Coordinate order follows the World Geodetic System (WGS84) standard + * as defined by the National Geospatial-Intelligence Agency (NGA): + * https://earth-info.nga.mil/php/download.php?file=coord-wgs84 + * + * This standard is adopted by GeoJSON specification: + * https://geojson.org/ + * + * Coordinates are always [longitude, latitude] in WGS84/GeoJSON + */ + longitudeKey = 0; // WGS84/GeoJSON standard: [longitude, latitude] + latitudeKey = 1; // WGS84/GeoJSON standard: [longitude, latitude] clickSetupMaps: Map[] = []; contextMenuSetupMaps: Map[] = []; hoverSetupMaps: Map[] = []; @@ -41,18 +54,43 @@ export class Glify { shapesInstances: Shapes[] = []; linesInstances: Lines[] = []; + /** + * Set coordinate order to [longitude, latitude] - WGS84/GeoJSON standard + * This is the default and recommended format + */ longitudeFirst(): this { this.longitudeKey = 0; this.latitudeKey = 1; return this; } + /** + * Set coordinate order to [latitude, longitude] - Legacy format + * Use only for data that doesn't follow WGS84/GeoJSON standards + */ latitudeFirst(): this { this.latitudeKey = 0; this.longitudeKey = 1; return this; } + getCoordinateOrder(): "latFirst" | "lngFirst" { + return this.longitudeKey === 0 ? "lngFirst" : "latFirst"; + } + + /** + * Set coordinate order for data parsing + * @param order - "lngFirst" for WGS84/GeoJSON standard [longitude, latitude] + * "latFirst" for legacy format [latitude, longitude] + */ + setCoordinateOrder(order: "latFirst" | "lngFirst"): this { + if (order === "lngFirst") { + return this.longitudeFirst(); + } else { + return this.latitudeFirst(); + } + } + get instances(): Array { return [ ...this.pointsInstances, @@ -66,8 +104,8 @@ export class Glify { setupClick: this.setupClick.bind(this), setupContextMenu: this.setupContextMenu.bind(this), setupHover: this.setupHover.bind(this), - latitudeKey: glify.latitudeKey, - longitudeKey: glify.longitudeKey, + latitudeKey: this.latitudeKey, + longitudeKey: this.longitudeKey, vertexShaderSource: () => { return this.shader.vertex; }, @@ -136,7 +174,7 @@ export class Glify { setupContextMenu(map: Map): void { if (this.contextMenuSetupMaps.includes(map)) return; - this.clickSetupMaps.push(map); + this.contextMenuSetupMaps.push(map); map.on("contextmenu", (e: LeafletMouseEvent) => { e.originalEvent.preventDefault(); // Prevent the default context menu from showing let hit; @@ -171,9 +209,25 @@ export class Glify { export const glify = new Glify(); export default glify; + if (typeof window !== "undefined" && window.L) { // @ts-expect-error exporting it to window window.L.glify = glify; // @ts-expect-error exporting it to window window.L.Glify = Glify; } + +// Export runtime classes and functions +export { Points } from "./points"; +export { Lines } from "./lines"; +export { Shapes } from "./shapes"; +export { LineFeatureVertices } from "./line-feature-vertices"; +export { CanvasOverlay } from "./canvas-overlay"; +export { BaseGlLayer } from "./base-gl-layer"; +export { MapMatrix } from "./map-matrix"; +export { + latLonToPixel, + pixelInCircle, + locationDistance, + debounce +} from "./utils"; diff --git a/src/lines.ts b/src/lines.ts index 51d872c..697528e 100644 --- a/src/lines.ts +++ b/src/lines.ts @@ -9,9 +9,8 @@ import { import { BaseGlLayer, - ColorCallback, - IBaseGlLayerSettings, } from "./base-gl-layer"; +import { IBaseGlLayerSettings, ColorCallback } from "./types-base"; import { ICanvasOverlayDrawEvent } from "./canvas-overlay"; import * as color from "./color"; import { LineFeatureVertices } from "./line-feature-vertices"; diff --git a/src/points.ts b/src/points.ts index fa4036b..3082343 100644 --- a/src/points.ts +++ b/src/points.ts @@ -5,8 +5,8 @@ import { Position, } from "geojson"; -import { BaseGlLayer, IBaseGlLayerSettings } from "./base-gl-layer"; -import { ICanvasOverlayDrawEvent } from "./canvas-overlay"; +import { BaseGlLayer } from "./base-gl-layer"; +import { IPointsSettings, IPointVertex, ICanvasOverlayDrawEvent } from "./types-base"; import * as Color from "./color"; import { LeafletMouseEvent, Map, Point, LatLng } from "leaflet"; import { IPixel } from "./pixel"; @@ -14,14 +14,6 @@ import { locationDistance, pixelInCircle } from "./utils"; import glify from "./index"; import { getChosenColor } from "./color"; -export interface IPointsSettings extends IBaseGlLayerSettings { - data: number[][] | FeatureCollection; - size?: ((i: number, latLng: LatLng | null) => number) | number | null; - eachVertex?: (pointVertex: IPointVertex) => void; - sensitivity?: number; - sensitivityHover?: number; -} - const defaults: Partial = { color: Color.random, opacity: 0.8, @@ -47,15 +39,6 @@ const defaults: Partial = { }, }; -export interface IPointVertex { - latLng: LatLng; - pixel: IPixel; - chosenColor: Color.IColor; - chosenSize: number; - key: string; - feature?: any; -} - export class Points extends BaseGlLayer { static defaults = defaults; static maps = []; diff --git a/src/shapes.ts b/src/shapes.ts index 267bd37..73bd59f 100644 --- a/src/shapes.ts +++ b/src/shapes.ts @@ -13,9 +13,8 @@ import { import { BaseGlLayer, - ColorCallback, - IBaseGlLayerSettings, } from "./base-gl-layer"; +import { IBaseGlLayerSettings, ColorCallback } from "./types-base"; import { ICanvasOverlayDrawEvent } from "./canvas-overlay"; import * as Color from "./color"; import { latLonToPixel } from "./utils"; diff --git a/src/tests/base-gl-layer.test.ts b/src/tests/base-gl-layer.test.ts index 9e702b4..5caf354 100644 --- a/src/tests/base-gl-layer.test.ts +++ b/src/tests/base-gl-layer.test.ts @@ -2,9 +2,8 @@ import { BaseGlLayer, defaultHoverWait, defaultPane, - EventCallback, - IBaseGlLayerSettings, } from "../base-gl-layer"; +import { EventCallback, IBaseGlLayerSettings } from "../types-base"; import { ICanvasOverlayDrawEvent } from "../canvas-overlay"; import { LatLng, LatLngBounds, LeafletMouseEvent, Map, Point } from "leaflet"; @@ -219,12 +218,10 @@ describe("BaseGlLayer", () => { describe("opacity", () => { describe("when settings.opacity is not defined", () => { - it("throws", () => { + it("returns default value", () => { const layer = getGlLayer(); delete layer.settings.opacity; - expect(() => { - layer.opacity; - }).toThrow(); + expect(layer.opacity).toBe(0.5); }); }); describe("when settings.opacity is defined", () => { diff --git a/src/tests/coordinate-order.test.ts b/src/tests/coordinate-order.test.ts new file mode 100644 index 0000000..4c307ce --- /dev/null +++ b/src/tests/coordinate-order.test.ts @@ -0,0 +1,365 @@ +import { Map } from "leaflet"; +import glify from "../index"; + +// Mock Leaflet map +const mockMap = { + on: jest.fn(), + addLayer: jest.fn(), + removeLayer: jest.fn(), + getCenter: jest.fn(() => ({ lat: 0, lng: 0 })), + project: jest.fn(() => ({ x: 0, y: 0 })), + getSize: jest.fn(() => ({ x: 800, y: 600 })), + latLngToLayerPoint: jest.fn(() => ({ x: 0, y: 0 })), + options: { + crs: { + code: "EPSG:3857" + } + } +} as unknown as Map; + +describe("Coordinate Order Types", () => { + beforeEach(() => { + glify.longitudeFirst(); + }); + + describe("Default WGS84 Compliance", () => { + it("should default to WGS84 standard [longitude, latitude] order", () => { + // This test will FAIL if someone changes the defaults to non-WGS84 + expect(glify.longitudeKey).toBe(0); + expect(glify.latitudeKey).toBe(1); + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + }); + + it("should maintain WGS84 compliance after instantiation", () => { + // Test that the default constructor maintains WGS84 compliance + const newGlify = new (glify.constructor as any)(); + expect(newGlify.longitudeKey).toBe(0); + expect(newGlify.latitudeKey).toBe(1); + expect(newGlify.getCoordinateOrder()).toBe("lngFirst"); + }); + + it("should reject invalid coordinate key assignments", () => { + // This test ensures coordinate keys can't be set to invalid values + // Currently the library doesn't validate assignments, but this test + // will catch if someone accidentally changes the defaults + + // Test that the current defaults are correct + expect(glify.longitudeKey).toBe(0); + expect(glify.latitudeKey).toBe(1); + + // Test that we can't accidentally set invalid keys that would break WGS84 + const originalLngKey = glify.longitudeKey; + const originalLatKey = glify.latitudeKey; + + // These assignments should not break WGS84 compliance + // This would be invalid + (glify as any).longitudeKey = 2; + // This would be invalid + (glify as any).latitudeKey = -1; + + // But the getCoordinateOrder method should still work correctly + // and the original WGS84 defaults should be restorable + // Reset to WGS84 standard + glify.longitudeFirst(); + expect(glify.longitudeKey).toBe(0); + expect(glify.latitudeKey).toBe(1); + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + }); + }); + + describe("GlifyCoordinateOrder type", () => { + it("should have correct coordinate order values", () => { + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + + glify.latitudeFirst(); + expect(glify.getCoordinateOrder()).toBe("latFirst"); + + // Reset back to WGS84 standard + glify.longitudeFirst(); + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + }); + + it("should only accept valid coordinate order values", () => { + // This test will catch if someone adds invalid coordinate orders + const validOrders = ["lngFirst", "latFirst"]; + const invalidOrder = "invalidOrder" as any; + + expect(validOrders).toContain("lngFirst"); + expect(validOrders).toContain("latFirst"); + expect(validOrders).not.toContain(invalidOrder); + }); + }); + + describe("setCoordinateOrder method", () => { + it("should set coordinate order to lngFirst (WGS84 standard)", () => { + glify.setCoordinateOrder("lngFirst"); + expect(glify.longitudeKey).toBe(0); + expect(glify.latitudeKey).toBe(1); + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + + // Verify this matches WGS84 standard + // First element = longitude + expect(glify.longitudeKey).toBe(0); + // Second element = latitude + expect(glify.latitudeKey).toBe(1); + }); + + it("should set coordinate order to latFirst (legacy format)", () => { + glify.setCoordinateOrder("latFirst"); + expect(glify.longitudeKey).toBe(1); + expect(glify.latitudeKey).toBe(0); + expect(glify.getCoordinateOrder()).toBe("latFirst"); + + // Verify this is the legacy format + // First element = latitude + expect(glify.latitudeKey).toBe(0); + // Second element = longitude + expect(glify.longitudeKey).toBe(1); + }); + + it("should maintain consistency between setCoordinateOrder and fluent methods", () => { + // Test that setCoordinateOrder and fluent methods are equivalent + glify.setCoordinateOrder("lngFirst"); + const lngFirstKeys = { lng: glify.longitudeKey, lat: glify.latitudeKey }; + + glify.longitudeFirst(); + const fluentLngFirstKeys = { lng: glify.longitudeKey, lat: glify.latitudeKey }; + + expect(lngFirstKeys).toEqual(fluentLngFirstKeys); + + glify.setCoordinateOrder("latFirst"); + const latFirstKeys = { lng: glify.longitudeKey, lat: glify.latitudeKey }; + + glify.latitudeFirst(); + const fluentLatFirstKeys = { lng: glify.longitudeKey, lat: glify.latitudeKey }; + + expect(latFirstKeys).toEqual(fluentLatFirstKeys); + }); + }); + + describe("IGlifyCoordinateConfig interface", () => { + it("should have correct structure", () => { + const config = { + longitudeKey: 0, + latitudeKey: 1, + order: "lngFirst" as const, + }; + + expect(config.longitudeKey).toBe(0); + expect(config.latitudeKey).toBe(1); + expect(config.order).toBe("lngFirst"); + }); + + it("should enforce WGS84 compliance in configuration", () => { + // This test ensures that WGS84 compliance is enforced + const wgs84Config = { + // WGS84 standard: longitude first + longitudeKey: 0, + // WGS84 standard: latitude second + latitudeKey: 1, + order: "lngFirst" as const, + }; + + const legacyConfig = { + // Legacy: longitude second + longitudeKey: 1, + // Legacy: latitude first + latitudeKey: 0, + order: "latFirst" as const, + }; + + // WGS84 config should be valid + expect(wgs84Config.longitudeKey).toBe(0); + expect(wgs84Config.latitudeKey).toBe(1); + + // Legacy config should be different from WGS84 + expect(legacyConfig.longitudeKey).not.toBe(0); + expect(legacyConfig.latitudeKey).not.toBe(1); + }); + }); + + describe("Coordinate order in layer creation", () => { + it("should use correct coordinate keys when creating points with WGS84 data", () => { + glify.setCoordinateOrder("lngFirst"); + + const points = glify.points({ + map: mockMap, + // [lng, lat] format - WGS84 standard + data: [[0, 0], [1, 1]], + size: 5, + }); + + // Verify WGS84 compliance is maintained + expect(points.longitudeKey).toBe(0); + expect(points.latitudeKey).toBe(1); + + // Test with [longitude=0, latitude=0] - WGS84 standard format + // [lng, lat] + const testCoordinate = [0, 0]; + // Should get longitude (index 0) + const lng = testCoordinate[points.longitudeKey]; + // Should get latitude (index 1) + const lat = testCoordinate[points.latitudeKey]; + + // With [0, 0] and lngKey=0, latKey=1: + // lng = testCoordinate[0] = 0 + // lat = testCoordinate[1] = 0 + expect(lng).toBe(0); + expect(lat).toBe(0); + + // Test with [longitude=1, latitude=1] to verify the pattern + // [lng, lat] + const testCoordinate2 = [1, 1]; + // Should get longitude (index 0) + const lng2 = testCoordinate2[points.longitudeKey]; + // Should get latitude (index 1) + const lat2 = testCoordinate2[points.latitudeKey]; + + // With [1, 1] and lngKey=0, latKey=1: + // lng2 = testCoordinate2[0] = 1 + // lat2 = testCoordinate2[1] = 1 + expect(lng2).toBe(1); + expect(lat2).toBe(1); + }); + + it("should use correct coordinate keys when creating lines with legacy data", () => { + glify.setCoordinateOrder("latFirst"); + + const lines = glify.lines({ + map: mockMap, + data: { + type: "FeatureCollection", + features: [{ + type: "Feature", + properties: {}, + geometry: { + type: "LineString", + // [lat, lng] format - legacy + coordinates: [[0, 0], [1, 1]] + } + }] + }, + weight: 2, + }); + + // Verify legacy format is handled correctly + expect(lines.longitudeKey).toBe(1); + expect(lines.latitudeKey).toBe(0); + + // Verify the data format matches the coordinate keys + // [lat, lng] + const testData = [0, 0]; + const lat = testData[lines.latitudeKey]; + const lng = testData[lines.longitudeKey]; + // latitude + expect(lat).toBe(0); + // longitude + expect(lng).toBe(0); + }); + + it("should maintain coordinate order consistency across different layer types", () => { + // Test that all layer types respect the same coordinate order + glify.setCoordinateOrder("lngFirst"); + + const points = glify.points({ + map: mockMap, + data: [[0, 0]], + size: 5, + }); + + const lines = glify.lines({ + map: mockMap, + data: { + type: "FeatureCollection", + features: [{ + type: "Feature", + properties: {}, + geometry: { + type: "LineString", + coordinates: [[0, 0], [1, 1]] + } + }] + }, + weight: 2, + }); + + const shapes = glify.shapes({ + map: mockMap, + data: { + type: "FeatureCollection", + features: [{ + type: "Feature", + properties: {}, + geometry: { + type: "Polygon", + coordinates: [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]] + } + }] + }, + }); + + // All layers should use the same coordinate order + expect(points.longitudeKey).toBe(lines.longitudeKey); + expect(points.longitudeKey).toBe(shapes.longitudeKey); + expect(points.latitudeKey).toBe(lines.latitudeKey); + expect(points.latitudeKey).toBe(shapes.latitudeKey); + + // And it should be WGS84 standard + expect(points.longitudeKey).toBe(0); + expect(points.latitudeKey).toBe(1); + }); + }); + + describe("WGS84 Standard Enforcement", () => { + it("should always default to WGS84 standard on new instances", () => { + // This test will FAIL if someone changes the default constructor + const freshGlify = new (glify.constructor as any)(); + expect(freshGlify.longitudeKey).toBe(0); + expect(freshGlify.latitudeKey).toBe(1); + expect(freshGlify.getCoordinateOrder()).toBe("lngFirst"); + }); + + it("should maintain WGS84 compliance after coordinate order changes", () => { + // Change to legacy format + glify.setCoordinateOrder("latFirst"); + expect(glify.getCoordinateOrder()).toBe("latFirst"); + + // Reset to WGS84 standard + glify.setCoordinateOrder("lngFirst"); + expect(glify.longitudeKey).toBe(0); + expect(glify.latitudeKey).toBe(1); + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + }); + + it("should reject invalid coordinate order values", () => { + // This test will catch if someone adds invalid coordinate orders + const validOrders = ["lngFirst", "latFirst"]; + + // Test that only valid orders are accepted + expect(validOrders).toContain("lngFirst"); + expect(validOrders).toContain("latFirst"); + + // Test that invalid orders are rejected (if validation is added) + const invalidOrder = "invalidOrder" as any; + expect(validOrders).not.toContain(invalidOrder); + + // Currently the library doesn't validate setCoordinateOrder input, + // but this test will catch if someone accidentally adds invalid coordinate orders + // or if the method signature changes unexpectedly + + // Test that the method signature is correct + expect(typeof glify.setCoordinateOrder).toBe("function"); + + // Test that valid orders work + expect(() => glify.setCoordinateOrder("lngFirst")).not.toThrow(); + expect(() => glify.setCoordinateOrder("latFirst")).not.toThrow(); + + // Test that the method returns the instance for chaining + expect(glify.setCoordinateOrder("lngFirst")).toBe(glify); + + // Reset to WGS84 standard + glify.longitudeFirst(); + expect(glify.getCoordinateOrder()).toBe("lngFirst"); + }); + }); +}); diff --git a/src/tests/index.test.ts b/src/tests/index.test.ts index 7adaef1..5ea906a 100644 --- a/src/tests/index.test.ts +++ b/src/tests/index.test.ts @@ -1,8 +1,11 @@ -import { Glify } from "../index"; -import { IPointsSettings, Points } from "../points"; -import { ILinesSettings, Lines } from "../lines"; -import { IShapesSettings, Shapes } from "../shapes"; -import { LatLng, LeafletMouseEvent, Map, Point } from "leaflet"; +import { Map } from "leaflet"; +import { IPointsSettings, ILinesSettings, IShapesSettings } from "../types-base"; +import { Points } from "../points"; +import { Lines } from "../lines"; +import { Shapes } from "../shapes"; +import { ICanvasOverlayDrawEvent } from "../canvas-overlay"; +import glify, { Glify } from "../index"; +import { LatLng, LeafletMouseEvent, Point } from "leaflet"; import { FeatureCollection, LineString, MultiPolygon } from "geojson"; type mouseEventFunction = (e: LeafletMouseEvent) => void; diff --git a/src/tests/points.test.ts b/src/tests/points.test.ts index 0a5181b..cc3e8cf 100644 --- a/src/tests/points.test.ts +++ b/src/tests/points.test.ts @@ -1,6 +1,7 @@ import { LatLng, LatLngBounds, Map, Point } from "leaflet"; import { FeatureCollection, Point as GeoPoint } from "geojson"; -import { IPointVertex, IPointsSettings, Points } from "../points"; +import { Points } from "../points"; +import { IPointVertex, IPointsSettings } from "../types-base"; import { ICanvasOverlayDrawEvent } from "../canvas-overlay"; function getPoints(settings?: Partial): Points { diff --git a/src/tests/shapes_interactive.test.ts b/src/tests/shapes_interactive.test.ts index 6addf44..1830998 100644 --- a/src/tests/shapes_interactive.test.ts +++ b/src/tests/shapes_interactive.test.ts @@ -2,7 +2,17 @@ import { Feature, FeatureCollection, Polygon } from "geojson"; import { LatLng, LeafletMouseEvent, Map, Point } from "leaflet"; import { IShapesSettings, Shapes } from "../shapes"; -jest.mock("../canvas-overlay"); +jest.mock("../canvas-overlay", () => { + return { + CanvasOverlay: jest.fn().mockImplementation(() => { + return { + addTo: jest.fn().mockReturnThis(), + canvas: document.createElement('canvas'), + redraw: jest.fn(), + }; + }), + }; +}); const mockFeatureCollection: FeatureCollection = { type: "FeatureCollection", diff --git a/src/types-base.ts b/src/types-base.ts new file mode 100644 index 0000000..924b674 --- /dev/null +++ b/src/types-base.ts @@ -0,0 +1,151 @@ +// Base type definitions for Leaflet.glify +// This file contains types that don't reference classes to avoid circular imports + +import { Map, LeafletMouseEvent } from "leaflet"; +import { Feature, FeatureCollection, LineString, MultiLineString, MultiPolygon, Point as GeoPoint } from "geojson"; + +// Base layer settings interface +export interface IBaseGlLayerSettings { + data: any; + longitudeKey: number; + latitudeKey: number; + pane: string; + map: Map; + shaderVariables?: { + [name: string]: IShaderVariable; + }; + setupClick?: (map: Map) => void; + setupContextMenu?: (map: Map) => void; + setupHover?: SetupHoverCallback; + sensitivity?: number; + sensitivityHover?: number; + vertexShaderSource?: (() => string) | string; + fragmentShaderSource?: (() => string) | string; + canvas?: HTMLCanvasElement; + click?: EventCallback; + contextMenu?: EventCallback; + hover?: EventCallback; + hoverOff?: EventCallback; + color?: ColorCallback | IColor | string | number[] | null; + className?: string; + opacity?: number; + preserveDrawingBuffer?: boolean; + hoverWait?: number; +} + +// Layer-specific settings interfaces +export interface IPointsSettings extends IBaseGlLayerSettings { + data: number[][] | FeatureCollection; + size?: ((i: number, latLng: any) => number) | number | null; + eachVertex?: (pointVertex: IPointVertex) => void; + sensitivity?: number; + sensitivityHover?: number; +} + +export interface ILinesSettings extends IBaseGlLayerSettings { + data: FeatureCollection; + weight: WeightCallback | number; + sensitivity?: number; + sensitivityHover?: number; + eachVertex?: (vertices: any) => void; +} + +export interface IShapesSettings extends IBaseGlLayerSettings { + border?: boolean; + borderOpacity?: number; + data: Feature | FeatureCollection | MultiPolygon; +} + +// Shader interface +export interface IGlifyShader { + vertex: string; + fragment: { + dot: string; + point: string; + puck: string; + simpleCircle: string; + square: string; + polygon: string; + }; +} + +// WebGL types +export interface IShaderVariable { + type: "FLOAT"; + start?: number; + size: number; + normalize?: boolean; +} + +export interface ICanvasOverlayDrawEvent { + canvas: HTMLCanvasElement; + bounds: any; + offset: any; + scale: number; + size: any; + zoomScale: number; + zoom: number; +} + +// Color and callback types +export interface IColor { + r: number; + g: number; + b: number; + a?: number; +} + +export type ColorCallback = (featureIndex: number, feature: any) => IColor; +export type WeightCallback = (i: number, feature: any) => number; +export type EventCallback = (e: LeafletMouseEvent, feature: any) => boolean | void; +export type SetupHoverCallback = (map: Map, hoverWait?: number, immediate?: false) => void; + +// Utility types +export interface IPixel { + x: number; + y: number; +} + +export interface IPointVertex { + latLng: any; + pixel: IPixel; + chosenColor: IColor; + chosenSize: number; + key: string; + feature?: any; +} + +// Coordinate and data types +export type GlifyLayerType = "points" | "lines" | "shapes"; +export type GlifyDataFormat = "Array" | "GeoJson.FeatureCollection"; +export type GlifyCoordinateOrder = "latFirst" | "lngFirst"; + +// Coordinate configuration interface +export interface IGlifyCoordinateConfig { + longitudeKey: number; + latitudeKey: number; + order: GlifyCoordinateOrder; +} + +// Event callback types +export type GlifyClickCallback = ( + e: LeafletMouseEvent, + feature: T, + xy?: { x: number; y: number } +) => boolean | void; + +export type GlifyHoverCallback = ( + e: LeafletMouseEvent, + feature: T, + xy?: { x: number; y: number } +) => boolean | void; + +export type GlifyHoverOffCallback = ( + e: LeafletMouseEvent, + feature: T +) => boolean | void; + +export type GlifyContextMenuCallback = ( + e: LeafletMouseEvent, + feature: T +) => boolean | void; diff --git a/src/types-glify.ts b/src/types-glify.ts new file mode 100644 index 0000000..cd1ddd6 --- /dev/null +++ b/src/types-glify.ts @@ -0,0 +1,50 @@ +// Glify interface definitions that reference classes +// This file imports the actual classes to ensure type consistency + +import { IBaseGlLayerSettings, IPointsSettings, ILinesSettings, IShapesSettings } from './types-base'; +import { BaseGlLayer } from './base-gl-layer'; +import { Points } from './points'; +import { Lines } from './lines'; +import { Shapes } from './shapes'; + +// Core glify interface +export interface IGlify { + longitudeKey: number; + latitudeKey: number; + clickSetupMaps: any[]; + contextMenuSetupMaps: any[]; + hoverSetupMaps: any[]; + shader: any; + + // Class constructors - these are the actual classes + Points: typeof Points; + Shapes: typeof Shapes; + Lines: typeof Lines; + + // Instance arrays - these contain actual instances + pointsInstances: Points[]; + shapesInstances: Shapes[]; + linesInstances: Lines[]; + + // Coordinate order methods + longitudeFirst(): this; + latitudeFirst(): this; + readonly instances: (Points | Lines | Shapes)[]; + + // Factory methods that return instances + points(settings: Partial): Points; + lines(settings: Partial): Lines; + shapes(settings: Partial): Shapes; + + // Setup methods + setupClick(map: any): void; + setupContextMenu(map: any): void; + setupHover(map: any, hoverWait?: number, immediate?: false): void; + + // Coordinate order methods + getCoordinateOrder(): any; + setCoordinateOrder(order: any): this; +} + +// Utility types that reference the classes +export type GlifyInstance = Points | Lines | Shapes; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..d95fb97 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,8 @@ +// Type definitions for Leaflet.glify +// This file re-exports all types from the split files + +// Re-export base types (no class references) +export * from './types-base'; + +// Re-export glify interface (with class references) +export * from './types-glify'; diff --git a/tsconfig.json b/tsconfig.json index ad4b2fc..73ef1a5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,12 @@ { "compilerOptions": { - "allowJs": true, + "allowJs": true, "allowSyntheticDefaultImports": true, "checkJs": false, "esModuleInterop": true, - // "declaration": true, - // "emitDeclarationOnly": true, - // "declarationMap": true, + "declaration": true, + "declarationMap": true, + "declarationDir": "./dist", "module": "esnext", "moduleResolution": "node", // "noEmit": true, @@ -18,5 +18,6 @@ "target": "es2018", "lib": ["es2019", "dom"] }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.glsl"], "exclude": ["node_modules", "**/*.json", "dist", "examples", "__coverage__"] }