From 94dbec246e8c702bb93093fd6e77ec679959b6c3 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 07:53:28 +0200 Subject: [PATCH 01/59] Incrementally update --- .eslintrc | 45 +- .husky/pre-commit | 1 + bench/README.md | 3 +- bench/index.js | 3 +- debug/index.html | 19 +- docs/API.md | 3 +- docs/EXAMPLES.md | 3 +- docs/MODES.md | 3 +- index.js | 36 - index.ts | 48 + package-lock.json | 5226 +++++++++------------------- package.json | 41 +- rollup.config.js | 30 +- src/{constants.js => constants.ts} | 0 src/options.js | 6 +- src/types/fast-deep-equal.d.ts | 1 + src/types/geojson-area.d.ts | 1 + src/types/geojson-flatten.d.ts | 1 + src/types/point-geometry.d.ts | 1 + src/types/types.ts | 17 + test/api.test.js | 2 +- test/direct_select.test.js | 18 +- test/draw_line_string.test.js | 8 +- test/draw_point.test.js | 8 +- test/draw_polygon.test.js | 8 +- test/interaction_events.test.js | 6 +- test/line_string.test.js | 16 +- test/options.test.js | 4 +- test/point.test.js | 16 +- test/polygon.test.js | 16 +- test/simple_select.test.js | 18 +- test/static.test.js | 10 +- tsconfig.json | 10 + tsconfig.tsbuildinfo | 1 + vite.config.js | 24 +- 35 files changed, 1874 insertions(+), 3779 deletions(-) create mode 100644 .husky/pre-commit delete mode 100644 index.js create mode 100644 index.ts rename src/{constants.js => constants.ts} (100%) create mode 100644 src/types/fast-deep-equal.d.ts create mode 100644 src/types/geojson-area.d.ts create mode 100644 src/types/geojson-flatten.d.ts create mode 100644 src/types/point-geometry.d.ts create mode 100644 src/types/types.ts create mode 100644 tsconfig.json create mode 100644 tsconfig.tsbuildinfo diff --git a/.eslintrc b/.eslintrc index a4ad190b..58422b7e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,46 +1,3 @@ { - "extends": [ - "mourner", - "plugin:import/recommended" - ], - "parser": "espree", - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 2020 - }, - "plugins": [ - "import" - ], - "globals": { - "document": true - }, - "rules": { - "no-duplicate-imports": "off", - "import/no-duplicates": "error", - "import/no-commonjs": "error", - - "indent": [2,2], - "array-bracket-spacing": "off", - "block-scoped-var": "error", - "consistent-return": "off", - "global-require": "off", - "key-spacing": "off", - "no-eq-null": "off", - "no-new": "off", - "no-var": "error", - "no-warning-comments": "error", - "object-curly-spacing": "off", - "prefer-arrow-callback": "error", - "prefer-const": "error", - "prefer-template": "error", - "quotes": "off", - "space-before-function-paren": "off", - "template-curly-spacing": "error", - "camelcase": 0, - "no-console": ["error", { "allow": ["warn", "error"] }] - }, - "env": { - "es6": true, - "browser": true - } + "parser": "@typescript-eslint/parser", } diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..72c4429b --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npm test diff --git a/bench/README.md b/bench/README.md index b014466b..a88b52ca 100644 --- a/bench/README.md +++ b/bench/README.md @@ -1,4 +1,5 @@ -# Benchmarks +Benchmarks +--- Benchmarks help us catch performance regressions and improve performance. diff --git a/bench/index.js b/bench/index.js index 13ffa60d..b84836d9 100644 --- a/bench/index.js +++ b/bench/index.js @@ -118,8 +118,7 @@ function createMap(options) { mapboxgl.accessToken = getAccessToken(); const map = new mapboxgl.Map(Object.assign({ - container: 'map', - style: 'mapbox://styles/mapbox/streets-v12' + container: 'map' }, options)); const draw = new MapboxDraw(options); diff --git a/debug/index.html b/debug/index.html index 72f6d3dc..319b8531 100644 --- a/debug/index.html +++ b/debug/index.html @@ -42,10 +42,9 @@ - - @@ -57,10 +56,10 @@ import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder'; import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css'; - import MapboxDraw from '../index.js'; + import MapboxDraw from '../index'; import '../dist/mapbox-gl-draw.css'; - import {getAccessToken} from './access_token_generated.js'; + import {getAccessToken} from './access_token_generated'; mapboxgl.accessToken = getAccessToken(); @@ -68,6 +67,7 @@ container: 'map', zoom: 1, center: [0, 0], + hash: true }); map.addControl(new MapboxGeocoder({ @@ -83,6 +83,8 @@ map.addControl(Draw, 'bottom-right'); map.on('load', () => { + map.setConfigProperty('basemap', 'theme', 'monochrome'); + // Add Draw to the map if it is inactive const addButton = document.getElementById('addBtn'); addButton.onclick = function () { @@ -99,15 +101,6 @@ map.removeControl(Draw); }; - // Toggle the style between dark and streets - const flipStyleButton = document.getElementById('flipStyleBtn'); - let currentStyle = 'streets-v9'; - flipStyleButton.onclick = function () { - const style = currentStyle === 'streets-v9' ? 'dark-v9' : 'streets-v9'; - map.setStyle(`mapbox://styles/mapbox/${style}`); - currentStyle = style; - }; - // toggle double click zoom const doubleClickZoom = document.getElementById('doubleClickZoom'); let doubleClickZoomOn = true; diff --git a/docs/API.md b/docs/API.md index 1010f0ed..18ce5d1b 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,4 +1,5 @@ -# API Reference +API Reference +--- To use Draw diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index d35152c6..8a4d384a 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -1,4 +1,5 @@ -# Examples +Examples +--- ## Styling diff --git a/docs/MODES.md b/docs/MODES.md index c48633c2..3273e197 100644 --- a/docs/MODES.md +++ b/docs/MODES.md @@ -1,4 +1,5 @@ -# Creating modes for Mapbox Draw +Creating modes for Mapbox Draw +--- In Mapbox Draw, modes are used to group sets of user interactions into one behavior. Internally Draw has the `draw_polygon` mode, which controls a bunch of interactions for drawing a polygon. Draw also has the `simple_select` mode which controls interactions when zero, one or many features are selected including transitioning to `direct_select` mode when a user's interactions imply that they want to do detailed edits of a single feature. diff --git a/index.js b/index.js deleted file mode 100644 index 99b8ba06..00000000 --- a/index.js +++ /dev/null @@ -1,36 +0,0 @@ -import runSetup from './src/setup.js'; -import setupOptions from './src/options.js'; -import setupAPI from './src/api.js'; -import modes from './src/modes/index.js'; -import * as Constants from './src/constants.js'; -import * as lib from './src/lib/index.js'; - -const setupDraw = function(options, api) { - options = setupOptions(options); - - const ctx = { - options - }; - - api = setupAPI(ctx, api); - ctx.api = api; - - const setup = runSetup(ctx); - - api.onAdd = setup.onAdd; - api.onRemove = setup.onRemove; - api.types = Constants.types; - api.options = options; - - return api; -}; - -function MapboxDraw(options) { - setupDraw(options, this); -} - -MapboxDraw.modes = modes; -MapboxDraw.constants = Constants; -MapboxDraw.lib = lib; - -export default MapboxDraw; diff --git a/index.ts b/index.ts new file mode 100644 index 00000000..6bd9d5df --- /dev/null +++ b/index.ts @@ -0,0 +1,48 @@ +import runSetup from './src/setup'; +import setupOptions from './src/options'; +import setupAPI from './src/api'; +import modes from './src/modes/index'; +import * as Constants from './src/constants'; +import * as lib from './src/lib/index'; +import type { Controls, DrawLayer } from './src/types/types' + +interface Options { + keybindings: boolean; + touchEnabled: boolean; + boxSelect: boolean; + clickBuffer: number; + touchBuffer: number; + controls: Controls; + displayControlsDefault: boolean; + styles: Array +} + +const setupDraw = (options: Options, api) => { + options = setupOptions(options); + + const ctx = { + options + }; + + api = setupAPI(ctx, api); + ctx.api = api; + + const setup = runSetup(ctx); + + api.onAdd = setup.onAdd; + api.onRemove = setup.onRemove; + api.types = Constants.types; + api.options = options; + + return api; +}; + +function MapboxDraw(options: Options) { + setupDraw(options, this); +} + +MapboxDraw.modes = modes; +MapboxDraw.constants = Constants; +MapboxDraw.lib = lib; + +export default MapboxDraw; diff --git a/package-lock.json b/package-lock.json index 0ce761c7..adf34bf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,41 +1,46 @@ { "name": "@mapbox/mapbox-gl-draw", - "version": "1.5.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mapbox/mapbox-gl-draw", - "version": "1.5.0", + "version": "2.0.0", "license": "ISC", "dependencies": { "@mapbox/geojson-area": "^0.2.2", "@mapbox/geojson-normalize": "^0.0.1", "@mapbox/point-geometry": "^1.1.0", "fast-deep-equal": "^3.1.3", - "nanoid": "^5.0.9" + "nanoid": "^5.1.2" }, "devDependencies": { "@mapbox/cloudfriend": "^8.1.0", "@mapbox/mapbox-gl-draw-static-mode": "^1.0.1", "@mapbox/mapbox-gl-geocoder": "^5.0.2", - "@rollup/plugin-commonjs": "^28.0.0", + "@rollup/plugin-commonjs": "^28.0.2", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-replace": "^6.0.1", - "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^12.1.2", "@turf/bbox-clip": "^7.0.0", "@turf/centroid": "^7.0.0", + "@types/geojson": "^7946.0.16", + "@typescript-eslint/parser": "^8.26.0", "eslint": "8.57.1", - "eslint-config-mourner": "3.0.0", - "eslint-plugin-import": "^2.28.1", - "mapbox-gl": "^3.4.0", + "husky": "^9.1.7", + "lint-staged": "^15.4.3", + "mapbox-gl": "^3.10.0", "mock-browser": "^0.92.14", "npm-run-all": "^4.1.5", + "prettier": "^3.5.3", "rollup": "^4.19.1", "sinon": "^19.0.2", "synthetic-dom-events": "0.3.0", - "vite": "^6.0.2" + "typescript": "^5.8.2", + "vite": "^6.0.2", + "vite-plugin-tsconfig-paths": "^1.4.1" }, "engines": { "node": "^18.0.0 || >=20.0.0" @@ -627,6 +632,8 @@ "version": "0.3.5", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -640,6 +647,8 @@ "version": "3.1.2", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=6.0.0" } @@ -648,6 +657,8 @@ "version": "1.2.1", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=6.0.0" } @@ -656,6 +667,8 @@ "version": "0.3.6", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -664,12 +677,16 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -678,7 +695,9 @@ "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@mapbox/cloudfriend": { "version": "8.2.0", @@ -975,25 +994,29 @@ } } }, - "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "node_modules/@rollup/plugin-typescript": { + "version": "12.1.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz", + "integrity": "sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==", "dev": true, "dependencies": { - "serialize-javascript": "^6.0.1", - "smob": "^1.0.0", - "terser": "^5.17.4" + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" }, "peerDependenciesMeta": { "rollup": { "optional": true + }, + "tslib": { + "optional": true } } }, @@ -1296,12 +1319,6 @@ "win32" ] }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -1462,8 +1479,7 @@ "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/geojson-vt": { "version": "3.2.5", @@ -1480,11 +1496,6 @@ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, - "node_modules/@types/json5": { - "version": "0.0.29", - "dev": true, - "license": "MIT" - }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -1536,8 +1547,9 @@ }, "node_modules/@types/resolve": { "version": "1.20.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true }, "node_modules/@types/responselike": { "version": "1.0.3", @@ -1557,6 +1569,151 @@ "@types/geojson": "*" } }, + "node_modules/@typescript-eslint/parser": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz", + "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", + "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz", + "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", + "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", + "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.26.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "dev": true, @@ -1601,6 +1758,21 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "dev": true, @@ -1628,79 +1800,45 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-buffer-byte-length": { + "node_modules/array-equal": { "version": "1.0.0", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/array-buffer-byte-length/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/array-buffer-byte-length/node_modules/is-array-buffer": { - "version": "3.0.1", + "node_modules/asn1": { + "version": "0.2.6", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "safer-buffer": "~2.1.0" } }, - "node_modules/array-buffer-byte-length/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/assert-plus": { + "version": "1.0.0", "dev": true, "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.8" } }, - "node_modules/array-equal": { - "version": "1.0.0", + "node_modules/asynckit": { + "version": "0.4.0", "dev": true, "license": "MIT" }, - "node_modules/array-includes": { - "version": "3.1.8", + "node_modules/available-typed-arrays": { + "version": "1.0.5", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, "engines": { "node": ">= 0.4" }, @@ -1708,499 +1846,557 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", + "node_modules/aws-sdk": { + "version": "2.1646.0", "dev": true, - "license": "MIT", + "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.6.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10.0.0" } }, - "node_modules/array.prototype.findlastindex/node_modules/es-shim-unscopables": { - "version": "1.0.2", + "node_modules/aws-sdk/node_modules/events": { + "version": "1.1.1", "dev": true, "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" + "engines": { + "node": ">=0.4.x" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", + "node_modules/aws-sdk/node_modules/ieee754": { + "version": "1.1.13", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "BSD-3-Clause" }, - "node_modules/array.prototype.flat/node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", + "node_modules/aws-sdk/node_modules/sax": { + "version": "1.2.1", "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "ISC" }, - "node_modules/array.prototype.flat/node_modules/es-abstract": { - "version": "1.22.2", + "node_modules/aws-sign2": { + "version": "0.7.0", "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "*" } }, - "node_modules/array.prototype.flat/node_modules/es-set-tostringtag": { - "version": "2.0.1", + "node_modules/aws4": { + "version": "1.11.0", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "tweetnacl": "^0.14.3" } }, - "node_modules/array.prototype.flat/node_modules/es-set-tostringtag/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/brace-expansion": { + "version": "1.1.11", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/array.prototype.flat/node_modules/get-intrinsic": { - "version": "1.2.1", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "fill-range": "^7.1.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/array.prototype.flat/node_modules/internal-slot": { - "version": "1.0.5", + "node_modules/buffer": { + "version": "4.9.2", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, - "node_modules/array.prototype.flat/node_modules/is-callable": { - "version": "1.2.7", + "node_modules/buffer-from": { + "version": "1.1.2", "dev": true, "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10.6.0" } }, - "node_modules/array.prototype.flat/node_modules/is-typed-array": { - "version": "1.1.12", + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", "dev": true, - "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.11" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/array.prototype.flat/node_modules/safe-array-concat": { - "version": "1.0.1", + "node_modules/call-bind": { + "version": "1.0.7", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { - "node": ">=0.4" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flat/node_modules/safe-regex-test": { - "version": "1.0.0", + "node_modules/call-bind/node_modules/function-bind": { + "version": "1.1.2", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flat/node_modules/safe-regex-test/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/callsites": { + "version": "3.1.0", "dev": true, "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/string.prototype.trimend": { - "version": "1.0.7", + "node_modules/camelcase-keys/node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chalk": { + "version": "2.4.2", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "node_modules/array.prototype.flat/node_modules/string.prototype.trimstart": { - "version": "1.0.7", + "node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "color-convert": "^1.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-buffer": { - "version": "1.0.0", + "node_modules/chalk/node_modules/color-convert": { + "version": "1.9.3", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, + "color-name": "1.1.3" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=4" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-buffer/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-byte-length": { - "version": "1.0.0", + "node_modules/cheap-ruler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cheap-ruler/-/cheap-ruler-4.0.0.tgz", + "integrity": "sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-byte-length/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-byte-offset": { - "version": "1.0.0", + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" + "mimic-response": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-byte-offset/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/color-convert": { + "version": "2.0.1", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=7.0.0" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length": { - "version": "1.0.4", + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "delayed-stream": "~1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.8" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/define-properties": { - "version": "1.1.4", + "node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/content-type-parser": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", "dev": true, "license": "MIT", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/es-abstract": { - "version": "1.20.1", + "node_modules/csscolorparser": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/cssom": { + "version": "0.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "0.2.37", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "cssom": "0.3.x" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/function.prototype.name": { - "version": "1.1.5", + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "ms": "^2.1.3" }, "engines": { - "node": ">= 0.4" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/get-intrinsic": { - "version": "1.1.2", + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, - "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/internal-slot": { - "version": "1.0.3", + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/is-callable": { - "version": "1.2.4", + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/is-typed-array": { - "version": "1.1.9", + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -2209,14 +2405,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/regexp.prototype.flags": { - "version": "1.4.3", + "node_modules/define-properties": { + "version": "1.2.1", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -2225,209 +2421,100 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/string.prototype.trimend": { - "version": "1.0.5", + "node_modules/delayed-stream": { + "version": "1.0.0", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat/node_modules/typed-array-length/node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat/node_modules/which-typed-array": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.4.0" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.3.1" } }, - "node_modules/array.prototype.flatmap/node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/earcut": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", + "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==", + "dev": true }, - "node_modules/array.prototype.flatmap/node_modules/es-abstract": { - "version": "1.22.2", + "node_modules/ecc-jsbn": { + "version": "0.1.2", "dev": true, "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, - "node_modules/array.prototype.flatmap/node_modules/es-set-tostringtag": { - "version": "2.0.1", + "node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "once": "^1.4.0" } }, - "node_modules/array.prototype.flatmap/node_modules/es-set-tostringtag/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array.prototype.flatmap/node_modules/get-intrinsic": { - "version": "1.2.1", + "node_modules/error-ex": { + "version": "1.3.2", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "is-arrayish": "^0.2.1" } }, - "node_modules/array.prototype.flatmap/node_modules/internal-slot": { - "version": "1.0.5", + "node_modules/es-define-property": { + "version": "1.0.0", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" } }, - "node_modules/array.prototype.flatmap/node_modules/is-callable": { - "version": "1.2.7", + "node_modules/es-errors": { + "version": "1.3.0", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flatmap/node_modules/is-typed-array": { - "version": "1.1.12", + "node_modules/es-to-primitive": { + "version": "1.2.1", "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.11" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2436,2633 +2523,633 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.flatmap/node_modules/safe-array-concat": { - "version": "1.0.1", + "node_modules/esbuild": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=0.4" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, - "node_modules/array.prototype.flatmap/node_modules/safe-regex-test": { - "version": "1.0.0", + "node_modules/escape-string-regexp": { + "version": "1.0.5", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.8.0" } }, - "node_modules/array.prototype.flatmap/node_modules/safe-regex-test/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/escodegen": { + "version": "1.14.3", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/string.prototype.trimend": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/array.prototype.flatmap/node_modules/string.prototype.trimstart": { - "version": "1.0.7", + "node_modules/escodegen/node_modules/estraverse": { + "version": "4.3.0", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-buffer": { - "version": "1.0.0", + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" }, "engines": { - "node": ">= 0.4" + "node": ">= 0.8.0" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-buffer/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-byte-length": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-byte-length/node_modules/is-typed-array": { - "version": "1.1.10", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-byte-offset/node_modules/is-typed-array": { - "version": "1.1.10", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/define-properties": { - "version": "1.1.4", + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "dev": true, - "license": "MIT", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/es-abstract": { - "version": "1.20.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/function.prototype.name": { - "version": "1.1.5", + "node_modules/eslint-scope": { + "version": "7.2.2", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/get-intrinsic": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/internal-slot": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" + "url": "https://opencollective.com/eslint" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/is-callable": { - "version": "1.2.4", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/is-typed-array": { - "version": "1.1.9", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", "dev": true, "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/regexp.prototype.flags": { - "version": "1.4.3", + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "esutils": "^2.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/string.prototype.trimend": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/typed-array-length/node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap/node_modules/which-typed-array": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice/node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice/node_modules/is-array-buffer": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice/node_modules/is-array-buffer/node_modules/get-intrinsic": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sdk": { - "version": "2.1646.0", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-sdk/node_modules/events": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/aws-sdk/node_modules/ieee754": { - "version": "1.1.13", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/aws-sdk/node_modules/sax": { - "version": "1.2.1", - "dev": true, - "license": "ISC" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "dev": true, - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/base-64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", - "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind/node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-keys/node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cheap-ruler": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cheap-ruler/-/cheap-ruler-4.0.0.tgz", - "integrity": "sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==", - "dev": true - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT" - }, - "node_modules/commondir": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/content-type-parser": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csscolorparser": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/cssom": { - "version": "0.3.8", - "dev": true, - "license": "MIT" - }, - "node_modules/cssstyle": { - "version": "0.2.37", - "dev": true, - "license": "MIT", - "dependencies": { - "cssom": "0.3.x" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "dev": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties/node_modules/define-data-property": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-properties/node_modules/get-intrinsic": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/earcut": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==", - "dev": true - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/available-typed-arrays": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/get-symbol-description": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/has-property-descriptors": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/has-proto": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-array-buffer": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-array-buffer/node_modules/get-intrinsic": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-array-buffer/node_modules/has-proto": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-callable": { - "version": "1.2.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-negative-zero": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/set-function-name": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag/node_modules/has-tostringtag": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-mourner": { - "version": "3.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", - "dev": true, - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.19.0", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/acorn": { - "version": "8.10.0", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/espree/node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.13.0", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fdir": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.0.tgz", - "integrity": "sha512-3oB133prH1o4j/L5lLW7uOCF1PlD+/It2L0eL/iAqWMB91RBbqTewABqxhj0ibBd90EEmWZq7ntIWzVaWcXTGQ==", - "dev": true, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "dev": true, - "license": "ISC" - }, - "node_modules/for-each": { - "version": "0.3.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name/node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name/node_modules/es-abstract": { - "version": "1.22.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.1", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name/node_modules/es-set-tostringtag": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "node": ">=6.0.0" } }, - "node_modules/function.prototype.name/node_modules/es-set-tostringtag/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", "dev": true, "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/get-intrinsic": { - "version": "1.2.1", + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/internal-slot": { - "version": "1.0.5", + "node_modules/eslint/node_modules/globals": { + "version": "13.19.0", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "type-fest": "^0.20.2" }, "engines": { - "node": ">= 0.4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/is-callable": { - "version": "1.2.7", + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", "dev": true, "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/is-typed-array": { - "version": "1.1.12", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.11" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/safe-array-concat": { - "version": "1.0.1", + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/safe-regex-test": { - "version": "1.0.0", + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/safe-regex-test/node_modules/get-intrinsic": { - "version": "1.2.0", + "node_modules/espree": { + "version": "9.6.1", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/function.prototype.name/node_modules/string.prototype.trimend": { - "version": "1.0.7", + "node_modules/espree/node_modules/acorn": { + "version": "8.10.0", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "bin": { + "acorn": "bin/acorn" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/function.prototype.name/node_modules/string.prototype.trimstart": { - "version": "1.0.7", + "node_modules/espree/node_modules/acorn-jsx": { + "version": "5.3.2", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-buffer": { - "version": "1.0.0", + "node_modules/esprima": { + "version": "4.0.1", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">= 0.4" + "node": ">=4" } }, - "node_modules/function.prototype.name/node_modules/typed-array-buffer/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/esquery": { + "version": "1.5.0", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "estraverse": "^5.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10" } }, - "node_modules/function.prototype.name/node_modules/typed-array-byte-length": { - "version": "1.0.0", + "node_modules/esrecurse": { + "version": "4.3.0", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "estraverse": "^5.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-byte-length/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/estraverse": { + "version": "5.3.0", "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-byte-offset": { - "version": "1.0.0", + "node_modules/estree-walker": { + "version": "2.0.2", "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-byte-offset/node_modules/is-typed-array": { - "version": "1.1.10", + "node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", "dev": true, "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.8.x" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length": { - "version": "1.0.4", + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/define-properties": { - "version": "1.1.4", + "node_modules/execa/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, - "license": "MIT", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/es-abstract": { - "version": "1.20.1", + "node_modules/extend": { + "version": "3.0.2", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "license": "MIT" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.6.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/function.prototype.name": { - "version": "1.1.5", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/get-intrinsic": { - "version": "1.1.2", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.13.0", + "dev": true, + "license": "ISC", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/internal-slot": { - "version": "1.0.3", + "node_modules/file-entry-cache": { + "version": "6.0.1", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">= 0.4" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/is-callable": { - "version": "1.2.4", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "to-regex-range": "^5.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/is-typed-array": { - "version": "1.1.9", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/regexp.prototype.flags": { - "version": "1.4.3", + "node_modules/flat-cache": { + "version": "3.0.4", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/string.prototype.trimend": { - "version": "1.0.5", + "node_modules/flatted": { + "version": "3.2.7", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.3", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "is-callable": "^1.1.3" } }, - "node_modules/function.prototype.name/node_modules/typed-array-length/node_modules/string.prototype.trimstart": { - "version": "1.0.5", + "node_modules/forever-agent": { + "version": "0.6.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 6" } }, - "node_modules/function.prototype.name/node_modules/which-typed-array": { - "version": "1.1.11", + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", "dev": true, "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, "node_modules/functions-have-names": { "version": "1.2.3", "dev": true, @@ -5084,6 +3171,18 @@ "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", "dev": true }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.2.4", "dev": true, @@ -5140,19 +3239,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-symbol-description/node_modules/get-intrinsic": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/getpass": { "version": "0.1.7", "dev": true, @@ -5196,35 +3282,6 @@ "node": ">=10.13.0" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globalthis/node_modules/define-properties": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gopd": { "version": "1.0.1", "dev": true, @@ -5236,19 +3293,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gopd/node_modules/get-intrinsic": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/got": { "version": "11.8.6", "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", @@ -5356,19 +3400,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-property-descriptors/node_modules/get-intrinsic": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-proto": { "version": "1.0.1", "dev": true, @@ -5467,7 +3498,31 @@ "resolve-alpn": "^1.0.0" }, "engines": { - "node": ">=10.19.0" + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" } }, "node_modules/iconv-lite": { @@ -5562,19 +3617,6 @@ "dev": true, "license": "ISC" }, - "node_modules/internal-slot": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/is-arguments": { "version": "1.1.1", "dev": true, @@ -5590,51 +3632,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer/node_modules/get-intrinsic": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer/node_modules/is-typed-array": { - "version": "1.1.10", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "dev": true, @@ -5692,20 +3689,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-data-view": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-date-object": { "version": "1.0.5", "dev": true, @@ -5728,6 +3711,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-generator-function": { "version": "1.0.10", "dev": true, @@ -5755,8 +3750,9 @@ }, "node_modules/is-module": { "version": "1.0.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true }, "node_modules/is-negative-zero": { "version": "2.0.2", @@ -5769,6 +3765,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-number-object": { "version": "1.0.7", "dev": true, @@ -5802,8 +3807,9 @@ }, "node_modules/is-reference": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "*" } @@ -5834,26 +3840,24 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-string": { - "version": "1.0.7", + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-symbol": { - "version": "1.0.4", + "node_modules/is-string": { + "version": "1.0.7", "dev": true, "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -5862,12 +3866,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typed-array": { - "version": "1.1.13", + "node_modules/is-symbol": { + "version": "1.0.4", "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "has-symbols": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5892,11 +3896,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isarray": { - "version": "2.0.5", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "dev": true, @@ -6074,12 +4073,107 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/lint-staged": { + "version": "15.4.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.4.3.tgz", + "integrity": "sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g==", + "dev": true, + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/lint-staged/node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/listr2": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, "node_modules/load-json-file": { "version": "4.0.0", "dev": true, @@ -6127,6 +4221,95 @@ "dev": true, "license": "MIT" }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -6178,11 +4361,6 @@ "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.10.0.tgz", "integrity": "sha512-YnQxjlthuv/tidcxGYU2C8nRDVXMlAHa3qFhuOJeX4AfRP72OMRBf9ApL+M+k5VWcAXi2fcNOUVgphknjLumjA==", "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "workspaces": [ - "src/style-spec", - "test/build/typings" - ], "dependencies": { "@mapbox/jsonlint-lines-primitives": "^2.0.2", "@mapbox/mapbox-gl-supported": "^3.0.0", @@ -6317,6 +4495,46 @@ "node": ">=8" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime-db": { "version": "1.52.0", "dev": true, @@ -6333,7 +4551,31 @@ "mime-db": "1.52.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mimic-response": { @@ -6397,9 +4639,10 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, "node_modules/murmurhash-js": { "version": "1.0.0", @@ -6587,6 +4830,33 @@ "which": "bin/which" } }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/nwmatcher": { "version": "1.4.4", "dev": true, @@ -6636,58 +4906,27 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", + "node_modules/once": { + "version": "1.4.0", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" + "wrappy": "1" } }, - "node_modules/object.values": { - "version": "1.2.0", + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/optionator": { @@ -6901,14 +5140,6 @@ "node": ">=4" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -6969,6 +5200,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", "dev": true, @@ -7049,14 +5295,6 @@ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", "dev": true }, - "node_modules/randombytes": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/read-pkg": { "version": "3.0.0", "dev": true, @@ -7158,22 +5396,6 @@ "node": ">=4" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/request": { "version": "2.88.2", "dev": true, @@ -7267,6 +5489,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/reusify": { "version": "1.0.4", "dev": true, @@ -7276,6 +5529,12 @@ "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, "node_modules/rimraf": { "version": "3.0.2", "dev": true, @@ -7351,23 +5610,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "dev": true, @@ -7387,22 +5629,6 @@ ], "license": "MIT" }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "dev": true, @@ -7413,22 +5639,6 @@ "dev": true, "license": "ISC" }, - "node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serialize-to-js": { "version": "3.1.2", "dev": true, @@ -7472,46 +5682,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/set-function-name": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name/node_modules/define-data-property": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name/node_modules/get-intrinsic": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "dev": true, @@ -7549,17 +5719,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel/node_modules/get-intrinsic": { - "version": "1.1.2", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "engines": { + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/sinon": { @@ -7580,15 +5749,39 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/smob": { - "version": "1.5.0", + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, - "license": "MIT" + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, "node_modules/source-map": { "version": "0.6.1", "dev": true, "license": "BSD-3-Clause", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -7607,6 +5800,8 @@ "version": "0.5.21", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7664,29 +5859,67 @@ "node": ">=0.10.0" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.3", + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/string.prototype.padend/node_modules/define-properties": { - "version": "1.1.4", + "node_modules/string.prototype.padend": { + "version": "3.1.3", "dev": true, "license": "MIT", "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -7748,19 +5981,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.padend/node_modules/get-intrinsic": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.padend/node_modules/internal-slot": { "version": "1.0.3", "dev": true, @@ -7816,52 +6036,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "dev": true, @@ -7881,6 +6055,18 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-indent": { "version": "2.0.0", "dev": true, @@ -7958,6 +6144,8 @@ "version": "5.31.1", "dev": true, "license": "BSD-2-Clause", + "optional": true, + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -7975,6 +6163,8 @@ "version": "8.12.0", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7993,6 +6183,18 @@ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", "dev": true }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tough-cookie": { "version": "2.5.0", "dev": true, @@ -8019,26 +6221,16 @@ "node": ">=8" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", + "node_modules/ts-api-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" + "engines": { + "node": ">=18.12" }, - "bin": { - "json5": "lib/cli.js" + "peerDependencies": { + "typescript": ">=4.8.4" } }, "node_modules/tslib": { @@ -8095,120 +6287,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-length/node_modules/has-proto": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset/node_modules/available-typed-arrays": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset/node_modules/has-proto": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=14.17" } }, - "node_modules/typed-array-length/node_modules/has-proto": { - "version": "1.0.3", + "node_modules/typescript-paths": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/typescript-paths/-/typescript-paths-1.5.1.tgz", + "integrity": "sha512-lYErSLCON2MSplVV5V/LBgD4UNjMgY3guATdFCZY2q1Nr6OZEu4q6zX/rYMsG1TaWqqQSszg6C9EU7AGWMDrIw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "typescript": "^4.7.2 || ^5" } }, "node_modules/unbox-primitive": { @@ -8260,21 +6358,6 @@ "which-typed-array": "^1.1.2" } }, - "node_modules/util/node_modules/define-properties": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/util/node_modules/es-abstract": { "version": "1.20.1", "dev": true, @@ -8328,19 +6411,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/util/node_modules/get-intrinsic": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/util/node_modules/internal-slot": { "version": "1.0.3", "dev": true, @@ -8543,6 +6613,18 @@ } } }, + "node_modules/vite-plugin-tsconfig-paths": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/vite-plugin-tsconfig-paths/-/vite-plugin-tsconfig-paths-1.4.1.tgz", + "integrity": "sha512-pGpvsPGDpiM5z7I9ZhBe7H2WAH0gAC2Lh55rM3pE+84V2q7qojNO28wdUl4i/M4XUfJcilhyucmbc9D7IKqpXA==", + "dev": true, + "dependencies": { + "typescript-paths": "^1.5.1" + }, + "peerDependencies": { + "vite": "*" + } + }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "dev": true, @@ -8631,58 +6713,68 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-typed-array": { - "version": "1.1.15", + "node_modules/word-wrap": { + "version": "1.2.5", "dev": true, "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/which-typed-array/node_modules/available-typed-arrays": { - "version": "1.0.7", + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/which-typed-array/node_modules/has-tostringtag": { - "version": "1.0.2", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/word-wrap": { - "version": "1.2.5", + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/wrappy": { @@ -8729,6 +6821,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", diff --git a/package.json b/package.json index aa232a93..34477bed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mapbox/mapbox-gl-draw", - "version": "1.5.0", + "version": "2.0.0", "engines": { "node": "^18.0.0 || >=20.0.0" }, @@ -35,52 +35,71 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.js --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.js --shallow", - "lint": "eslint index.js src test bench", + "lint": "eslint index.ts src test bench", "pretest": "npm run lint", "test": "node --test --import ./test/mock-browser.js", "coverage": "node --test --import ./test/mock-browser.js --experimental-test-coverage", "build-token": "node build/generate-access-token-script.js", "build": "rollup -c", "build-min": "rollup -c --environment MINIFY:true", + "tsc": "tsc", "prepublishOnly": "run-s build build-min", "watch": "rollup -c --watch", "watch-bench": "rollup -c bench/rollup.config.js --watch", "start-server": "vite --config vite.config.js", "start-bench": "run-p build-token watch watch-bench \"start-server --base . .\"", - "start": "run-p build-token start-server" + "start": "run-p build-token start-server", + "prepare": "husky" }, "devDependencies": { "@mapbox/cloudfriend": "^8.1.0", "@mapbox/mapbox-gl-draw-static-mode": "^1.0.1", "@mapbox/mapbox-gl-geocoder": "^5.0.2", - "@rollup/plugin-commonjs": "^28.0.0", + "@rollup/plugin-commonjs": "^28.0.2", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-replace": "^6.0.1", - "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^12.1.2", "@turf/bbox-clip": "^7.0.0", "@turf/centroid": "^7.0.0", + "@types/geojson": "^7946.0.16", + "@typescript-eslint/parser": "^8.26.0", "eslint": "8.57.1", - "eslint-config-mourner": "3.0.0", - "eslint-plugin-import": "^2.28.1", - "mapbox-gl": "^3.4.0", + "husky": "^9.1.7", + "lint-staged": "^15.4.3", + "mapbox-gl": "^3.10.0", "mock-browser": "^0.92.14", "npm-run-all": "^4.1.5", + "prettier": "^3.5.3", "rollup": "^4.19.1", "sinon": "^19.0.2", "synthetic-dom-events": "0.3.0", - "vite": "^6.0.2" + "typescript": "^5.8.2", + "vite": "^6.0.2", + "vite-plugin-tsconfig-paths": "^1.4.1" }, "dependencies": { "@mapbox/geojson-area": "^0.2.2", "@mapbox/geojson-normalize": "^0.0.1", "@mapbox/point-geometry": "^1.1.0", "fast-deep-equal": "^3.1.3", - "nanoid": "^5.0.9" + "nanoid": "^5.1.2" }, "files": [ "src", "index.js", "dist/mapbox-gl-draw*" - ] + ], + "lint-staged": { + "**/*.{js,ts}": [ + "eslint", + "prettier --write" + ] + }, + "prettier": { + "singleQuote": true, + "trailingComma": "none", + "arrowParens": "avoid", + "endOfLine": "auto" + } } diff --git a/rollup.config.js b/rollup.config.js index 2a271b7d..e0455fdb 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,34 +1,16 @@ -const {MINIFY} = process.env; +const { MINIFY } = process.env; const minified = MINIFY === 'true'; const outputFile = minified ? 'dist/mapbox-gl-draw.js' : 'dist/mapbox-gl-draw-unminified.js'; -import commonjs from '@rollup/plugin-commonjs'; -import resolve from '@rollup/plugin-node-resolve'; -import terser from '@rollup/plugin-terser'; +import typescript from '@rollup/plugin-typescript'; export default { - input: ['index.js'], + input: 'index.ts', output: { name: 'MapboxDraw', file: outputFile, - format: 'umd', - sourcemap: true, - indent: false + format: 'esm', // Ensure ESM output if using ES modules + sourcemap: true }, - treeshake: true, - plugins: [ - minified ? terser({ - ecma: 2020, - module: true, - }) : false, - resolve({ - browser: true, - preferBuiltins: true - }), - commonjs({ - // global keyword handling causes Webpack compatibility issues, so we disabled it: - // https://github.com/mapbox/mapbox-gl-js/pull/6956 - ignoreGlobal: true - }) - ], + plugins: [typescript()] }; diff --git a/src/constants.js b/src/constants.ts similarity index 100% rename from src/constants.js rename to src/constants.ts diff --git a/src/options.js b/src/options.js index 8e88928e..41b2fbff 100644 --- a/src/options.js +++ b/src/options.js @@ -1,7 +1,7 @@ -import * as Constants from './constants.js'; +import * as Constants from './constants'; -import styles from './lib/theme.js'; -import modes from './modes/index.js'; +import styles from './lib/theme'; +import modes from './modes/index'; const defaultOptions = { defaultMode: Constants.modes.SIMPLE_SELECT, diff --git a/src/types/fast-deep-equal.d.ts b/src/types/fast-deep-equal.d.ts new file mode 100644 index 00000000..f2ed3da5 --- /dev/null +++ b/src/types/fast-deep-equal.d.ts @@ -0,0 +1 @@ +declare module 'fast-deep-equal'; diff --git a/src/types/geojson-area.d.ts b/src/types/geojson-area.d.ts new file mode 100644 index 00000000..2dbcb518 --- /dev/null +++ b/src/types/geojson-area.d.ts @@ -0,0 +1 @@ +declare module '@mapbox/geojson-area'; diff --git a/src/types/geojson-flatten.d.ts b/src/types/geojson-flatten.d.ts new file mode 100644 index 00000000..cc1dd53a --- /dev/null +++ b/src/types/geojson-flatten.d.ts @@ -0,0 +1 @@ +declare module 'geojson-flatten'; diff --git a/src/types/point-geometry.d.ts b/src/types/point-geometry.d.ts new file mode 100644 index 00000000..1dba7786 --- /dev/null +++ b/src/types/point-geometry.d.ts @@ -0,0 +1 @@ +declare module '@mapbox/point-geometry'; diff --git a/src/types/types.ts b/src/types/types.ts new file mode 100644 index 00000000..175ba696 --- /dev/null +++ b/src/types/types.ts @@ -0,0 +1,17 @@ +import { modes, meta } from '../constants'; +import type { Layer } from 'mapbox-gl'; + +export interface Controls { + point: boolean; + line_string: boolean; + polygon: boolean; + trash: boolean; + combine_features: boolean + uncombine_features: boolean +} + +export interface DrawLayer extends Layer { + meta: typeof meta[keyof typeof meta]; + mode: typeof modes[keyof typeof modes]; + active: boolean; +} diff --git a/test/api.test.js b/test/api.test.js index 9956bee2..cfbcc743 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -4,7 +4,7 @@ import assert from 'node:assert/strict'; import {spy} from 'sinon'; import * as Constants from '../src/constants.js'; -import MapboxDraw from '../index.js'; +import MapboxDraw from '../index'; import createMap from './utils/create_map.js'; import getGeoJSON from './utils/get_geojson.js'; import {setupAfterNextRender} from './utils/after_next_render.js'; diff --git a/test/direct_select.test.js b/test/direct_select.test.js index 6a6ce6d6..89f8d946 100644 --- a/test/direct_select.test.js +++ b/test/direct_select.test.js @@ -5,15 +5,15 @@ import turfCentroid from '@turf/centroid'; import createSyntheticEvent from 'synthetic-dom-events'; import {spy} from 'sinon'; -import MapboxDraw from '../index.js'; -import click from './utils/mouse_click.js'; -import tap from './utils/touch_tap.js'; -import getGeoJSON from './utils/get_geojson.js'; -import createMap from './utils/create_map.js'; -import {setupAfterNextRender} from './utils/after_next_render.js'; -import makeMouseEvent from './utils/make_mouse_event.js'; -import makeTouchEvent from './utils/make_touch_event.js'; -import * as Constants from '../src/constants.js'; +import MapboxDraw from '../index'; +import click from './utils/mouse_click'; +import tap from './utils/touch_tap'; +import getGeoJSON from './utils/get_geojson'; +import createMap from './utils/create_map'; +import {setupAfterNextRender} from './utils/after_next_render'; +import makeMouseEvent from './utils/make_mouse_event'; +import makeTouchEvent from './utils/make_touch_event'; +import * as Constants from '../src/constants'; test('direct_select', async (t) => { const mapContainer = document.createElement('div'); diff --git a/test/draw_line_string.test.js b/test/draw_line_string.test.js index ee0a1fcf..a1023cf9 100644 --- a/test/draw_line_string.test.js +++ b/test/draw_line_string.test.js @@ -1,9 +1,9 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import MapboxDraw from '../index.js'; -import mouseClick from './utils/mouse_click.js'; -import touchTap from './utils/touch_tap.js'; -import createMap from './utils/create_map.js'; +import MapboxDraw from '../index'; +import mouseClick from './utils/mouse_click'; +import touchTap from './utils/touch_tap'; +import createMap from './utils/create_map'; import makeMouseEvent from './utils/make_mouse_event.js'; import makeTouchEvent from './utils/make_touch_event.js'; import drawLineStringModeObject from '../src/modes/draw_line_string.js'; diff --git a/test/draw_point.test.js b/test/draw_point.test.js index cf6caba9..7b283a34 100644 --- a/test/draw_point.test.js +++ b/test/draw_point.test.js @@ -1,9 +1,9 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import MapboxDraw from '../index.js'; -import mouseClick from './utils/mouse_click.js'; -import touchTap from './utils/touch_tap.js'; -import createMap from './utils/create_map.js'; +import MapboxDraw from '../index'; +import mouseClick from './utils/mouse_click'; +import touchTap from './utils/touch_tap'; +import createMap from './utils/create_map'; import makeMouseEvent from './utils/make_mouse_event.js'; import makeTouchEvent from './utils/make_touch_event.js'; import drawPointModeObject from '../src/modes/draw_point.js'; diff --git a/test/draw_polygon.test.js b/test/draw_polygon.test.js index 03b41695..f37c2dc3 100644 --- a/test/draw_polygon.test.js +++ b/test/draw_polygon.test.js @@ -1,9 +1,9 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import MapboxDraw from '../index.js'; -import createMap from './utils/create_map.js'; -import mouseClick from './utils/mouse_click.js'; -import touchTap from './utils/touch_tap.js'; +import MapboxDraw from '../index'; +import createMap from './utils/create_map'; +import mouseClick from './utils/mouse_click'; +import touchTap from './utils/touch_tap'; import makeMouseEvent from './utils/make_mouse_event.js'; import makeTouchEvent from './utils/make_touch_event.js'; import drawPolygonModeObject from '../src/modes/draw_polygon.js'; diff --git a/test/interaction_events.test.js b/test/interaction_events.test.js index 4a928394..49784682 100644 --- a/test/interaction_events.test.js +++ b/test/interaction_events.test.js @@ -3,9 +3,9 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; -import MapboxDraw from '../index.js'; -import click from './utils/mouse_click.js'; -import createMap from './utils/create_map.js'; +import MapboxDraw from '../index'; +import click from './utils/mouse_click'; +import createMap from './utils/create_map'; import { setupAfterNextRender } from './utils/after_next_render.js'; import makeMouseEvent from './utils/make_mouse_event.js'; diff --git a/test/line_string.test.js b/test/line_string.test.js index 9e53b5d1..6f052e4e 100644 --- a/test/line_string.test.js +++ b/test/line_string.test.js @@ -1,14 +1,14 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import {spy} from 'sinon'; -import Feature from '../src/feature_types/feature.js'; -import LineString from '../src/feature_types/line_string.js'; -import MapboxDraw from '../index.js'; -import createFeature from './utils/create_feature.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; -import createMockCtx from './utils/create_mock_feature_context.js'; -import {drawGeometry} from './utils/draw_geometry.js'; -import createMap from './utils/create_map.js'; +import Feature from '../src/feature_types/feature'; +import LineString from '../src/feature_types/line_string'; +import MapboxDraw from '../index'; +import createFeature from './utils/create_feature'; +import getPublicMemberKeys from './utils/get_public_member_keys'; +import createMockCtx from './utils/create_mock_feature_context'; +import {drawGeometry} from './utils/draw_geometry'; +import createMap from './utils/create_map'; test('LineString constructor and API', () => { const rawLine = createFeature('line'); diff --git a/test/options.test.js b/test/options.test.js index aa256964..7d2a53d9 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -5,8 +5,8 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import {fileURLToPath} from 'url'; -import MapboxDraw from '../index.js'; -import modes from '../src/modes/index.js'; +import MapboxDraw from '../index'; +import modes from '../src/modes/index'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const styleWithSourcesFixture = JSON.parse(fs.readFileSync(path.join(__dirname, './fixtures/style_with_sources.json'))); diff --git a/test/point.test.js b/test/point.test.js index 815824fc..c513a264 100644 --- a/test/point.test.js +++ b/test/point.test.js @@ -1,14 +1,14 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import {spy} from 'sinon'; -import Feature from '../src/feature_types/feature.js'; -import Point from '../src/feature_types/point.js'; -import MapboxDraw from '../index.js'; -import createFeature from './utils/create_feature.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; -import createMockCtx from './utils/create_mock_feature_context.js'; -import {drawGeometry} from './utils/draw_geometry.js'; -import createMap from './utils/create_map.js'; +import Feature from '../src/feature_types/feature'; +import Point from '../src/feature_types/point'; +import MapboxDraw from '../index'; +import createFeature from './utils/create_feature'; +import getPublicMemberKeys from './utils/get_public_member_keys'; +import createMockCtx from './utils/create_mock_feature_context'; +import {drawGeometry} from './utils/draw_geometry'; +import createMap from './utils/create_map'; test('Point constructor and API', () => { const rawPoint = createFeature('point'); diff --git a/test/polygon.test.js b/test/polygon.test.js index 5ebf2680..4b7344e4 100644 --- a/test/polygon.test.js +++ b/test/polygon.test.js @@ -1,14 +1,14 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import {spy} from 'sinon'; -import Feature from '../src/feature_types/feature.js'; -import Polygon from '../src/feature_types/polygon.js'; -import MapboxDraw from '../index.js'; -import createFeature from './utils/create_feature.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; -import createMockCtx from './utils/create_mock_feature_context.js'; -import {drawGeometry} from './utils/draw_geometry.js'; -import createMap from './utils/create_map.js'; +import Feature from '../src/feature_types/feature'; +import Polygon from '../src/feature_types/polygon'; +import MapboxDraw from '../index'; +import createFeature from './utils/create_feature'; +import getPublicMemberKeys from './utils/get_public_member_keys'; +import createMockCtx from './utils/create_mock_feature_context'; +import {drawGeometry} from './utils/draw_geometry'; +import createMap from './utils/create_map'; test('Polygon constructor and API', () => { const rawPolygon = createFeature('polygon'); diff --git a/test/simple_select.test.js b/test/simple_select.test.js index b82132c1..f0e0edaa 100644 --- a/test/simple_select.test.js +++ b/test/simple_select.test.js @@ -4,15 +4,15 @@ import assert from 'node:assert/strict'; import createSyntheticEvent from 'synthetic-dom-events'; import {spy} from 'sinon'; -import MapboxDraw from '../index.js'; -import {setupAfterNextRender} from './utils/after_next_render.js'; -import makeMouseEvent from './utils/make_mouse_event.js'; -import mouseClick from './utils/mouse_click.js'; -import makeTouchEvent from './utils/make_touch_event.js'; -import getGeoJSON from './utils/get_geojson.js'; -import createMap from './utils/create_map.js'; -import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; -import { TAP_INTERVAL, TAP_TOLERANCE } from '../src/lib/is_tap.js'; +import MapboxDraw from '../index'; +import {setupAfterNextRender} from './utils/after_next_render'; +import makeMouseEvent from './utils/make_mouse_event'; +import mouseClick from './utils/mouse_click'; +import makeTouchEvent from './utils/make_touch_event'; +import getGeoJSON from './utils/get_geojson'; +import createMap from './utils/create_map'; +import createMockDrawModeContext from './utils/create_mock_draw_mode_context'; +import { TAP_INTERVAL, TAP_TOLERANCE } from '../src/lib/is_tap'; test('simple_select', async (t) => { const context = createMockDrawModeContext(); diff --git a/test/static.test.js b/test/static.test.js index a44b4324..5de681fd 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -4,11 +4,11 @@ import assert from 'node:assert/strict'; import StaticMode from '@mapbox/mapbox-gl-draw-static-mode'; import {spy} from 'sinon'; -import MapboxDraw from '../index.js'; -import {setupAfterNextRender} from './utils/after_next_render.js'; -import makeMouseEvent from './utils/make_mouse_event.js'; -import getGeoJSON from './utils/get_geojson.js'; -import createMap from './utils/create_map.js'; +import MapboxDraw from '../index'; +import {setupAfterNextRender} from './utils/after_next_render'; +import makeMouseEvent from './utils/make_mouse_event'; +import getGeoJSON from './utils/get_geojson'; +import createMap from './utils/create_map'; test('static', async (t) => { const map = createMap(); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..398bf53d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "Node", + "strict": true, + "esModuleInterop": true, + "declaration": true + } +} diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo new file mode 100644 index 00000000..804e25df --- /dev/null +++ b/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./src/constants.ts","./src/types/fast-deep-equal.d.ts","./src/types/geojson-area.d.ts","./src/types/geojson-flatten.d.ts","./src/types/point-geometry.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/globals.global.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/keyv/src/index.d.ts","./node_modules/@types/http-cache-semantics/index.d.ts","./node_modules/@types/responselike/index.d.ts","./node_modules/@types/cacheable-request/index.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/geojson/index.d.ts","./node_modules/@types/geojson-vt/index.d.ts","./node_modules/@types/json5/index.d.ts","./node_modules/@types/keyv/index.d.ts","./node_modules/@types/mapbox__point-geometry/index.d.ts","./node_modules/@types/pbf/index.d.ts","./node_modules/@mapbox/point-geometry/index.d.ts","./node_modules/@types/mapbox__vector-tile/index.d.ts","./node_modules/@types/minimist/index.d.ts","./node_modules/@types/normalize-package-data/index.d.ts","./node_modules/@types/resolve/index.d.ts","./node_modules/@types/supercluster/index.d.ts"],"fileIdsList":[[98],[68,71,97,98,105,106,107,108],[98,111],[68,98,105],[52,98,111,116],[53,98],[56,98],[57,62,98],[58,68,69,76,86,97,98],[58,59,68,76,98],[60,98],[61,62,69,77,98],[62,86,94,98],[63,65,68,76,98],[64,98],[65,66,98],[67,68,98],[68,98],[68,69,70,86,97,98],[68,69,70,86,89,98],[98,102],[71,76,86,97,98],[68,69,71,72,76,86,94,97,98],[71,73,86,94,97,98],[53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104],[68,74,98],[75,97,98],[65,68,76,86,98],[77,98],[78,98],[56,79,98],[80,96,98,102],[81,98],[82,98],[68,83,84,98],[83,85,98,100],[68,86,87,88,89,98],[86,88,98],[86,87,98],[89,98],[90,98],[68,92,93,98],[92,93,98],[62,76,86,94,98],[95,98],[76,96,98],[57,71,82,97,98],[62,98],[86,98,99],[98,100],[98,101],[57,62,68,70,79,86,97,98,100,102],[86,98,103],[71,86,98,105]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"092c2bfe125ce69dbb1223c85d68d4d2397d7d8411867b5cc03cec902c233763","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},"1b60eb59d9f48d6eee9d0402b286824b926bee768ec2f01755e926193a29f7f0","d2b46f22255daef82ebf0aa0d2028ea163739ff6b21dbaf31cf748864bebe1f4","f6e324ff4a8b9d7755aebb679dadcc5dbab5ae72b8c4436f7a541188e2c5a890","8cd02a0c1fa163d043a6a5444c412db2b6cf88228739580ed80b922949acec00","d0e5c906b91d9dd11dd5d9a61f82cd5b9a4f36d6b7514cc9481f3e6ead4a6946",{"version":"9122ed7070e054b73ebab37c2373a196def2d90e7d1a9a7fcd9d46b0e51fae78","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"77f0b5c6a193a699c9f7d7fb0578e64e562d271afa740783665d2a827104a873","affectsGlobalScope":true,"impliedFormat":1},{"version":"21a167fec8f933752fb8157f06d28fab6817af3ad9b0bdb1908a10762391eab9","impliedFormat":1},{"version":"002d6d5f044365b3fbfba0ba9be3bb57cac09b81547c8df4b0795755d2081d90","affectsGlobalScope":true,"impliedFormat":1},{"version":"0c0cee62cb619aed81133b904f644515ba3064487002a7da83fd8aa07b1b4abd","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"c4cfc9a6e2ebb8bc8c0e2392dfc4056993ced3b35069ebf132ac18ca7a562881","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"75ecef44f126e2ae018b4abbd85b6e8a2e2ba1638ebec56cc64274643ce3567b","impliedFormat":1},{"version":"f30bb836526d930a74593f7b0f5c1c46d10856415a8f69e5e2fc3db80371e362","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"bae4ea23beb8397755b935cb84d3cdc6cdb0b1b4a329b90de9fc6c8774d71994","affectsGlobalScope":true,"impliedFormat":1},{"version":"cec36af22f514322f870e81d30675c78df82ae8bf4863f5fd4e4424c040c678d","impliedFormat":1},{"version":"df36874d9e56aff601e921c4b3971d37cf66d14f6455935ce821e6cad13b1823","impliedFormat":1},{"version":"68915895d4a136df5cf5f90aaa41d8e1e47ec047e7781a150b5d0cf273dbb7a9","impliedFormat":1},{"version":"acfbb5aaef964e1d441f961a1846197f03241dba3c63b1e4d1903684888ef465","impliedFormat":1},{"version":"09416dd69576b03a3f485adf329a02f043e4a481e060ef5b208194e488d31fd9","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e8b18c6385ff784228a6f369694fcf1a6b475355ba89090a88de13587a9391d5","affectsGlobalScope":true,"impliedFormat":1},{"version":"76527127c8b749bee5977408861ce3ee56ec19ddcea8704c628f98ca610283e6","impliedFormat":1},{"version":"a907bf91df26df2400858ef75f749498fb5cf00062bf90a737ac3949cc07978d","impliedFormat":1},{"version":"cb92bc2e42b261e4299025756f1beb826b3d9666a3f0d46f8a7254ca512f57e4","impliedFormat":1},{"version":"cb4f3f03480e1727eae46400606cecaa97f550186ff8fa909ebc00db4180531b","impliedFormat":1},{"version":"b3624aed92dab6da8484280d3cb3e2f4130ec3f4ef3f8201c95144ae9e898bb6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"d1a78a3c5708807e8de3e399f91df4797c62e44b02195eefc2209b2e713e54ee","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"556bf5c36deb62cffa1bf697c1789fe008ec82db0273025001db66732714e9d9","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"806ef4cac3b3d9fa4a48d849c8e084d7c72fcd7b16d76e06049a9ed742ff79c0","affectsGlobalScope":true,"impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"0830071706fa0e477fb5e95f0955cc1062b5948b146b7d4e03a126f12ad6085f","impliedFormat":1},{"version":"970a90f76d4d219ad60819d61f5994514087ba94c985647a3474a5a3d12714ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"664d8f2d59164f2e08c543981453893bc7e003e4dfd29651ce09db13e9457980","impliedFormat":1},{"version":"4c8525f256873c7ba3135338c647eaf0ca7115a1a2805ae2d0056629461186ce","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"bfe39beb986d2a2e512c091cbe924f1c415bc65de54de0e2f6a0dc6f84c183d9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2d526e6f21d8cc66ac11ada32874e95ae88d870c6c9d3d9d4e03b1d1f9ad7b8e","impliedFormat":1},{"version":"06d7c42d256f0ce6afe1b2b6cfbc97ab391f29dadb00dd0ae8e8f23f5bc916c3","impliedFormat":1},{"version":"ec4bd1b200670fb567920db572d6701ed42a9641d09c4ff6869768c8f81b404c","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"d2ec52f565f0570e90b659811347bd689f8c6039b11eaaccd0f243759d46da6e","impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a12806a1bde5e9f137bb79728d87a4ceaedf04e95efc9967d3288a3c252d9a7b","impliedFormat":1},{"version":"42baf4ca38c38deaf411ea73f37bc39ff56c6e5c761a968b64ac1b25c92b5cd8","impliedFormat":1},{"version":"d7dbe0ad36bdca8a6ecf143422a48e72cc8927bab7b23a1a2485c2f78a7022c6","impliedFormat":1},{"version":"8718fa41d7cf4aa91de4e8f164c90f88e0bf343aa92a1b9b725a9c675c64e16b","impliedFormat":1},{"version":"f992cd6cc0bcbaa4e6c810468c90f2d8595f8c6c3cf050c806397d3de8585562","impliedFormat":1},{"version":"785b9d575b49124ce01b46f5b9402157c7611e6532effa562ac6aebec0074dfc","impliedFormat":1},{"version":"d30e67059f5c545c5f8f0cc328a36d2e03b8c4a091b4301bc1d6afb2b1491a3a","impliedFormat":1},{"version":"37550007de426cbbb418582008deae1a508935eaebbd4d41e22805ad3b485ad4","impliedFormat":1},{"version":"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","impliedFormat":1},{"version":"fec943fdb3275eb6e006b35e04a8e2e99e9adf3f4b969ddf15315ac7575a93e4","impliedFormat":1},{"version":"ae4cda96b058f20db053c1f57e51257d1cffff9c0880326d2b8129ade5363402","impliedFormat":1},{"version":"12115a2a03125cb3f600e80e7f43ef57f71a2951bb6e60695fb00ac8e12b27f3","impliedFormat":1},{"version":"59ffd1f821bf240bbd89c9a10fa2fdaec9716bc292e847864efb7ccecd976d5c","impliedFormat":99},{"version":"02f7c65c690af708e9da6b09698c86d34b6b39a05acd8288a079859d920aea9f","impliedFormat":1},{"version":"fbca5ffaebf282ec3cdac47b0d1d4a138a8b0bb32105251a38acb235087d3318","impliedFormat":1},{"version":"22293bd6fa12747929f8dfca3ec1684a3fe08638aa18023dd286ab337e88a592","impliedFormat":1},{"version":"8baa5d0febc68db886c40bf341e5c90dc215a90cd64552e47e8184be6b7e3358","impliedFormat":1},{"version":"e3913b35c221b4468658743d6496b83323c895f8e5b566c48d8844c01bf24738","impliedFormat":1}],"root":[[48,52]],"options":{"esModuleInterop":true,"jsx":4,"strict":true},"referencedMap":[[117,1],[109,2],[110,1],[112,3],[111,1],[107,1],[113,1],[114,4],[115,1],[118,5],[119,1],[53,6],[54,6],[56,7],[57,8],[58,9],[59,10],[60,11],[61,12],[62,13],[63,14],[64,15],[65,16],[66,16],[67,17],[68,18],[69,19],[70,20],[55,21],[104,1],[71,22],[72,23],[73,24],[105,25],[74,26],[75,27],[76,28],[77,29],[78,30],[79,31],[80,32],[81,33],[82,34],[83,35],[84,35],[85,36],[86,37],[88,38],[87,39],[89,40],[90,41],[91,1],[92,42],[93,43],[94,44],[95,45],[96,46],[97,47],[98,48],[99,49],[100,50],[101,51],[102,52],[103,53],[120,1],[116,1],[121,1],[108,54],[122,3],[106,18],[46,1],[47,1],[8,1],[10,1],[9,1],[2,1],[11,1],[12,1],[13,1],[14,1],[15,1],[16,1],[17,1],[18,1],[3,1],[19,1],[20,1],[4,1],[21,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[1,1],[45,1],[48,1],[49,1],[50,1],[51,1],[52,1]],"semanticDiagnosticsPerFile":[[55,[{"start":2311,"length":11,"messageText":"Subsequent variable declarations must have the same type. Variable 'AbortSignal' must be of type '{ new (): AbortSignal; prototype: AbortSignal; abort(reason?: any): AbortSignal; any(signals: AbortSignal[]): AbortSignal; timeout(milliseconds: number): AbortSignal; }', but here has type '{ new (): AbortSignal; prototype: AbortSignal; }'.","category":1,"code":2403,"relatedInformation":[{"file":"./node_modules/typescript/lib/lib.dom.d.ts","start":69084,"length":11,"messageText":"'AbortSignal' was also declared here.","category":3,"code":6203}]}]],[75,[{"start":3888,"length":7,"messageText":"Overload signatures must all be optional or required.","category":1,"code":2386}]],[118,[{"start":456,"length":5,"messageText":"Cannot use namespace 'Point' as a type.","category":1,"code":2709}]]],"version":"5.8.2"} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index 02991154..9a000cd0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,17 +1,9 @@ -export default { - root: 'debug/', - base: '/debug/', - envPrefix: 'MAPBOX_', - server: { - host: '0.0.0.0', - port: 9967, - strictPort: true, - }, - optimizeDeps: { - esbuildOptions: { - define: { - global: 'globalThis' - } - } +import { defineConfig } from 'vite'; +import tsconfigPaths from 'vite-plugin-tsconfig-paths'; + +export default defineConfig({ + plugins: [tsconfigPaths()], + build: { + target: 'esnext', // Ensure compatibility with modern JavaScript } -}; +}); From 0e087635625a56834297c00d38c80fa89918d21a Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 09:23:43 +0200 Subject: [PATCH 02/59] Lose extensions on imports --- src/api.js | 20 ++++++++++---------- src/events.js | 14 +++++++------- src/feature_types/feature.js | 4 ++-- src/feature_types/multi_feature.js | 12 ++++++------ src/lib/common_selectors.js | 2 +- src/lib/constrain_feature_movement.js | 2 +- src/lib/create_midpoint.js | 2 +- src/lib/create_supplementary_points.js | 6 +++--- src/lib/create_vertex.js | 2 +- src/lib/features_at.js | 8 ++++---- src/lib/get_features_and_set_cursor.js | 4 ++-- src/lib/move_features.js | 4 ++-- src/lib/sort_features.js | 2 +- src/modes/direct_select.js | 12 ++++++------ src/modes/draw_line_string.js | 10 +++++----- src/modes/draw_point.js | 4 ++-- src/modes/draw_polygon.js | 10 +++++----- src/modes/mode_interface_accessors.js | 24 ++++++++++++------------ src/modes/simple_select.js | 14 +++++++------- src/render.js | 2 +- src/setup.js | 8 ++++---- src/store.js | 8 ++++---- src/ui.js | 2 +- test/api.test.js | 10 +++++----- test/features_at.test.js | 8 ++++---- test/utils/create_map.js | 4 ++-- test/utils/key_events.js | 2 +- 27 files changed, 100 insertions(+), 100 deletions(-) diff --git a/src/api.js b/src/api.js index ddea6921..8422ccd9 100644 --- a/src/api.js +++ b/src/api.js @@ -1,15 +1,15 @@ import isEqual from 'fast-deep-equal'; import normalize from '@mapbox/geojson-normalize'; -import {generateID} from './lib/id.js'; -import featuresAt from './lib/features_at.js'; -import stringSetsAreEqual from './lib/string_sets_are_equal.js'; -import * as Constants from './constants.js'; -import StringSet from './lib/string_set.js'; - -import Polygon from './feature_types/polygon.js'; -import LineString from './feature_types/line_string.js'; -import Point from './feature_types/point.js'; -import MultiFeature from './feature_types/multi_feature.js'; +import {generateID} from './lib/id'; +import featuresAt from './lib/features_at'; +import stringSetsAreEqual from './lib/string_sets_are_equal'; +import * as Constants from './constants'; +import StringSet from './lib/string_set'; + +import Polygon from './feature_types/polygon'; +import LineString from './feature_types/line_string'; +import Point from './feature_types/point'; +import MultiFeature from './feature_types/multi_feature'; const featureTypes = { Polygon, diff --git a/src/events.js b/src/events.js index 8f6c4c6a..947665f5 100644 --- a/src/events.js +++ b/src/events.js @@ -1,10 +1,10 @@ -import setupModeHandler from './lib/mode_handler.js'; -import getFeaturesAndSetCursor from './lib/get_features_and_set_cursor.js'; -import featuresAt from './lib/features_at.js'; -import isClick from './lib/is_click.js'; -import isTap from './lib/is_tap.js'; -import * as Constants from './constants.js'; -import objectToMode from './modes/object_to_mode.js'; +import setupModeHandler from './lib/mode_handler'; +import getFeaturesAndSetCursor from './lib/get_features_and_set_cursor'; +import featuresAt from './lib/features_at'; +import isClick from './lib/is_click'; +import isTap from './lib/is_tap'; +import * as Constants from './constants'; +import objectToMode from './modes/object_to_mode'; export default function(ctx) { diff --git a/src/feature_types/feature.js b/src/feature_types/feature.js index ee2b92ea..37634487 100644 --- a/src/feature_types/feature.js +++ b/src/feature_types/feature.js @@ -1,5 +1,5 @@ -import {generateID} from '../lib/id.js'; -import * as Constants from '../constants.js'; +import {generateID} from '../lib/id'; +import * as Constants from '../constants'; const Feature = function(ctx, geojson) { this.ctx = ctx; diff --git a/src/feature_types/multi_feature.js b/src/feature_types/multi_feature.js index 752eca00..552d1433 100644 --- a/src/feature_types/multi_feature.js +++ b/src/feature_types/multi_feature.js @@ -1,10 +1,10 @@ -import {generateID} from '../lib/id.js'; -import Feature from './feature.js'; -import * as Constants from '../constants.js'; +import {generateID} from '../lib/id'; +import Feature from './feature'; +import * as Constants from '../constants'; -import MultiPoint from './point.js'; -import MultiLineString from './line_string.js'; -import MultiPolygon from './polygon.js'; +import MultiPoint from './point'; +import MultiLineString from './line_string'; +import MultiPolygon from './polygon'; const models = { MultiPoint, diff --git a/src/lib/common_selectors.js b/src/lib/common_selectors.js index 3339f688..f097c831 100644 --- a/src/lib/common_selectors.js +++ b/src/lib/common_selectors.js @@ -1,4 +1,4 @@ -import * as Constants from '../constants.js'; +import * as Constants from '../constants'; export function isOfMetaType(type) { return function(e) { diff --git a/src/lib/constrain_feature_movement.js b/src/lib/constrain_feature_movement.js index 64a36379..9a536535 100644 --- a/src/lib/constrain_feature_movement.js +++ b/src/lib/constrain_feature_movement.js @@ -1,4 +1,4 @@ -import * as Constants from '../constants.js'; +import * as Constants from '../constants'; const { LAT_MIN, diff --git a/src/lib/create_midpoint.js b/src/lib/create_midpoint.js index a6a5e63b..766eb854 100644 --- a/src/lib/create_midpoint.js +++ b/src/lib/create_midpoint.js @@ -1,4 +1,4 @@ -import * as Constants from '../constants.js'; +import * as Constants from '../constants'; export default function(parent, startVertex, endVertex) { const startCoord = startVertex.geometry.coordinates; diff --git a/src/lib/create_supplementary_points.js b/src/lib/create_supplementary_points.js index 2a22567b..017a801b 100644 --- a/src/lib/create_supplementary_points.js +++ b/src/lib/create_supplementary_points.js @@ -1,6 +1,6 @@ -import createVertex from './create_vertex.js'; -import createMidpoint from './create_midpoint.js'; -import * as Constants from '../constants.js'; +import createVertex from './create_vertex'; +import createMidpoint from './create_midpoint'; +import * as Constants from '../constants'; function createSupplementaryPoints(geojson, options = {}, basePath = null) { const { type, coordinates } = geojson.geometry; diff --git a/src/lib/create_vertex.js b/src/lib/create_vertex.js index 048be7ec..e6ab9a95 100644 --- a/src/lib/create_vertex.js +++ b/src/lib/create_vertex.js @@ -1,4 +1,4 @@ -import * as Constants from '../constants.js'; +import * as Constants from '../constants'; /** * Returns GeoJSON for a Point representing the diff --git a/src/lib/features_at.js b/src/lib/features_at.js index 1ca36b97..16feba7d 100644 --- a/src/lib/features_at.js +++ b/src/lib/features_at.js @@ -1,7 +1,7 @@ -import sortFeatures from './sort_features.js'; -import mapEventToBoundingBox from './map_event_to_bounding_box.js'; -import * as Constants from '../constants.js'; -import StringSet from './string_set.js'; +import sortFeatures from './sort_features'; +import mapEventToBoundingBox from './map_event_to_bounding_box'; +import * as Constants from '../constants'; +import StringSet from './string_set'; const META_TYPES = [ Constants.meta.FEATURE, diff --git a/src/lib/get_features_and_set_cursor.js b/src/lib/get_features_and_set_cursor.js index f3a4ab61..91c1067b 100644 --- a/src/lib/get_features_and_set_cursor.js +++ b/src/lib/get_features_and_set_cursor.js @@ -1,5 +1,5 @@ -import featuresAt from './features_at.js'; -import * as Constants from '../constants.js'; +import featuresAt from './features_at'; +import * as Constants from '../constants'; export default function getFeatureAtAndSetCursors(event, ctx) { const features = featuresAt.click(event, null, ctx); diff --git a/src/lib/move_features.js b/src/lib/move_features.js index 72513b7f..f153b2e0 100644 --- a/src/lib/move_features.js +++ b/src/lib/move_features.js @@ -1,5 +1,5 @@ -import constrainFeatureMovement from './constrain_feature_movement.js'; -import * as Constants from '../constants.js'; +import constrainFeatureMovement from './constrain_feature_movement'; +import * as Constants from '../constants'; export default function(features, delta) { const constrainedDelta = constrainFeatureMovement(features.map(feature => feature.toGeoJSON()), delta); diff --git a/src/lib/sort_features.js b/src/lib/sort_features.js index 85229584..80ab010f 100644 --- a/src/lib/sort_features.js +++ b/src/lib/sort_features.js @@ -1,5 +1,5 @@ import area from '@mapbox/geojson-area'; -import * as Constants from '../constants.js'; +import * as Constants from '../constants'; const FEATURE_SORT_RANKS = { Point: 0, diff --git a/src/modes/direct_select.js b/src/modes/direct_select.js index a27749d4..f3347bed 100644 --- a/src/modes/direct_select.js +++ b/src/modes/direct_select.js @@ -1,9 +1,9 @@ -import { noTarget, isOfMetaType, isActiveFeature, isInactiveFeature, isShiftDown } from '../lib/common_selectors.js'; -import createSupplementaryPoints from '../lib/create_supplementary_points.js'; -import constrainFeatureMovement from '../lib/constrain_feature_movement.js'; -import doubleClickZoom from '../lib/double_click_zoom.js'; -import * as Constants from '../constants.js'; -import moveFeatures from '../lib/move_features.js'; +import { noTarget, isOfMetaType, isActiveFeature, isInactiveFeature, isShiftDown } from '../lib/common_selectors'; +import createSupplementaryPoints from '../lib/create_supplementary_points'; +import constrainFeatureMovement from '../lib/constrain_feature_movement'; +import doubleClickZoom from '../lib/double_click_zoom'; +import * as Constants from '../constants'; +import moveFeatures from '../lib/move_features'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); diff --git a/src/modes/draw_line_string.js b/src/modes/draw_line_string.js index ec008061..d747ced2 100644 --- a/src/modes/draw_line_string.js +++ b/src/modes/draw_line_string.js @@ -1,8 +1,8 @@ -import * as CommonSelectors from '../lib/common_selectors.js'; -import isEventAtCoordinates from '../lib/is_event_at_coordinates.js'; -import doubleClickZoom from '../lib/double_click_zoom.js'; -import * as Constants from '../constants.js'; -import createVertex from '../lib/create_vertex.js'; +import * as CommonSelectors from '../lib/common_selectors'; +import isEventAtCoordinates from '../lib/is_event_at_coordinates'; +import doubleClickZoom from '../lib/double_click_zoom'; +import * as Constants from '../constants'; +import createVertex from '../lib/create_vertex'; const DrawLineString = {}; diff --git a/src/modes/draw_point.js b/src/modes/draw_point.js index 896187b5..d550834e 100644 --- a/src/modes/draw_point.js +++ b/src/modes/draw_point.js @@ -1,5 +1,5 @@ -import * as CommonSelectors from '../lib/common_selectors.js'; -import * as Constants from '../constants.js'; +import * as CommonSelectors from '../lib/common_selectors'; +import * as Constants from '../constants'; const DrawPoint = {}; diff --git a/src/modes/draw_polygon.js b/src/modes/draw_polygon.js index a7561404..816a4fd3 100644 --- a/src/modes/draw_polygon.js +++ b/src/modes/draw_polygon.js @@ -1,8 +1,8 @@ -import * as CommonSelectors from '../lib/common_selectors.js'; -import doubleClickZoom from '../lib/double_click_zoom.js'; -import * as Constants from '../constants.js'; -import isEventAtCoordinates from '../lib/is_event_at_coordinates.js'; -import createVertex from '../lib/create_vertex.js'; +import * as CommonSelectors from '../lib/common_selectors'; +import doubleClickZoom from '../lib/double_click_zoom'; +import * as Constants from '../constants'; +import isEventAtCoordinates from '../lib/is_event_at_coordinates'; +import createVertex from '../lib/create_vertex'; const DrawPolygon = {}; diff --git a/src/modes/mode_interface_accessors.js b/src/modes/mode_interface_accessors.js index ee5eed86..2b72145e 100644 --- a/src/modes/mode_interface_accessors.js +++ b/src/modes/mode_interface_accessors.js @@ -1,9 +1,9 @@ -import * as Constants from '../constants.js'; -import featuresAt from '../lib/features_at.js'; -import Point from '../feature_types/point.js'; -import LineString from '../feature_types/line_string.js'; -import Polygon from '../feature_types/polygon.js'; -import MultiFeature from '../feature_types/multi_feature.js'; +import * as Constants from '../constants'; +import featuresAt from '../lib/features_at'; +import Point from '../feature_types/point'; +import LineString from '../feature_types/line_string'; +import Polygon from '../feature_types/polygon'; +import MultiFeature from '../feature_types/multi_feature'; export default function ModeInterface(ctx) { this.map = ctx.map; @@ -14,7 +14,7 @@ export default function ModeInterface(ctx) { /** * Sets Draw's interal selected state * @name this.setSelected - * @param {DrawFeature[]} - whats selected as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature.js) + * @param {DrawFeature[]} - whats selected as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) */ ModeInterface.prototype.setSelected = function(features) { return this._ctx.store.setSelected(features); @@ -37,7 +37,7 @@ ModeInterface.prototype.setSelectedCoordinates = function(coords) { }; /** - * Get all selected features as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature.js) + * Get all selected features as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) * @name this.getSelected * @returns {DrawFeature[]} */ @@ -65,7 +65,7 @@ ModeInterface.prototype.isSelected = function(id) { }; /** - * Get a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature.js) by its id + * Get a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) by its id * @name this.getFeature * @param {String} id - a feature id * @returns {DrawFeature} @@ -102,7 +102,7 @@ ModeInterface.prototype.deleteFeature = function(id, opts = {}) { }; /** - * Add a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature.js) to draw. + * Add a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) to draw. * See `this.newFeature` for converting geojson into a DrawFeature * @name this.addFeature * @param {DrawFeature} feature - the feature to add @@ -192,7 +192,7 @@ ModeInterface.prototype.featuresAt = function(event, bbox, bufferType = 'click') }; /** - * Create a new [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature.js) from geojson + * Create a new [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) from geojson * @name this.newFeature * @param {GeoJSONFeature} geojson * @returns {DrawFeature} @@ -206,7 +206,7 @@ ModeInterface.prototype.newFeature = function(geojson) { }; /** - * Check is an object is an instance of a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature.js) + * Check is an object is an instance of a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) * @name this.isInstanceOf * @param {String} type - `Point`, `LineString`, `Polygon`, `MultiFeature` * @param {Object} feature - the object that needs to be checked diff --git a/src/modes/simple_select.js b/src/modes/simple_select.js index 62eab178..649867d5 100644 --- a/src/modes/simple_select.js +++ b/src/modes/simple_select.js @@ -1,10 +1,10 @@ -import * as CommonSelectors from '../lib/common_selectors.js'; -import mouseEventPoint from '../lib/mouse_event_point.js'; -import createSupplementaryPoints from '../lib/create_supplementary_points.js'; -import StringSet from '../lib/string_set.js'; -import doubleClickZoom from '../lib/double_click_zoom.js'; -import moveFeatures from '../lib/move_features.js'; -import * as Constants from '../constants.js'; +import * as CommonSelectors from '../lib/common_selectors'; +import mouseEventPoint from '../lib/mouse_event_point'; +import createSupplementaryPoints from '../lib/create_supplementary_points'; +import StringSet from '../lib/string_set'; +import doubleClickZoom from '../lib/double_click_zoom'; +import moveFeatures from '../lib/move_features'; +import * as Constants from '../constants'; const SimpleSelect = {}; diff --git a/src/render.js b/src/render.js index ae63efb0..879ef055 100644 --- a/src/render.js +++ b/src/render.js @@ -1,4 +1,4 @@ -import * as Constants from './constants.js'; +import * as Constants from './constants'; export default function render() { // eslint-disable-next-line no-invalid-this diff --git a/src/setup.js b/src/setup.js index e1524db8..c16c5677 100644 --- a/src/setup.js +++ b/src/setup.js @@ -1,7 +1,7 @@ -import events from './events.js'; -import Store from './store.js'; -import ui from './ui.js'; -import * as Constants from './constants.js'; +import events from './events'; +import Store from './store'; +import ui from './ui'; +import * as Constants from './constants'; export default function(ctx) { diff --git a/src/store.js b/src/store.js index ed163a74..3155ecc8 100644 --- a/src/store.js +++ b/src/store.js @@ -1,7 +1,7 @@ -import toDenseArray from './lib/to_dense_array.js'; -import StringSet from './lib/string_set.js'; -import render from './render.js'; -import * as Constants from './constants.js'; +import toDenseArray from './lib/to_dense_array'; +import StringSet from './lib/string_set'; +import render from './render'; +import * as Constants from './constants'; export default function Store(ctx) { this._features = {}; diff --git a/src/ui.js b/src/ui.js index 82b287a8..22b8f1ec 100644 --- a/src/ui.js +++ b/src/ui.js @@ -1,4 +1,4 @@ -import * as Constants from './constants.js'; +import * as Constants from './constants'; const classTypes = ['mode', 'feature', 'mouse']; diff --git a/test/api.test.js b/test/api.test.js index cfbcc743..7f5fb924 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -3,12 +3,12 @@ import {test, beforeEach, afterEach} from 'node:test'; import assert from 'node:assert/strict'; import {spy} from 'sinon'; -import * as Constants from '../src/constants.js'; +import * as Constants from '../src/constants'; import MapboxDraw from '../index'; -import createMap from './utils/create_map.js'; -import getGeoJSON from './utils/get_geojson.js'; -import {setupAfterNextRender} from './utils/after_next_render.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; +import createMap from './utils/create_map'; +import getGeoJSON from './utils/get_geojson'; +import {setupAfterNextRender} from './utils/after_next_render'; +import getPublicMemberKeys from './utils/get_public_member_keys'; let map; let afterNextRender; diff --git a/test/features_at.test.js b/test/features_at.test.js index 1209425e..5dcf6f0f 100644 --- a/test/features_at.test.js +++ b/test/features_at.test.js @@ -1,9 +1,9 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import featuresAt from '../src/lib/features_at.js'; -import styles from '../src/lib/theme.js'; -import * as Constants from '../src/constants.js'; -import setupOptions from '../src/options.js'; +import featuresAt from '../src/lib/features_at'; +import styles from '../src/lib/theme'; +import * as Constants from '../src/constants'; +import setupOptions from '../src/options'; /** * Mock of the addLayers function in setup diff --git a/test/utils/create_map.js b/test/utils/create_map.js index fa96aaa6..14fd10bb 100644 --- a/test/utils/create_map.js +++ b/test/utils/create_map.js @@ -1,7 +1,7 @@ import {bboxClip} from '@turf/bbox-clip'; -import Evented from '../../bench/lib/evented.js'; -import { interactions } from '../../src/constants.js'; +import Evented from '../../bench/lib/evented'; +import { interactions } from '../../src/constants'; class MockMap extends Evented { constructor(options = {}) { diff --git a/test/utils/key_events.js b/test/utils/key_events.js index c70fb829..7dca7fb6 100644 --- a/test/utils/key_events.js +++ b/test/utils/key_events.js @@ -1,5 +1,5 @@ import createSyntheticEvent from 'synthetic-dom-events'; -import * as Constants from '../../src/constants.js'; +import * as Constants from '../../src/constants'; const classList = [Constants.classes.CANVAS]; classList.contains = function(cls) { From f81f4839c6db1f63f735f2f5c86b8cc503ee8760 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 10:44:28 +0200 Subject: [PATCH 03/59] Declare class --- index.ts | 15 ++----------- src/types/types.ts | 55 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/index.ts b/index.ts index 6bd9d5df..0128cea5 100644 --- a/index.ts +++ b/index.ts @@ -4,20 +4,9 @@ import setupAPI from './src/api'; import modes from './src/modes/index'; import * as Constants from './src/constants'; import * as lib from './src/lib/index'; -import type { Controls, DrawLayer } from './src/types/types' - -interface Options { - keybindings: boolean; - touchEnabled: boolean; - boxSelect: boolean; - clickBuffer: number; - touchBuffer: number; - controls: Controls; - displayControlsDefault: boolean; - styles: Array -} +import type { DrawOptions, Draw } from './src/types/types' -const setupDraw = (options: Options, api) => { +const setupDraw = (options: DrawOptions, api: Draw) => { options = setupOptions(options); const ctx = { diff --git a/src/types/types.ts b/src/types/types.ts index 175ba696..5bfb21a1 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,5 +1,17 @@ -import { modes, meta } from '../constants'; -import type { Layer } from 'mapbox-gl'; +import { modes, meta, types } from '../constants'; +import type { ControlPosition, IControl, Map, Layer } from 'mapbox-gl'; +import type { FeatureCollection, Feature, Point, Geometry } from 'geojson'; + +export interface DrawOptions { + keybindings: boolean; + touchEnabled: boolean; + boxSelect: boolean; + clickBuffer: number; + touchBuffer: number; + controls: Controls; + displayControlsDefault: boolean; + styles: Array +} export interface Controls { point: boolean; @@ -10,8 +22,43 @@ export interface Controls { uncombine_features: boolean } +type Modes = typeof modes; + export interface DrawLayer extends Layer { - meta: typeof meta[keyof typeof meta]; - mode: typeof modes[keyof typeof modes]; + meta: typeof meta; + mode: Modes; active: boolean; } + +export declare class Draw implements IControl { + options: DrawOptions; + types: typeof types; + modes: Modes; + getDefaultPosition: () => ControlPosition; + constructor(options?: DrawOptions); + add(geojson: Feature | FeatureCollection | Geometry): string[]; + get(featureId: string): Feature | undefined; + getFeatureIdsAt(point: { x: number; y: number }): string[]; + getSelectedIds(): string[]; + getSelected(): FeatureCollection; + getSelectedPoints(): FeatureCollection; + getAll(): FeatureCollection; + delete(ids: string | string[]): this; + deleteAll(): this; + set(featureCollection: FeatureCollection): string[]; + trash(): this; + combineFeatures(): this; + uncombineFeatures(): this; + getMode(): (Modes & {}) | string; + changeMode(mode: typeof modes['SIMPLE_SELECT'], options?: { featureIds: string[] }): this; + changeMode(mode: typeof modes['DIRECT_SELECT'], options: { featureId: string }): this; + changeMode( + mode: typeof modes['DRAW_LINE_STRING'], + options?: { featureId: string; from: Feature | Point | number[] }, + ): this; + changeMode(mode: Modes): this; + changeMode(mode: T & (T extends Modes ? never : T), options?: object): this; + setFeatureProperty(featureId: string, property: string, value: any): this; + onAdd(map: Map): HTMLElement; + onRemove(map: Map): unknown; +} From 60e274d9b8b7a27fcefe15349e99c5dcbe5dbde6 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 11:42:30 +0200 Subject: [PATCH 04/59] More conversion --- src/{api.js => api.ts} | 4 +- src/events.js | 2 +- src/lib/{features_at.js => features_at.ts} | 19 +-- src/lib/get_features_and_set_cursor.js | 2 +- src/lib/{id.js => id.ts} | 2 +- src/lib/index.js | 40 +++---- src/lib/map_event_to_bounding_box.js | 14 --- src/lib/map_event_to_bounding_box.ts | 11 ++ .../{move_features.js => move_features.ts} | 0 .../{sort_features.js => sort_features.ts} | 21 +++- src/modes/mode_interface_accessors.js | 2 +- src/types/geojson-flatten.d.ts | 1 - src/types/geojson-normalize.d.ts | 1 + src/types/types.ts | 113 +++++++++++++++++- test/features_at.test.js | 2 +- 15 files changed, 171 insertions(+), 63 deletions(-) rename src/{api.js => api.ts} (98%) rename src/lib/{features_at.js => features_at.ts} (72%) rename src/lib/{id.js => id.ts} (74%) delete mode 100644 src/lib/map_event_to_bounding_box.js create mode 100644 src/lib/map_event_to_bounding_box.ts rename src/lib/{move_features.js => move_features.ts} (100%) rename src/lib/{sort_features.js => sort_features.ts} (66%) delete mode 100644 src/types/geojson-flatten.d.ts create mode 100644 src/types/geojson-normalize.d.ts diff --git a/src/api.js b/src/api.ts similarity index 98% rename from src/api.js rename to src/api.ts index 8422ccd9..90b0bfbb 100644 --- a/src/api.js +++ b/src/api.ts @@ -1,7 +1,7 @@ import isEqual from 'fast-deep-equal'; import normalize from '@mapbox/geojson-normalize'; -import {generateID} from './lib/id'; -import featuresAt from './lib/features_at'; +import { generateID } from './lib/id'; +import { featuresAt } from './lib/features_at'; import stringSetsAreEqual from './lib/string_sets_are_equal'; import * as Constants from './constants'; import StringSet from './lib/string_set'; diff --git a/src/events.js b/src/events.js index 947665f5..ea79f59c 100644 --- a/src/events.js +++ b/src/events.js @@ -1,6 +1,6 @@ import setupModeHandler from './lib/mode_handler'; import getFeaturesAndSetCursor from './lib/get_features_and_set_cursor'; -import featuresAt from './lib/features_at'; +import { featuresAt } from './lib/features_at'; import isClick from './lib/is_click'; import isTap from './lib/is_tap'; import * as Constants from './constants'; diff --git a/src/lib/features_at.js b/src/lib/features_at.ts similarity index 72% rename from src/lib/features_at.js rename to src/lib/features_at.ts index 16feba7d..280feb55 100644 --- a/src/lib/features_at.js +++ b/src/lib/features_at.ts @@ -3,27 +3,16 @@ import mapEventToBoundingBox from './map_event_to_bounding_box'; import * as Constants from '../constants'; import StringSet from './string_set'; +import type { BBox } from 'geojson'; +import type { DrawCTX } from '../types/types'; + const META_TYPES = [ Constants.meta.FEATURE, Constants.meta.MIDPOINT, Constants.meta.VERTEX ]; -// Requires either event or bbox -export default { - click: featuresAtClick, - touch: featuresAtTouch -}; - -function featuresAtClick(event, bbox, ctx) { - return featuresAt(event, bbox, ctx, ctx.options.clickBuffer); -} - -function featuresAtTouch(event, bbox, ctx) { - return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); -} - -function featuresAt(event, bbox, ctx, buffer) { +export const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: number) => { if (ctx.map === null) return []; const box = (event) ? mapEventToBoundingBox(event, buffer) : bbox; diff --git a/src/lib/get_features_and_set_cursor.js b/src/lib/get_features_and_set_cursor.js index 91c1067b..5998746f 100644 --- a/src/lib/get_features_and_set_cursor.js +++ b/src/lib/get_features_and_set_cursor.js @@ -1,4 +1,4 @@ -import featuresAt from './features_at'; +import { featuresAt } from './features_at'; import * as Constants from '../constants'; export default function getFeatureAtAndSetCursors(event, ctx) { diff --git a/src/lib/id.js b/src/lib/id.ts similarity index 74% rename from src/lib/id.js rename to src/lib/id.ts index eaf080a9..6fc46762 100644 --- a/src/lib/id.js +++ b/src/lib/id.ts @@ -1,4 +1,4 @@ -import {customAlphabet} from 'nanoid/non-secure'; +import { customAlphabet } from 'nanoid/non-secure'; const nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 32); diff --git a/src/lib/index.js b/src/lib/index.js index dd881099..04acd5c9 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -1,23 +1,23 @@ -import * as CommonSelectors from "./common_selectors.js"; -import constrainFeatureMovement from "./constrain_feature_movement.js"; -import createMidPoint from "./create_midpoint.js"; -import createSupplementaryPoints from "./create_supplementary_points.js"; -import createVertex from "./create_vertex.js"; -import doubleClickZoom from "./double_click_zoom.js"; -import euclideanDistance from "./euclidean_distance.js"; -import featuresAt from "./features_at.js"; -import getFeatureAtAndSetCursors from "./get_features_and_set_cursor.js"; -import isClick from "./is_click.js"; -import isEventAtCoordinates from "./is_event_at_coordinates.js"; -import isTap from "./is_tap.js"; -import mapEventToBoundingBox from "./map_event_to_bounding_box.js"; -import ModeHandler from "./mode_handler.js"; -import moveFeatures from "./move_features.js"; -import sortFeatures from "./sort_features.js"; -import StringSet from "./string_set.js"; -import stringSetsAreEqual from "./string_sets_are_equal.js"; -import theme from "./theme.js"; -import toDenseArray from "./to_dense_array.js"; +import * as CommonSelectors from './common_selectors.js'; +import constrainFeatureMovement from './constrain_feature_movement.js'; +import createMidPoint from './create_midpoint.js'; +import createSupplementaryPoints from './create_supplementary_points.js'; +import createVertex from './create_vertex.js'; +import doubleClickZoom from './double_click_zoom.js'; +import euclideanDistance from './euclidean_distance.js'; +import { featuresAt } from './features_at.js'; +import getFeatureAtAndSetCursors from './get_features_and_set_cursor.js'; +import isClick from './is_click.js'; +import isEventAtCoordinates from './is_event_at_coordinates.js'; +import isTap from './is_tap.js'; +import mapEventToBoundingBox from './map_event_to_bounding_box.js'; +import ModeHandler from './mode_handler.js'; +import moveFeatures from './move_features.js'; +import sortFeatures from './sort_features.js'; +import StringSet from './string_set.js'; +import stringSetsAreEqual from './string_sets_are_equal.js'; +import theme from './theme.js'; +import toDenseArray from './to_dense_array.js'; export { CommonSelectors, diff --git a/src/lib/map_event_to_bounding_box.js b/src/lib/map_event_to_bounding_box.js deleted file mode 100644 index b4793ae7..00000000 --- a/src/lib/map_event_to_bounding_box.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Returns a bounding box representing the event's location. - * - * @param {Event} mapEvent - Mapbox GL JS map event, with a point properties. - * @return {Array>} Bounding box. - */ -function mapEventToBoundingBox(mapEvent, buffer = 0) { - return [ - [mapEvent.point.x - buffer, mapEvent.point.y - buffer], - [mapEvent.point.x + buffer, mapEvent.point.y + buffer] - ]; -} - -export default mapEventToBoundingBox; diff --git a/src/lib/map_event_to_bounding_box.ts b/src/lib/map_event_to_bounding_box.ts new file mode 100644 index 00000000..5d6c164f --- /dev/null +++ b/src/lib/map_event_to_bounding_box.ts @@ -0,0 +1,11 @@ +import type { Position } from 'geojson'; +import type { MapMouseEvent, MapTouchEvent } from '../types/types'; + +function mapEventToBoundingBox(mapEvent: MapMouseEvent | MapTouchEvent, buffer: number = 0): Position[] { + return [ + [mapEvent.point.x - buffer, mapEvent.point.y - buffer], + [mapEvent.point.x + buffer, mapEvent.point.y + buffer] + ]; +} + +export default mapEventToBoundingBox; diff --git a/src/lib/move_features.js b/src/lib/move_features.ts similarity index 100% rename from src/lib/move_features.js rename to src/lib/move_features.ts diff --git a/src/lib/sort_features.js b/src/lib/sort_features.ts similarity index 66% rename from src/lib/sort_features.js rename to src/lib/sort_features.ts index 80ab010f..133e7f35 100644 --- a/src/lib/sort_features.js +++ b/src/lib/sort_features.ts @@ -1,17 +1,30 @@ import area from '@mapbox/geojson-area'; import * as Constants from '../constants'; +import { Feature } from 'geojson'; const FEATURE_SORT_RANKS = { Point: 0, + MultiPoint: 0, LineString: 1, MultiLineString: 1, - Polygon: 2 + MultiPolygon: 2, + Polygon: 2, + GeometryCollection: 2 }; -function comparator(a, b) { +interface DrawFeature extends Feature { + area?: number; +} + +function comparator(a: DrawFeature, b: DrawFeature) { const score = FEATURE_SORT_RANKS[a.geometry.type] - FEATURE_SORT_RANKS[b.geometry.type]; - if (score === 0 && a.geometry.type === Constants.geojsonTypes.POLYGON) { + if ( + score === 0 && + a.area && + b.area && + a.geometry.type === Constants.geojsonTypes.POLYGON + ) { return a.area - b.area; } @@ -19,7 +32,7 @@ function comparator(a, b) { } // Sort in the order above, then sort polygons by area ascending. -function sortFeatures(features) { +function sortFeatures(features: Array) { return features.map((feature) => { if (feature.geometry.type === Constants.geojsonTypes.POLYGON) { feature.area = area.geometry({ diff --git a/src/modes/mode_interface_accessors.js b/src/modes/mode_interface_accessors.js index 2b72145e..932b6e2e 100644 --- a/src/modes/mode_interface_accessors.js +++ b/src/modes/mode_interface_accessors.js @@ -1,5 +1,5 @@ import * as Constants from '../constants'; -import featuresAt from '../lib/features_at'; +import { featuresAt } from '../lib/features_at'; import Point from '../feature_types/point'; import LineString from '../feature_types/line_string'; import Polygon from '../feature_types/polygon'; diff --git a/src/types/geojson-flatten.d.ts b/src/types/geojson-flatten.d.ts deleted file mode 100644 index cc1dd53a..00000000 --- a/src/types/geojson-flatten.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'geojson-flatten'; diff --git a/src/types/geojson-normalize.d.ts b/src/types/geojson-normalize.d.ts new file mode 100644 index 00000000..d8f01ac9 --- /dev/null +++ b/src/types/geojson-normalize.d.ts @@ -0,0 +1 @@ +declare module '@mapbox/geojson-normalize'; diff --git a/src/types/types.ts b/src/types/types.ts index 5bfb21a1..d594e06b 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,6 +1,21 @@ import { modes, meta, types } from '../constants'; -import type { ControlPosition, IControl, Map, Layer } from 'mapbox-gl'; -import type { FeatureCollection, Feature, Point, Geometry } from 'geojson'; +import { BBox, Feature, FeatureCollection, GeoJSON, GeoJsonTypes, Geometry, Point, Position } from 'geojson'; +import type { + ControlPosition, + IControl, + Map, + Layer, + MapMouseEvent as MapboxMapMouseEvent, + MapTouchEvent as MapboxMapTouchEvent, +} from 'mapbox-gl'; + +export interface MapMouseEvent extends MapboxMapMouseEvent { + featureTarget: DrawFeature; +} + +export interface MapTouchEvent extends MapboxMapTouchEvent { + featureTarget: DrawFeature; +} export interface DrawOptions { keybindings: boolean; @@ -30,6 +45,100 @@ export interface DrawLayer extends Layer { active: boolean; } +interface DrawPoint extends DrawFeatureBase { + readonly type: 'Point'; + getCoordinate(): Position; + updateCoordinate(lng: number, lat: number): void; + updateCoordinate(path: string, lng: number, lat: number): void; +} + +interface DrawLineString extends DrawFeatureBase { + readonly type: 'LineString'; + addCoordinate(path: string | number, lng: number, lat: number): void; + removeCoordinate(path: string | number): void; +} + +interface DrawPolygon extends DrawFeatureBase { + readonly type: 'Polygon'; + addCoordinate(path: string, lng: number, lat: number): void; + removeCoordinate(path: string): void; +} + +interface DrawFeatureBase { + readonly properties: Readonly; + readonly coordinates: Coordinates; + readonly id: NonNullable; + readonly type: GeoJsonTypes; + + changed(): void; + isValid(): boolean; + incomingCoords: this["setCoordinates"]; + setCoordinates(coords: Coordinates): void; + getCoordinates(): Coordinates; + getCoordinate(path: string): Position; + updateCoordinate(path: string, lng: number, lat: number): void; + setProperty(property: string, value: any): void; + toGeoJSON(): GeoJSON; +} + +interface DrawMultiFeature extends + Omit< + DrawFeatureBase< + | (Type extends 'MultiPoint' ? Array : never) + | (Type extends 'MultiLineString' ? Array : never) + | (Type extends 'MultiPolygon' ? Array : never) + >, + "coordinates" + > +{ + readonly type: Type; + readonly features: Array< + | (Type extends 'MultiPoint' ? DrawPoint : never) + | (Type extends 'MultiLineString' ? DrawLineString : never) + | (Type extends 'MultiPolygon' ? DrawPolygon : never) + >; + getFeatures(): this["features"]; +} + +type DrawFeature = + | DrawPoint + | DrawLineString + | DrawPolygon + | DrawMultiFeature<'MultiPoint'> + | DrawMultiFeature<'MultiLineString'> + | DrawMultiFeature<'MultiPolygon'>; + +interface DrawActionableState { + trash: boolean; + combineFeatures: boolean; + uncombineFeatures: boolean; +} + +export interface DrawCTX { + map: Map; + drawConfig: DrawOptions; + setSelected(features?: string | string[]): void; + setSelectedCoordinates(coords: Array<{ coord_path: string; feature_id: string }>): void; + getSelected(): DrawFeature[]; + getSelectedIds(): string[]; + isSelected(id: string): boolean; + getFeature(id: string): DrawFeature; + select(id: string): void; + delete(id: string): void; + deleteFeature(id: string, opts?: any): void; + addFeature(feature: DrawFeature): void; + clearSelectedFeatures(): void; + clearSelectedCoordinates(): void; + setActionableState(actionableState: DrawActionableState): void; + changeMode(mode: Modes, opts?: object, eventOpts?: object): void; + updateUIClasses(opts: object): void; + activateUIButton(name?: string): void; + featuresAt(event: Event, bbox: BBox, bufferType: 'click' | 'tap'): DrawFeature[]; + newFeature(geojson: GeoJSON): DrawFeature; + isInstanceOf(type: string, feature: object): boolean; + doRender(id: string): void; +} + export declare class Draw implements IControl { options: DrawOptions; types: typeof types; diff --git a/test/features_at.test.js b/test/features_at.test.js index 5dcf6f0f..1920be88 100644 --- a/test/features_at.test.js +++ b/test/features_at.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import featuresAt from '../src/lib/features_at'; +import { featuresAt } from '../src/lib/features_at'; import styles from '../src/lib/theme'; import * as Constants from '../src/constants'; import setupOptions from '../src/options'; From f8166b33171be7364bd028a81e1a0b2bf2935906 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 14:38:38 +0200 Subject: [PATCH 05/59] Move all source .js to .ts --- index.ts | 4 +- package.json | 10 ++-- src/{events.js => events.ts} | 8 +-- src/feature_types/{feature.js => feature.ts} | 0 .../{line_string.js => line_string.ts} | 0 .../{multi_feature.js => multi_feature.ts} | 0 src/feature_types/{point.js => point.ts} | 0 src/feature_types/{polygon.js => polygon.ts} | 0 ...ommon_selectors.js => common_selectors.ts} | 0 ...ement.js => constrain_feature_movement.ts} | 0 ...{create_midpoint.js => create_midpoint.ts} | 0 ...ints.js => create_supplementary_points.ts} | 0 .../{create_vertex.js => create_vertex.ts} | 0 ...ble_click_zoom.js => double_click_zoom.ts} | 0 ...dean_distance.js => euclidean_distance.ts} | 0 src/lib/features_at.ts | 22 ++++++- ...r.js => get_features_at_and_set_cursor.ts} | 3 +- src/lib/index.js | 43 -------------- src/lib/index.ts | 43 ++++++++++++++ src/lib/{is_click.js => is_click.ts} | 0 ...rdinates.js => is_event_at_coordinates.ts} | 0 src/lib/{is_tap.js => is_tap.ts} | 0 src/lib/{mode_handler.js => mode_handler.ts} | 0 ...se_event_point.js => mouse_event_point.ts} | 0 src/lib/{string_set.js => string_set.ts} | 0 ..._are_equal.js => string_sets_are_equal.ts} | 0 src/lib/{theme.js => theme.ts} | 0 .../{to_dense_array.js => to_dense_array.ts} | 0 .../{direct_select.js => direct_select.ts} | 57 ++++++++++++------- ...raw_line_string.js => draw_line_string.ts} | 0 src/modes/{draw_point.js => draw_point.ts} | 0 .../{draw_polygon.js => draw_polygon.ts} | 0 src/modes/index.js | 14 ----- src/modes/index.ts | 13 +++++ .../{mode_interface.js => mode_interface.ts} | 0 ...cessors.js => mode_interface_accessors.ts} | 0 .../{object_to_mode.js => object_to_mode.ts} | 0 .../{simple_select.js => simple_select.ts} | 0 src/{options.js => options.ts} | 3 +- src/{render.js => render.ts} | 0 src/{setup.js => setup.ts} | 0 src/{store.js => store.ts} | 0 src/types/types.ts | 26 +++++++++ src/{ui.js => ui.ts} | 0 test/options.test.js | 2 +- 45 files changed, 151 insertions(+), 97 deletions(-) rename src/{events.js => events.ts} (96%) rename src/feature_types/{feature.js => feature.ts} (100%) rename src/feature_types/{line_string.js => line_string.ts} (100%) rename src/feature_types/{multi_feature.js => multi_feature.ts} (100%) rename src/feature_types/{point.js => point.ts} (100%) rename src/feature_types/{polygon.js => polygon.ts} (100%) rename src/lib/{common_selectors.js => common_selectors.ts} (100%) rename src/lib/{constrain_feature_movement.js => constrain_feature_movement.ts} (100%) rename src/lib/{create_midpoint.js => create_midpoint.ts} (100%) rename src/lib/{create_supplementary_points.js => create_supplementary_points.ts} (100%) rename src/lib/{create_vertex.js => create_vertex.ts} (100%) rename src/lib/{double_click_zoom.js => double_click_zoom.ts} (100%) rename src/lib/{euclidean_distance.js => euclidean_distance.ts} (100%) rename src/lib/{get_features_and_set_cursor.js => get_features_at_and_set_cursor.ts} (83%) delete mode 100644 src/lib/index.js create mode 100644 src/lib/index.ts rename src/lib/{is_click.js => is_click.ts} (100%) rename src/lib/{is_event_at_coordinates.js => is_event_at_coordinates.ts} (100%) rename src/lib/{is_tap.js => is_tap.ts} (100%) rename src/lib/{mode_handler.js => mode_handler.ts} (100%) rename src/lib/{mouse_event_point.js => mouse_event_point.ts} (100%) rename src/lib/{string_set.js => string_set.ts} (100%) rename src/lib/{string_sets_are_equal.js => string_sets_are_equal.ts} (100%) rename src/lib/{theme.js => theme.ts} (100%) rename src/lib/{to_dense_array.js => to_dense_array.ts} (100%) rename src/modes/{direct_select.js => direct_select.ts} (92%) rename src/modes/{draw_line_string.js => draw_line_string.ts} (100%) rename src/modes/{draw_point.js => draw_point.ts} (100%) rename src/modes/{draw_polygon.js => draw_polygon.ts} (100%) delete mode 100644 src/modes/index.js create mode 100644 src/modes/index.ts rename src/modes/{mode_interface.js => mode_interface.ts} (100%) rename src/modes/{mode_interface_accessors.js => mode_interface_accessors.ts} (100%) rename src/modes/{object_to_mode.js => object_to_mode.ts} (100%) rename src/modes/{simple_select.js => simple_select.ts} (100%) rename src/{options.js => options.ts} (97%) rename src/{render.js => render.ts} (100%) rename src/{setup.js => setup.ts} (100%) rename src/{store.js => store.ts} (100%) rename src/{ui.js => ui.ts} (100%) diff --git a/index.ts b/index.ts index 0128cea5..c2025b15 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,7 @@ import runSetup from './src/setup'; import setupOptions from './src/options'; import setupAPI from './src/api'; -import modes from './src/modes/index'; +import * as modes from './src/modes/index'; import * as Constants from './src/constants'; import * as lib from './src/lib/index'; import type { DrawOptions, Draw } from './src/types/types' @@ -26,7 +26,7 @@ const setupDraw = (options: DrawOptions, api: Draw) => { return api; }; -function MapboxDraw(options: Options) { +function MapboxDraw(options: DrawOptions) { setupDraw(options, this); } diff --git a/package.json b/package.json index 34477bed..165a511d 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ ], "type": "module", "exports": { - ".": "./index.js", "./dist/mapbox-gl-draw-unminified.js": "./dist/mapbox-gl-draw-unminified.js", "./dist/mapbox-gl-draw.js": "./dist/mapbox-gl-draw.js", "./dist/mapbox-gl-draw.css": "./dist/mapbox-gl-draw.css" @@ -33,8 +32,8 @@ "style": "dist/mapbox-gl-draw.css", "scripts": { "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", - "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.js --shallow", - "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.js --shallow", + "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", + "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", "lint": "eslint index.ts src test bench", "pretest": "npm run lint", "test": "node --test --import ./test/mock-browser.js", @@ -49,6 +48,7 @@ "start-server": "vite --config vite.config.js", "start-bench": "run-p build-token watch watch-bench \"start-server --base . .\"", "start": "run-p build-token start-server", + "format": "prettier --write '**/*.{js,ts,tsx,css}'", "prepare": "husky" }, "devDependencies": { @@ -87,11 +87,11 @@ }, "files": [ "src", - "index.js", + "index.ts", "dist/mapbox-gl-draw*" ], "lint-staged": { - "**/*.{js,ts}": [ + "**/*.ts": [ "eslint", "prettier --write" ] diff --git a/src/events.js b/src/events.ts similarity index 96% rename from src/events.js rename to src/events.ts index ea79f59c..73d52f26 100644 --- a/src/events.js +++ b/src/events.ts @@ -1,5 +1,5 @@ import setupModeHandler from './lib/mode_handler'; -import getFeaturesAndSetCursor from './lib/get_features_and_set_cursor'; +import { getFeatureAtAndSetCursors } from './lib/get_features_at_and_set_cursor'; import { featuresAt } from './lib/features_at'; import isClick from './lib/is_click'; import isTap from './lib/is_tap'; @@ -44,7 +44,7 @@ export default function(ctx) { if (button === 1) { return events.mousedrag(event); } - const target = getFeaturesAndSetCursor(event, ctx); + const target = getFeatureAtAndSetCursors(event, ctx); event.featureTarget = target; currentMode.mousemove(event); }; @@ -54,13 +54,13 @@ export default function(ctx) { time: new Date().getTime(), point: event.point }; - const target = getFeaturesAndSetCursor(event, ctx); + const target = getFeatureAtAndSetCursors(event, ctx); event.featureTarget = target; currentMode.mousedown(event); }; events.mouseup = function(event) { - const target = getFeaturesAndSetCursor(event, ctx); + const target = getFeatureAtAndSetCursors(event, ctx); event.featureTarget = target; if (isClick(mouseDownInfo, { diff --git a/src/feature_types/feature.js b/src/feature_types/feature.ts similarity index 100% rename from src/feature_types/feature.js rename to src/feature_types/feature.ts diff --git a/src/feature_types/line_string.js b/src/feature_types/line_string.ts similarity index 100% rename from src/feature_types/line_string.js rename to src/feature_types/line_string.ts diff --git a/src/feature_types/multi_feature.js b/src/feature_types/multi_feature.ts similarity index 100% rename from src/feature_types/multi_feature.js rename to src/feature_types/multi_feature.ts diff --git a/src/feature_types/point.js b/src/feature_types/point.ts similarity index 100% rename from src/feature_types/point.js rename to src/feature_types/point.ts diff --git a/src/feature_types/polygon.js b/src/feature_types/polygon.ts similarity index 100% rename from src/feature_types/polygon.js rename to src/feature_types/polygon.ts diff --git a/src/lib/common_selectors.js b/src/lib/common_selectors.ts similarity index 100% rename from src/lib/common_selectors.js rename to src/lib/common_selectors.ts diff --git a/src/lib/constrain_feature_movement.js b/src/lib/constrain_feature_movement.ts similarity index 100% rename from src/lib/constrain_feature_movement.js rename to src/lib/constrain_feature_movement.ts diff --git a/src/lib/create_midpoint.js b/src/lib/create_midpoint.ts similarity index 100% rename from src/lib/create_midpoint.js rename to src/lib/create_midpoint.ts diff --git a/src/lib/create_supplementary_points.js b/src/lib/create_supplementary_points.ts similarity index 100% rename from src/lib/create_supplementary_points.js rename to src/lib/create_supplementary_points.ts diff --git a/src/lib/create_vertex.js b/src/lib/create_vertex.ts similarity index 100% rename from src/lib/create_vertex.js rename to src/lib/create_vertex.ts diff --git a/src/lib/double_click_zoom.js b/src/lib/double_click_zoom.ts similarity index 100% rename from src/lib/double_click_zoom.js rename to src/lib/double_click_zoom.ts diff --git a/src/lib/euclidean_distance.js b/src/lib/euclidean_distance.ts similarity index 100% rename from src/lib/euclidean_distance.js rename to src/lib/euclidean_distance.ts diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index 280feb55..bc0e3378 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -4,7 +4,9 @@ import * as Constants from '../constants'; import StringSet from './string_set'; import type { BBox } from 'geojson'; -import type { DrawCTX } from '../types/types'; +import type { DrawCTX, MapMouseEvent, MapTouchEvent } from '../types/types'; + +type Event = MapMouseEvent | MapTouchEvent; const META_TYPES = [ Constants.meta.FEATURE, @@ -12,6 +14,20 @@ const META_TYPES = [ Constants.meta.VERTEX ]; +// Requires either event or bbox +export default { + click: featuresAtClick, + touch: featuresAtTouch +}; + +function featuresAtClick(event: Event, bbox: BBox, ctx: DrawCTX) { + return featuresAt(event, bbox, ctx, ctx.options.clickBuffer); +} + +function featuresAtTouch(event: Event, bbox: BBox, ctx: DrawCTX) { + return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); +} + export const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: number) => { if (ctx.map === null) return []; @@ -22,12 +38,12 @@ export const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: numbe if (ctx.options.styles) queryParams.layers = ctx.options.styles.map(s => s.id).filter(id => ctx.map.getLayer(id) != null); const features = ctx.map.queryRenderedFeatures(box, queryParams) - .filter(feature => META_TYPES.indexOf(feature.properties.meta) !== -1); + .filter(feature => META_TYPES.indexOf(feature?.properties?.meta) !== -1); const featureIds = new StringSet(); const uniqueFeatures = []; features.forEach((feature) => { - const featureId = feature.properties.id; + const featureId = feature.properties?.id; if (featureIds.has(featureId)) return; featureIds.add(featureId); uniqueFeatures.push(feature); diff --git a/src/lib/get_features_and_set_cursor.js b/src/lib/get_features_at_and_set_cursor.ts similarity index 83% rename from src/lib/get_features_and_set_cursor.js rename to src/lib/get_features_at_and_set_cursor.ts index 5998746f..45525d57 100644 --- a/src/lib/get_features_and_set_cursor.js +++ b/src/lib/get_features_at_and_set_cursor.ts @@ -1,7 +1,8 @@ import { featuresAt } from './features_at'; import * as Constants from '../constants'; +import type { DrawCTX } from '../types/types'; -export default function getFeatureAtAndSetCursors(event, ctx) { +export const getFeatureAtAndSetCursors = (event: Event, ctx: DrawCTX) => { const features = featuresAt.click(event, null, ctx); const classes = { mouse: Constants.cursors.NONE }; diff --git a/src/lib/index.js b/src/lib/index.js deleted file mode 100644 index 04acd5c9..00000000 --- a/src/lib/index.js +++ /dev/null @@ -1,43 +0,0 @@ -import * as CommonSelectors from './common_selectors.js'; -import constrainFeatureMovement from './constrain_feature_movement.js'; -import createMidPoint from './create_midpoint.js'; -import createSupplementaryPoints from './create_supplementary_points.js'; -import createVertex from './create_vertex.js'; -import doubleClickZoom from './double_click_zoom.js'; -import euclideanDistance from './euclidean_distance.js'; -import { featuresAt } from './features_at.js'; -import getFeatureAtAndSetCursors from './get_features_and_set_cursor.js'; -import isClick from './is_click.js'; -import isEventAtCoordinates from './is_event_at_coordinates.js'; -import isTap from './is_tap.js'; -import mapEventToBoundingBox from './map_event_to_bounding_box.js'; -import ModeHandler from './mode_handler.js'; -import moveFeatures from './move_features.js'; -import sortFeatures from './sort_features.js'; -import StringSet from './string_set.js'; -import stringSetsAreEqual from './string_sets_are_equal.js'; -import theme from './theme.js'; -import toDenseArray from './to_dense_array.js'; - -export { - CommonSelectors, - constrainFeatureMovement, - createMidPoint, - createSupplementaryPoints, - createVertex, - doubleClickZoom, - euclideanDistance, - featuresAt, - getFeatureAtAndSetCursors, - isClick, - isEventAtCoordinates, - isTap, - mapEventToBoundingBox, - ModeHandler, - moveFeatures, - sortFeatures, - stringSetsAreEqual, - StringSet, - theme, - toDenseArray, -}; diff --git a/src/lib/index.ts b/src/lib/index.ts new file mode 100644 index 00000000..2c205b2a --- /dev/null +++ b/src/lib/index.ts @@ -0,0 +1,43 @@ +import * as CommonSelectors from './common_selectors'; +import constrainFeatureMovement from './constrain_feature_movement'; +import createMidPoint from './create_midpoint'; +import createSupplementaryPoints from './create_supplementary_points'; +import createVertex from './create_vertex'; +import doubleClickZoom from './double_click_zoom'; +import euclideanDistance from './euclidean_distance'; +import { featuresAt } from './features_at'; +import { getFeatureAtAndSetCursors } from './get_features_at_and_set_cursor'; +import isClick from './is_click'; +import isEventAtCoordinates from './is_event_at_coordinates'; +import isTap from './is_tap'; +import mapEventToBoundingBox from './map_event_to_bounding_box'; +import ModeHandler from './mode_handler'; +import moveFeatures from './move_features'; +import sortFeatures from './sort_features'; +import StringSet from './string_set'; +import stringSetsAreEqual from './string_sets_are_equal'; +import theme from './theme'; +import toDenseArray from './to_dense_array'; + +export { + CommonSelectors, + constrainFeatureMovement, + createMidPoint, + createSupplementaryPoints, + createVertex, + doubleClickZoom, + euclideanDistance, + featuresAt, + getFeatureAtAndSetCursors, + isClick, + isEventAtCoordinates, + isTap, + mapEventToBoundingBox, + ModeHandler, + moveFeatures, + sortFeatures, + stringSetsAreEqual, + StringSet, + theme, + toDenseArray, +}; diff --git a/src/lib/is_click.js b/src/lib/is_click.ts similarity index 100% rename from src/lib/is_click.js rename to src/lib/is_click.ts diff --git a/src/lib/is_event_at_coordinates.js b/src/lib/is_event_at_coordinates.ts similarity index 100% rename from src/lib/is_event_at_coordinates.js rename to src/lib/is_event_at_coordinates.ts diff --git a/src/lib/is_tap.js b/src/lib/is_tap.ts similarity index 100% rename from src/lib/is_tap.js rename to src/lib/is_tap.ts diff --git a/src/lib/mode_handler.js b/src/lib/mode_handler.ts similarity index 100% rename from src/lib/mode_handler.js rename to src/lib/mode_handler.ts diff --git a/src/lib/mouse_event_point.js b/src/lib/mouse_event_point.ts similarity index 100% rename from src/lib/mouse_event_point.js rename to src/lib/mouse_event_point.ts diff --git a/src/lib/string_set.js b/src/lib/string_set.ts similarity index 100% rename from src/lib/string_set.js rename to src/lib/string_set.ts diff --git a/src/lib/string_sets_are_equal.js b/src/lib/string_sets_are_equal.ts similarity index 100% rename from src/lib/string_sets_are_equal.js rename to src/lib/string_sets_are_equal.ts diff --git a/src/lib/theme.js b/src/lib/theme.ts similarity index 100% rename from src/lib/theme.js rename to src/lib/theme.ts diff --git a/src/lib/to_dense_array.js b/src/lib/to_dense_array.ts similarity index 100% rename from src/lib/to_dense_array.js rename to src/lib/to_dense_array.ts diff --git a/src/modes/direct_select.js b/src/modes/direct_select.ts similarity index 92% rename from src/modes/direct_select.js rename to src/modes/direct_select.ts index f3347bed..cdb43f7f 100644 --- a/src/modes/direct_select.js +++ b/src/modes/direct_select.ts @@ -5,12 +5,28 @@ import doubleClickZoom from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; +import type { DrawCTX, DrawCustomMode } from '../types/types'; +import type { MapMouseEvent } from 'mapbox-gl'; + const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); -const DirectSelect = {}; -// INTERNAL FUCNTIONS +interface DirectSelectMode extends DrawCustomMode { + fireUpdate(): void; + clickInactive(): void; + fireActionable(state: DrawCTX): void; + clickNoTarget(state: DrawCTX, e: MapMouseEvent): void; + startDragging(state: DrawCTX, e: MapMouseEvent): void; +} + +const DirectSelect: DirectSelectMode = { + clickInactive: function() { + this.changeMode(Constants.modes.SIMPLE_SELECT); + } +}; + +// INTERNAL FUNCTIONS DirectSelect.fireUpdate = function() { this.fire(Constants.events.UPDATE, { @@ -106,10 +122,6 @@ DirectSelect.clickNoTarget = function () { this.changeMode(Constants.modes.SIMPLE_SELECT); }; -DirectSelect.clickInactive = function () { - this.changeMode(Constants.modes.SIMPLE_SELECT); -}; - DirectSelect.clickActiveFeature = function (state) { state.selectedCoordPaths = []; this.clearSelectedCoordinates(); @@ -155,22 +167,6 @@ DirectSelect.onStop = function() { this.clearSelectedCoordinates(); }; -DirectSelect.toDisplayFeatures = function(state, geojson, push) { - if (state.featureId === geojson.properties.id) { - geojson.properties.active = Constants.activeStates.ACTIVE; - push(geojson); - createSupplementaryPoints(geojson, { - map: this.map, - midpoints: true, - selectedPaths: state.selectedCoordPaths - }).forEach(push); - } else { - geojson.properties.active = Constants.activeStates.INACTIVE; - push(geojson); - } - this.fireActionable(state); -}; - DirectSelect.onTrash = function(state) { // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them // in reverse order so that we can remove by index safely. @@ -255,5 +251,22 @@ DirectSelect.onTouchEnd = DirectSelect.onMouseUp = function(state) { this.stopDragging(state); }; +DirectSelect.toDisplayFeatures = function(state: DrawCTX, geojson, push) { + if (state.featureId === geojson.properties.id) { + geojson.properties.active = Constants.activeStates.ACTIVE; + push(geojson); + createSupplementaryPoints(geojson, { + map: this.map, + midpoints: true, + selectedPaths: state.selectedCoordPaths + }).forEach(push); + } else { + geojson.properties.active = Constants.activeStates.INACTIVE; + push(geojson); + } + + this.fireActionable(state); +} + export default DirectSelect; diff --git a/src/modes/draw_line_string.js b/src/modes/draw_line_string.ts similarity index 100% rename from src/modes/draw_line_string.js rename to src/modes/draw_line_string.ts diff --git a/src/modes/draw_point.js b/src/modes/draw_point.ts similarity index 100% rename from src/modes/draw_point.js rename to src/modes/draw_point.ts diff --git a/src/modes/draw_polygon.js b/src/modes/draw_polygon.ts similarity index 100% rename from src/modes/draw_polygon.js rename to src/modes/draw_polygon.ts diff --git a/src/modes/index.js b/src/modes/index.js deleted file mode 100644 index 38b3ec35..00000000 --- a/src/modes/index.js +++ /dev/null @@ -1,14 +0,0 @@ - -import simple_select from './simple_select.js'; -import direct_select from './direct_select.js'; -import draw_point from './draw_point.js'; -import draw_polygon from './draw_polygon.js'; -import draw_line_string from './draw_line_string.js'; - -export default { - simple_select, - direct_select, - draw_point, - draw_polygon, - draw_line_string, -}; diff --git a/src/modes/index.ts b/src/modes/index.ts new file mode 100644 index 00000000..df91bab3 --- /dev/null +++ b/src/modes/index.ts @@ -0,0 +1,13 @@ +import simple_select from './simple_select'; +import direct_select from './direct_select'; +import draw_point from './draw_point'; +import draw_polygon from './draw_polygon'; +import draw_line_string from './draw_line_string'; + +export { + simple_select, + direct_select, + draw_point, + draw_polygon, + draw_line_string +}; diff --git a/src/modes/mode_interface.js b/src/modes/mode_interface.ts similarity index 100% rename from src/modes/mode_interface.js rename to src/modes/mode_interface.ts diff --git a/src/modes/mode_interface_accessors.js b/src/modes/mode_interface_accessors.ts similarity index 100% rename from src/modes/mode_interface_accessors.js rename to src/modes/mode_interface_accessors.ts diff --git a/src/modes/object_to_mode.js b/src/modes/object_to_mode.ts similarity index 100% rename from src/modes/object_to_mode.js rename to src/modes/object_to_mode.ts diff --git a/src/modes/simple_select.js b/src/modes/simple_select.ts similarity index 100% rename from src/modes/simple_select.js rename to src/modes/simple_select.ts diff --git a/src/options.js b/src/options.ts similarity index 97% rename from src/options.js rename to src/options.ts index 41b2fbff..0a36233b 100644 --- a/src/options.js +++ b/src/options.ts @@ -1,7 +1,6 @@ import * as Constants from './constants'; - +import * as modes from './modes/index'; import styles from './lib/theme'; -import modes from './modes/index'; const defaultOptions = { defaultMode: Constants.modes.SIMPLE_SELECT, diff --git a/src/render.js b/src/render.ts similarity index 100% rename from src/render.js rename to src/render.ts diff --git a/src/setup.js b/src/setup.ts similarity index 100% rename from src/setup.js rename to src/setup.ts diff --git a/src/store.js b/src/store.ts similarity index 100% rename from src/store.js rename to src/store.ts diff --git a/src/types/types.ts b/src/types/types.ts index d594e06b..49522f3b 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -139,6 +139,32 @@ export interface DrawCTX { doRender(id: string): void; } +export interface DrawCustomMode { + onSetup?(this: DrawCTX & this, options: CustomModeOptions): CustomModeState; + onDrag?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onClick?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseMove?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseDown?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseUp?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseOut?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onKeyUp?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; + onKeyDown?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; + onTouchStart?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onTouchMove?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onTouchEnd?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onTap?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onStop?(this: DrawCTX & this, state: CustomModeState): void; + onTrash?(this: DrawCTX & this, state: CustomModeState): void; + onCombineFeature?(this: DrawCTX & this, state: CustomModeState): void; + onUncombineFeature?(this: DrawCTX & this, state: CustomModeState): void; + toDisplayFeatures( + this: DrawCTX & this, + state: CustomModeState, + geojson: GeoJSON, + display: (geojson: GeoJSON) => void, + ): void; +} + export declare class Draw implements IControl { options: DrawOptions; types: typeof types; diff --git a/src/ui.js b/src/ui.ts similarity index 100% rename from src/ui.js rename to src/ui.ts diff --git a/test/options.test.js b/test/options.test.js index 7d2a53d9..3ea5215c 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -6,7 +6,7 @@ import assert from 'node:assert/strict'; import {fileURLToPath} from 'url'; import MapboxDraw from '../index'; -import modes from '../src/modes/index'; +import { modes } from '../src/modes/index'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const styleWithSourcesFixture = JSON.parse(fs.readFileSync(path.join(__dirname, './fixtures/style_with_sources.json'))); From 88f9cb1382e7b1506ed685a793044bfd4fefbeea Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 14:39:08 +0200 Subject: [PATCH 06/59] Format everything --- bench/index.js | 40 +- bench/lib/evented.js | 1 - bench/lib/format_number.js | 4 +- bench/lib/fps.js | 4 +- bench/lib/mouse_drag.js | 17 +- bench/lib/mouse_draw.js | 4 +- bench/lib/mouse_events.js | 10 +- bench/lib/mouse_path.js | 10 +- bench/lib/mouse_trace.js | 5 +- bench/lib/trace_progress.js | 6 +- bench/rollup.config.js | 10 +- bench/tests/direct_select_large.js | 14 +- bench/tests/direct_select_large_zoomed.js | 14 +- bench/tests/direct_select_small.js | 10 +- bench/tests/direct_select_small_zoomed.js | 10 +- bench/tests/draw_land_polygon_large.js | 16 +- bench/tests/draw_land_polygon_small.js | 14 +- bench/tests/draw_line_string_large.js | 12 +- bench/tests/draw_line_string_large_zoomed.js | 12 +- bench/tests/draw_line_string_small.js | 10 +- bench/tests/draw_point_large.js | 16 +- bench/tests/draw_point_large_zoomed.js | 14 +- bench/tests/draw_point_small.js | 14 +- bench/tests/draw_polygon_large.js | 14 +- bench/tests/draw_polygon_large_zoomed.js | 14 +- bench/tests/draw_polygon_small.js | 12 +- bench/tests/draw_urban_areas_polygon_large.js | 18 +- bench/tests/draw_urban_areas_polygon_small.js | 16 +- bench/tests/simple_select_large.js | 14 +- bench/tests/simple_select_large_two_maps.js | 35 +- bench/tests/simple_select_large_zoomed.js | 14 +- bench/tests/simple_select_small.js | 8 +- build/generate-access-token-script.js | 22 +- cloudformation/ci.template.js | 32 +- debug/access_token.js | 2 +- dist/mapbox-gl-draw.css | 52 +- index.ts | 2 +- rollup.config.js | 4 +- src/api.ts | 98 +- src/events.ts | 88 +- src/feature_types/feature.ts | 38 +- src/feature_types/line_string.ts | 12 +- src/feature_types/multi_feature.ts | 61 +- src/feature_types/point.ts | 14 +- src/feature_types/polygon.ts | 18 +- src/lib/common_selectors.ts | 14 +- src/lib/constrain_feature_movement.ts | 15 +- src/lib/create_midpoint.ts | 8 +- src/lib/create_supplementary_points.ts | 25 +- src/lib/create_vertex.ts | 6 +- src/lib/double_click_zoom.ts | 9 +- src/lib/euclidean_distance.ts | 4 +- src/lib/features_at.ts | 21 +- src/lib/get_features_at_and_set_cursor.ts | 8 +- src/lib/id.ts | 5 +- src/lib/index.ts | 2 +- src/lib/is_click.ts | 14 +- src/lib/is_event_at_coordinates.ts | 4 +- src/lib/is_tap.ts | 7 +- src/lib/map_event_to_bounding_box.ts | 5 +- src/lib/mode_handler.ts | 4 +- src/lib/move_features.ts | 21 +- src/lib/sort_features.ts | 32 +- src/lib/string_set.ts | 15 +- src/lib/string_sets_are_equal.ts | 7 +- src/lib/theme.ts | 157 +-- src/modes/direct_select.ts | 83 +- src/modes/draw_line_string.ts | 116 +- src/modes/draw_point.ts | 20 +- src/modes/draw_polygon.ts | 87 +- src/modes/mode_interface.ts | 37 +- src/modes/mode_interface_accessors.ts | 69 +- src/modes/object_to_mode.ts | 7 +- src/modes/simple_select.ts | 127 +- src/options.ts | 11 +- src/render.ts | 28 +- src/setup.ts | 15 +- src/store.ts | 121 +- src/types/types.ts | 141 ++- src/ui.ts | 110 +- test/api.test.js | 509 +++++--- test/common_selectors.test.js | 529 ++++---- test/constrain_feature_movement.test.js | 417 ++++-- test/create_supplementary_points.test.js | 1120 +++++++++-------- test/create_vertex.test.js | 2 - test/direct_select.test.js | 607 +++++---- test/draw_line_string.test.js | 531 +++++--- test/draw_point.test.js | 146 ++- test/draw_polygon.test.js | 847 +++++++++---- test/euclidean_distance.test.js | 10 +- test/feature.test.js | 91 +- test/features_at.test.js | 335 +++-- test/interaction_events.test.js | 819 +++++++----- test/is_click.test.js | 61 +- test/is_event_at_coordinates.test.js | 47 +- test/is_tap.test.js | 24 +- test/line_string.test.js | 147 ++- test/map_event_to_bounding_box.test.js | 60 +- test/mock-browser.js | 4 +- test/mode_handler.test.js | 204 ++- test/move_features.test.js | 226 +++- test/multi_feature.test.js | 366 ++++-- test/options.test.js | 92 +- test/point.test.js | 58 +- test/polygon.test.js | 296 ++++- test/simple_select.test.js | 1099 +++++++++++----- test/sort_features.test.js | 40 +- test/static.test.js | 18 +- test/store.test.js | 246 +++- test/string_set.test.js | 42 +- test/ui.test.js | 333 ++++- test/utils/create_feature.js | 17 +- test/utils/create_map.js | 23 +- test/utils/create_mock_draw_mode_context.js | 2 +- test/utils/create_mock_feature_context.js | 6 +- test/utils/create_mock_lifecycle_context.js | 2 +- test/utils/create_mock_mode.js | 2 +- .../utils/create_mock_mode_handler_context.js | 2 +- test/utils/draw_geometry.js | 2 +- test/utils/get_geojson.js | 122 +- test/utils/key_events.js | 2 +- test/utils/make_mouse_event.js | 21 +- test/utils/make_touch_event.js | 23 +- vite.config.js | 2 +- 124 files changed, 7879 insertions(+), 3883 deletions(-) diff --git a/bench/index.js b/bench/index.js index b84836d9..2c632f70 100644 --- a/bench/index.js +++ b/bench/index.js @@ -35,7 +35,7 @@ function main() { draw_point_small: require('./tests/draw_point_small'), draw_point_large: require('./tests/draw_point_large'), - draw_point_large_zoomed: require('./tests/draw_point_large_zoomed'), + draw_point_large_zoomed: require('./tests/draw_point_large_zoomed') }; const benchmarkName = location.hash.substr(1); @@ -46,7 +46,7 @@ function main() { let innerHTML = ''; - tests.forEach((test) => { + tests.forEach(test => { innerHTML += '
'; innerHTML += `${test}`; innerHTML += '
'; @@ -59,7 +59,10 @@ function main() { window.addEventListener('hashchange', () => location.reload(), false); - log('dark', 'please keep this window in the foreground and close the debugger'); + log( + 'dark', + 'please keep this window in the foreground and close the debugger' + ); const Benchmark = benchmarks[benchmarkName]; if (!Benchmark) { @@ -72,30 +75,30 @@ function main() { createMap }); - bench.on('log', (event) => { + bench.on('log', event => { log(event.color || 'blue', event.message); }); - bench.on('pass', (event) => { + bench.on('pass', event => { log('green', `${event.message}`); }); - bench.on('fail', (event) => { + bench.on('fail', event => { log('red', `${event.message}`); }); } function log(color, message) { - document.getElementById('logs').innerHTML += `

${message}

`; + document.getElementById('logs').innerHTML += + `

${message}

`; } function getAccessToken() { - const accessToken = ( + const accessToken = process.env.MapboxAccessToken || - process.env.MAPBOX_ACCESS_TOKEN || - getURLParameter('access_token') || - localStorage.getItem('accessToken') - ); + process.env.MAPBOX_ACCESS_TOKEN || + getURLParameter('access_token') || + localStorage.getItem('accessToken'); localStorage.setItem('accessToken', accessToken); return accessToken; } @@ -109,7 +112,7 @@ function getURLParameter(name) { function createMap(options) { const mapElement = document.getElementById('map'); - options = Object.assign({width: 512, height: 512}, options); + options = Object.assign({ width: 512, height: 512 }, options); mapElement.style.display = 'block'; mapElement.style.width = `${options.width}px`; @@ -117,9 +120,14 @@ function createMap(options) { mapboxgl.accessToken = getAccessToken(); - const map = new mapboxgl.Map(Object.assign({ - container: 'map' - }, options)); + const map = new mapboxgl.Map( + Object.assign( + { + container: 'map' + }, + options + ) + ); const draw = new MapboxDraw(options); diff --git a/bench/lib/evented.js b/bench/lib/evented.js index 3a69db51..a55abf16 100644 --- a/bench/lib/evented.js +++ b/bench/lib/evented.js @@ -1,4 +1,3 @@ - export default class Evented { on(type, listener) { if (!listener) { diff --git a/bench/lib/format_number.js b/bench/lib/format_number.js index 40846715..e77f91a1 100644 --- a/bench/lib/format_number.js +++ b/bench/lib/format_number.js @@ -1,5 +1,7 @@ 'use strict'; export default function formatNumber(x) { - return Math.round(x).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return Math.round(x) + .toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ','); } diff --git a/bench/lib/fps.js b/bench/lib/fps.js index 948c7890..de62794b 100644 --- a/bench/lib/fps.js +++ b/bench/lib/fps.js @@ -1,9 +1,9 @@ -export default function() { +export default function () { let frameCount = 0; let start = null; let running = false; - const frameCounter = function() { + const frameCounter = function () { if (running) { frameCount++; requestAnimationFrame(frameCounter); diff --git a/bench/lib/mouse_drag.js b/bench/lib/mouse_drag.js index 5f2a4faa..ae7010f2 100644 --- a/bench/lib/mouse_drag.js +++ b/bench/lib/mouse_drag.js @@ -1,15 +1,18 @@ import mouseEvents from './mouse_events'; import mousePath from './mouse_path'; -export default function(start, map) { - +export default function (start, map) { const path = mousePath(start); const events = mouseEvents(map); - events.push('mousedown', { - x: start.x, - y: start.y - }, true); + events.push( + 'mousedown', + { + x: start.x, + y: start.y + }, + true + ); for (let i = 0; i < path.length; i++) { events.push('mousemove', path[i]); @@ -23,7 +26,7 @@ export default function(start, map) { y: start.y }); - return function(cb) { + return function (cb) { events.run(cb); }; } diff --git a/bench/lib/mouse_draw.js b/bench/lib/mouse_draw.js index 4ebbc7b6..0a088cdc 100644 --- a/bench/lib/mouse_draw.js +++ b/bench/lib/mouse_draw.js @@ -1,7 +1,7 @@ import mouseEvents from './mouse_events'; import mousePath from './mouse_path'; -export default function(start, map) { +export default function (start, map) { const path = mousePath(start); const events = mouseEvents(map); @@ -24,7 +24,7 @@ export default function(start, map) { events.push('mouseup', path[path.length - 1]); - return function(cb) { + return function (cb) { events.run(cb); }; } diff --git a/bench/lib/mouse_events.js b/bench/lib/mouse_events.js index 850576a4..294aa780 100644 --- a/bench/lib/mouse_events.js +++ b/bench/lib/mouse_events.js @@ -1,7 +1,7 @@ -export default function(map) { +export default function (map) { const events = []; - events.push = function(event, point, dp) { + events.push = function (event, point, dp) { const payload = { dropPoint: dp === undefined ? false : dp, originalEvent: { @@ -14,15 +14,15 @@ export default function(map) { events[events.length] = [event, payload]; }; - events.run = function(cb) { + events.run = function (cb) { const one = 100 / events.length; - const runner = function(i) { + const runner = function (i) { const event = events[i]; if (event === undefined) { cb(); } else { map.fire(event[0], event[1]); - map.fire('progress', {done:Math.ceil(one * i)}); + map.fire('progress', { done: Math.ceil(one * i) }); setTimeout(() => { runner(i + 1); }, 0); diff --git a/bench/lib/mouse_path.js b/bench/lib/mouse_path.js index 057d8414..3b22b132 100644 --- a/bench/lib/mouse_path.js +++ b/bench/lib/mouse_path.js @@ -1,15 +1,15 @@ -export default function(start) { +export default function (start) { const path = []; - for (let i = 0; i < 7; i += .04) { + for (let i = 0; i < 7; i += 0.04) { const A = 3; const B = Math.PI / 2; const SIZE = 100; const OFFSET = 5; - const x = start.x + (Math.sin(i) * SIZE) + (i * OFFSET); - const y = start.y + (Math.sin(A * i + B) * SIZE) + (i * OFFSET); - path.push({x, y}); + const x = start.x + Math.sin(i) * SIZE + i * OFFSET; + const y = start.y + Math.sin(A * i + B) * SIZE + i * OFFSET; + path.push({ x, y }); } return path; diff --git a/bench/lib/mouse_trace.js b/bench/lib/mouse_trace.js index eddfb4a5..9947840d 100644 --- a/bench/lib/mouse_trace.js +++ b/bench/lib/mouse_trace.js @@ -1,7 +1,6 @@ import mouseEvents from './mouse_events'; -export default function(ring, map) { - +export default function (ring, map) { const events = mouseEvents(map); let lastPoint = null; @@ -24,7 +23,7 @@ export default function(ring, map) { events.push('mouseup', lastPoint); } - return function(cb) { + return function (cb) { events.run(cb); }; } diff --git a/bench/lib/trace_progress.js b/bench/lib/trace_progress.js index 16ae271c..c70a5b8f 100644 --- a/bench/lib/trace_progress.js +++ b/bench/lib/trace_progress.js @@ -1,4 +1,4 @@ -export default function(features, map) { +export default function (features, map) { const sizes = []; let total = 0; for (const feature of features) { @@ -18,7 +18,7 @@ export default function(features, map) { let pos = 0; let lastDone = -1; - map.on('progress', (e) => { + map.on('progress', e => { if (e.done < lastDone) { pos++; } @@ -27,7 +27,7 @@ export default function(features, map) { for (let i = 0; i < pos; i++) { done += sizes[i]; } - done += (sizes[pos] * e.done / 100); + done += (sizes[pos] * e.done) / 100; progressDiv.style.width = `${done}%`; }); } diff --git a/bench/rollup.config.js b/bench/rollup.config.js index 8bc945ac..0d1561ca 100644 --- a/bench/rollup.config.js +++ b/bench/rollup.config.js @@ -15,8 +15,12 @@ export default { plugins: [ json(), replace({ - 'process.env.MapboxAccessToken': JSON.stringify(process.env.MapboxAccessToken), - 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN), + 'process.env.MapboxAccessToken': JSON.stringify( + process.env.MapboxAccessToken + ), + 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify( + process.env.MAPBOX_ACCESS_TOKEN + ), preventAssignment: true }), resolve({ @@ -28,5 +32,5 @@ export default { // https://github.com/mapbox/mapbox-gl-js/pull/6956 ignoreGlobal: true }) - ], + ] }; diff --git a/bench/tests/direct_select_large.js b/bench/tests/direct_select_large.js index 6f98ccf0..ca5f4b41 100644 --- a/bench/tests/direct_select_large.js +++ b/bench/tests/direct_select_large.js @@ -6,19 +6,19 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = {x: 445, y: 293}; +const START = { x: 445, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width: 1024}); + const out = options.createMap({ width: 1024 }); // eslint-disable-next-line new-cap const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -27,15 +27,17 @@ export default class Benchmark extends Evented { out.draw.changeMode('direct_select', { featureId: SouthAmerica.id }); setTimeout(() => { - this.fire('log', {message: 'normal - 41fps'}); + this.fire('log', { message: 'normal - 41fps' }); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); diff --git a/bench/tests/direct_select_large_zoomed.js b/bench/tests/direct_select_large_zoomed.js index 74ddfa7b..d31243bc 100644 --- a/bench/tests/direct_select_large_zoomed.js +++ b/bench/tests/direct_select_large_zoomed.js @@ -6,14 +6,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = {x: 339, y: 282}; +const START = { x: 339, y: 282 }; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width:1024, + width: 1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -22,7 +22,7 @@ export default class Benchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -31,15 +31,17 @@ export default class Benchmark extends Evented { out.draw.changeMode('direct_select', { featureId: SouthAmerica.id }); setTimeout(() => { - this.fire('log', {message: 'normal - 26fps'}); + this.fire('log', { message: 'normal - 26fps' }); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); diff --git a/bench/tests/direct_select_small.js b/bench/tests/direct_select_small.js index 11317ac4..a4866019 100644 --- a/bench/tests/direct_select_small.js +++ b/bench/tests/direct_select_small.js @@ -6,7 +6,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { @@ -18,7 +18,7 @@ export default class Benchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -32,9 +32,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); diff --git a/bench/tests/direct_select_small_zoomed.js b/bench/tests/direct_select_small_zoomed.js index ce5baa3d..1e73db6a 100644 --- a/bench/tests/direct_select_small_zoomed.js +++ b/bench/tests/direct_select_small_zoomed.js @@ -6,7 +6,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = {x: 85, y: 282}; +const START = { x: 85, y: 282 }; export default class Benchmark extends Evented { constructor(options) { @@ -21,7 +21,7 @@ export default class Benchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -35,9 +35,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); diff --git a/bench/tests/draw_land_polygon_large.js b/bench/tests/draw_land_polygon_large.js index 619cda7c..9d4ac1a7 100644 --- a/bench/tests/draw_land_polygon_large.js +++ b/bench/tests/draw_land_polygon_large.js @@ -11,11 +11,11 @@ export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width:1024}); + const out = options.createMap({ width: 1024 }); const drawing = []; - land.features.forEach((feature) => { - feature.geometry.coordinates.forEach((ring) => { + land.features.forEach(feature => { + feature.geometry.coordinates.forEach(ring => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function(cb) { - const runner = function(count) { + const traceMouse = function (cb) { + const runner = function (count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,9 +45,11 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_land_polygon_small.js b/bench/tests/draw_land_polygon_small.js index 5d287ba9..9b626b1a 100644 --- a/bench/tests/draw_land_polygon_small.js +++ b/bench/tests/draw_land_polygon_small.js @@ -14,8 +14,8 @@ export default class Benchmark extends Evented { const out = options.createMap(); const drawing = []; - land.features.forEach((feature) => { - feature.geometry.coordinates.forEach((ring) => { + land.features.forEach(feature => { + feature.geometry.coordinates.forEach(ring => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function(cb) { - const runner = function(count) { + const traceMouse = function (cb) { + const runner = function (count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,9 +45,11 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_line_string_large.js b/bench/tests/draw_line_string_large.js index a33a2c39..4c30fcff 100644 --- a/bench/tests/draw_line_string_large.js +++ b/bench/tests/draw_line_string_large.js @@ -5,19 +5,19 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width:1024}); + const out = options.createMap({ width: 1024 }); // eslint-disable-next-line new-cap const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -30,9 +30,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_line_string_large_zoomed.js b/bench/tests/draw_line_string_large_zoomed.js index f8b8a7b1..8be6c258 100644 --- a/bench/tests/draw_line_string_large_zoomed.js +++ b/bench/tests/draw_line_string_large_zoomed.js @@ -5,14 +5,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width:1024, + width: 1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -21,7 +21,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -34,9 +34,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_line_string_small.js b/bench/tests/draw_line_string_small.js index 26101255..323d6ca4 100644 --- a/bench/tests/draw_line_string_small.js +++ b/bench/tests/draw_line_string_small.js @@ -5,7 +5,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { @@ -17,7 +17,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -30,9 +30,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_point_large.js b/bench/tests/draw_point_large.js index 3ffa75c7..b7d97566 100644 --- a/bench/tests/draw_point_large.js +++ b/bench/tests/draw_point_large.js @@ -5,24 +5,24 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width:1024}); + const out = options.createMap({ width: 1024 }); // eslint-disable-next-line new-cap const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); out.map.on('load', () => { - out.map.on('draw.modechange', (e) => { + out.map.on('draw.modechange', e => { if (e.mode === 'simple_select') { out.draw.changeMode('draw_point'); } @@ -35,9 +35,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -45,5 +47,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/draw_point_large_zoomed.js b/bench/tests/draw_point_large_zoomed.js index afe6dd0c..eaacc46f 100644 --- a/bench/tests/draw_point_large_zoomed.js +++ b/bench/tests/draw_point_large_zoomed.js @@ -5,14 +5,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width:1024, + width: 1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -21,12 +21,12 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); out.map.on('load', () => { - out.map.on('draw.modechange', (e) => { + out.map.on('draw.modechange', e => { if (e.mode === 'simple_select') { out.draw.changeMode('draw_point'); } @@ -39,9 +39,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_point_small.js b/bench/tests/draw_point_small.js index b609a510..c696d866 100644 --- a/bench/tests/draw_point_small.js +++ b/bench/tests/draw_point_small.js @@ -5,7 +5,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { @@ -17,12 +17,12 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); out.map.on('load', () => { - out.map.on('draw.modechange', (e) => { + out.map.on('draw.modechange', e => { if (e.mode === 'simple_select') { out.draw.changeMode('draw_point'); } @@ -35,9 +35,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -45,5 +47,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/draw_polygon_large.js b/bench/tests/draw_polygon_large.js index f8853128..0da51f55 100644 --- a/bench/tests/draw_polygon_large.js +++ b/bench/tests/draw_polygon_large.js @@ -5,19 +5,19 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width:1024}); + const out = options.createMap({ width: 1024 }); // eslint-disable-next-line new-cap const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -30,9 +30,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -40,5 +42,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/draw_polygon_large_zoomed.js b/bench/tests/draw_polygon_large_zoomed.js index b24eca41..b4f2ead1 100644 --- a/bench/tests/draw_polygon_large_zoomed.js +++ b/bench/tests/draw_polygon_large_zoomed.js @@ -5,14 +5,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width:1024, + width: 1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -21,7 +21,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -34,9 +34,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -44,5 +46,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/draw_polygon_small.js b/bench/tests/draw_polygon_small.js index cafb5f5d..de767cae 100644 --- a/bench/tests/draw_polygon_small.js +++ b/bench/tests/draw_polygon_small.js @@ -5,7 +5,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = {x: 189, y: 293}; +const START = { x: 189, y: 293 }; export default class Benchmark extends Evented { constructor(options) { @@ -17,7 +17,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -30,9 +30,11 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -40,5 +42,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/draw_urban_areas_polygon_large.js b/bench/tests/draw_urban_areas_polygon_large.js index 6b5c74d0..e4a9b84a 100644 --- a/bench/tests/draw_urban_areas_polygon_large.js +++ b/bench/tests/draw_urban_areas_polygon_large.js @@ -11,11 +11,11 @@ export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width:1024}); + const out = options.createMap({ width: 1024 }); const drawing = []; - land.features.forEach((feature) => { - feature.geometry.coordinates.forEach((ring) => { + land.features.forEach(feature => { + feature.geometry.coordinates.forEach(ring => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function(cb) { - const runner = function(count) { + const traceMouse = function (cb) { + const runner = function (count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,9 +45,11 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -55,5 +57,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/draw_urban_areas_polygon_small.js b/bench/tests/draw_urban_areas_polygon_small.js index 6ad92374..9ed5d73e 100644 --- a/bench/tests/draw_urban_areas_polygon_small.js +++ b/bench/tests/draw_urban_areas_polygon_small.js @@ -14,8 +14,8 @@ export default class Benchmark extends Evented { const out = options.createMap(); const drawing = []; - land.features.forEach((feature) => { - feature.geometry.coordinates.forEach((ring) => { + land.features.forEach(feature => { + feature.geometry.coordinates.forEach(ring => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function(cb) { - const runner = function(count) { + const traceMouse = function (cb) { + const runner = function (count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,9 +45,11 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } out.draw.changeMode('simple_select'); }); @@ -55,5 +57,3 @@ export default class Benchmark extends Evented { }); } } - - diff --git a/bench/tests/simple_select_large.js b/bench/tests/simple_select_large.js index 0d4a63f3..22f80fb6 100644 --- a/bench/tests/simple_select_large.js +++ b/bench/tests/simple_select_large.js @@ -14,10 +14,10 @@ const START = { export default class SimpleSelectLargeBenchmark extends Evented { constructor(options) { super(); - const out = options.createMap({width:1024}); + const out = options.createMap({ width: 1024 }); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -28,20 +28,20 @@ export default class SimpleSelectLargeBenchmark extends Evented { out.draw.add(SouthAmerica); setTimeout(() => { - this.fire('log', {message: 'normal - 43fps'}); + this.fire('log', { message: 'normal - 43fps' }); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); }); } } - - diff --git a/bench/tests/simple_select_large_two_maps.js b/bench/tests/simple_select_large_two_maps.js index 16ad2c51..ef3c1c50 100644 --- a/bench/tests/simple_select_large_two_maps.js +++ b/bench/tests/simple_select_large_two_maps.js @@ -12,28 +12,25 @@ const START = { }; const emptyStyle = { - "version": 8, - "name": "Empty", - "center": [ - 0, - -1.1368683772161603e-13 - ], - "zoom": 0.4051413497691584, - "bearing": 0, - "pitch": 0, - "sources": {}, - "layers": [], + version: 8, + name: 'Empty', + center: [0, -1.1368683772161603e-13], + zoom: 0.4051413497691584, + bearing: 0, + pitch: 0, + sources: {}, + layers: [] }; export default class SimpleSelectLargeTwoMapsBenchmark extends Evented { constructor(options) { super(); // eslint-disable-next-line no-unused-vars - const background = options.createMap({'container': 'backmap', width:1024}); - const out = options.createMap({width: 1024, style: emptyStyle}); + const background = options.createMap({ container: 'backmap', width: 1024 }); + const out = options.createMap({ width: 1024, style: emptyStyle }); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -44,20 +41,20 @@ export default class SimpleSelectLargeTwoMapsBenchmark extends Evented { out.draw.add(SouthAmerica); setTimeout(() => { - this.fire('log', {message: 'normal - 43fps'}); + this.fire('log', { message: 'normal - 43fps' }); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); }); } } - - diff --git a/bench/tests/simple_select_large_zoomed.js b/bench/tests/simple_select_large_zoomed.js index 12cc8e96..59c194bb 100644 --- a/bench/tests/simple_select_large_zoomed.js +++ b/bench/tests/simple_select_large_zoomed.js @@ -16,7 +16,7 @@ export default class SimpleSelectLargeZoomedBenchmark extends Evented { super(); const out = options.createMap({ - width:1024, + width: 1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -25,7 +25,7 @@ export default class SimpleSelectLargeZoomedBenchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -33,20 +33,20 @@ export default class SimpleSelectLargeZoomedBenchmark extends Evented { out.draw.add(SouthAmerica); setTimeout(() => { - this.fire('log', {message: 'normal - 29fps'}); + this.fire('log', { message: 'normal - 29fps' }); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); }); } } - - diff --git a/bench/tests/simple_select_small.js b/bench/tests/simple_select_small.js index 1f361c7c..92fe358d 100644 --- a/bench/tests/simple_select_small.js +++ b/bench/tests/simple_select_small.js @@ -20,7 +20,7 @@ export default class SimpleSelectSmallBenchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', (e) => { + out.map.on('progress', e => { progressDiv.style.width = `${e.done}%`; }); @@ -33,9 +33,11 @@ export default class SimpleSelectSmallBenchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); + this.fire('fail', { + message: `${formatNumber(fps)} fps - expected 55fps or better` + }); } else { - this.fire('pass', {message: `${formatNumber(fps)} fps`}); + this.fire('pass', { message: `${formatNumber(fps)} fps` }); } }); }, 2000); diff --git a/build/generate-access-token-script.js b/build/generate-access-token-script.js index 22709381..42898404 100644 --- a/build/generate-access-token-script.js +++ b/build/generate-access-token-script.js @@ -1,13 +1,21 @@ import fs from 'fs'; import path from 'path'; -import {fileURLToPath} from 'url'; +import { fileURLToPath } from 'url'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); -const script = fs.readFileSync(path.join(__dirname, '../debug/access_token.js'), 'utf-8') - .replace('process.env.MapboxAccessToken', - JSON.stringify(process.env.MapboxAccessToken)) - .replace('process.env.MAPBOX_ACCESS_TOKEN', - JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN)); +const script = fs + .readFileSync(path.join(__dirname, '../debug/access_token.js'), 'utf-8') + .replace( + 'process.env.MapboxAccessToken', + JSON.stringify(process.env.MapboxAccessToken) + ) + .replace( + 'process.env.MAPBOX_ACCESS_TOKEN', + JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN) + ); -fs.writeFileSync(path.join(__dirname, '../debug/access_token_generated.js'), script); +fs.writeFileSync( + path.join(__dirname, '../debug/access_token_generated.js'), + script +); diff --git a/cloudformation/ci.template.js b/cloudformation/ci.template.js index 591201e6..3d35b9c7 100644 --- a/cloudformation/ci.template.js +++ b/cloudformation/ci.template.js @@ -7,17 +7,13 @@ module.exports = { Properties: { Policies: [ { - "PolicyName": "list", - "PolicyDocument": { - "Statement": [ + PolicyName: 'list', + PolicyDocument: { + Statement: [ { - "Action": [ - "s3:ListBucket" - ], - "Effect": "Allow", - "Resource": [ - "arn:aws:s3:::mapbox-gl-js" - ] + Action: ['s3:ListBucket'], + Effect: 'Allow', + Resource: ['arn:aws:s3:::mapbox-gl-js'] } ] } @@ -27,15 +23,15 @@ module.exports = { PolicyDocument: { Statement: [ { - "Action": [ - "s3:GetObject", - "s3:GetObjectAcl", - "s3:PutObject", - "s3:PutObjectAcl" + Action: [ + 's3:GetObject', + 's3:GetObjectAcl', + 's3:PutObject', + 's3:PutObjectAcl' ], - "Effect": "Allow", - "Resource": [ - "arn:aws:s3:::mapbox-gl-js/plugins/mapbox-gl-draw/*" + Effect: 'Allow', + Resource: [ + 'arn:aws:s3:::mapbox-gl-js/plugins/mapbox-gl-draw/*' ] } ] diff --git a/debug/access_token.js b/debug/access_token.js index 48c3f841..d039d0fd 100644 --- a/debug/access_token.js +++ b/debug/access_token.js @@ -2,7 +2,7 @@ export function getAccessToken() { const accessToken = process.env.MapboxAccessToken || process.env.MAPBOX_ACCESS_TOKEN || - (new URLSearchParams(location.search).get('access_token')) || + new URLSearchParams(location.search).get('access_token') || localStorage.getItem('accessToken'); localStorage.setItem('accessToken', accessToken); diff --git a/dist/mapbox-gl-draw.css b/dist/mapbox-gl-draw.css index 0347a271..fe35d397 100644 --- a/dist/mapbox-gl-draw.css +++ b/dist/mapbox-gl-draw.css @@ -1,26 +1,25 @@ - /* Override default control style */ .mapbox-gl-draw_ctrl-bottom-left, .mapbox-gl-draw_ctrl-top-left { - margin-left:0; - border-radius:0 4px 4px 0; + margin-left: 0; + border-radius: 0 4px 4px 0; } .mapbox-gl-draw_ctrl-top-right, .mapbox-gl-draw_ctrl-bottom-right { - margin-right:0; - border-radius:4px 0 0 4px; + margin-right: 0; + border-radius: 4px 0 0 4px; } .mapbox-gl-draw_ctrl-draw-btn { - border-color:rgba(0,0,0,0.9); - color:rgba(255,255,255,0.5); - width:30px; - height:30px; + border-color: rgba(0, 0, 0, 0.9); + color: rgba(255, 255, 255, 0.5); + width: 30px; + height: 30px; } .mapbox-gl-draw_ctrl-draw-btn.active, .mapbox-gl-draw_ctrl-draw-btn.active:hover { - background-color:rgb(0 0 0/5%); + background-color: rgb(0 0 0/5%); } .mapbox-gl-draw_ctrl-draw-btn { background-repeat: no-repeat; @@ -55,34 +54,39 @@ .mapboxgl-map.mouse-add .mapboxgl-canvas-container.mapboxgl-interactive { cursor: crosshair; } -.mapboxgl-map.mouse-move.mode-direct_select .mapboxgl-canvas-container.mapboxgl-interactive { +.mapboxgl-map.mouse-move.mode-direct_select + .mapboxgl-canvas-container.mapboxgl-interactive { cursor: grab; cursor: -moz-grab; cursor: -webkit-grab; } -.mapboxgl-map.mode-direct_select.feature-vertex.mouse-move .mapboxgl-canvas-container.mapboxgl-interactive { +.mapboxgl-map.mode-direct_select.feature-vertex.mouse-move + .mapboxgl-canvas-container.mapboxgl-interactive { cursor: move; } -.mapboxgl-map.mode-direct_select.feature-midpoint.mouse-pointer .mapboxgl-canvas-container.mapboxgl-interactive { +.mapboxgl-map.mode-direct_select.feature-midpoint.mouse-pointer + .mapboxgl-canvas-container.mapboxgl-interactive { cursor: cell; } -.mapboxgl-map.mode-direct_select.feature-feature.mouse-move .mapboxgl-canvas-container.mapboxgl-interactive { +.mapboxgl-map.mode-direct_select.feature-feature.mouse-move + .mapboxgl-canvas-container.mapboxgl-interactive { cursor: move; } -.mapboxgl-map.mode-static.mouse-pointer .mapboxgl-canvas-container.mapboxgl-interactive { +.mapboxgl-map.mode-static.mouse-pointer + .mapboxgl-canvas-container.mapboxgl-interactive { cursor: grab; cursor: -moz-grab; cursor: -webkit-grab; } .mapbox-gl-draw_boxselect { - pointer-events: none; - position: absolute; - top: 0; - left: 0; - width: 0; - height: 0; - background: rgba(0,0,0,.1); - border: 2px dotted #fff; - opacity: 0.5; + pointer-events: none; + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; + background: rgba(0, 0, 0, 0.1); + border: 2px dotted #fff; + opacity: 0.5; } diff --git a/index.ts b/index.ts index c2025b15..4740c73a 100644 --- a/index.ts +++ b/index.ts @@ -4,7 +4,7 @@ import setupAPI from './src/api'; import * as modes from './src/modes/index'; import * as Constants from './src/constants'; import * as lib from './src/lib/index'; -import type { DrawOptions, Draw } from './src/types/types' +import type { DrawOptions, Draw } from './src/types/types'; const setupDraw = (options: DrawOptions, api: Draw) => { options = setupOptions(options); diff --git a/rollup.config.js b/rollup.config.js index e0455fdb..6ef06f75 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,6 +1,8 @@ const { MINIFY } = process.env; const minified = MINIFY === 'true'; -const outputFile = minified ? 'dist/mapbox-gl-draw.js' : 'dist/mapbox-gl-draw-unminified.js'; +const outputFile = minified + ? 'dist/mapbox-gl-draw.js' + : 'dist/mapbox-gl-draw-unminified.js'; import typescript from '@rollup/plugin-typescript'; diff --git a/src/api.ts b/src/api.ts index 90b0bfbb..d7fd8bd2 100644 --- a/src/api.ts +++ b/src/api.ts @@ -20,29 +20,35 @@ const featureTypes = { MultiPoint: MultiFeature }; -export default function(ctx, api) { +export default function (ctx, api) { api.modes = Constants.modes; // API doesn't emit events by default - const silent = ctx.options.suppressAPIEvents !== undefined ? !!ctx.options.suppressAPIEvents : true; + const silent = + ctx.options.suppressAPIEvents !== undefined + ? !!ctx.options.suppressAPIEvents + : true; - api.getFeatureIdsAt = function(point) { + api.getFeatureIdsAt = function (point) { const features = featuresAt.click({ point }, null, ctx); return features.map(feature => feature.properties.id); }; - api.getSelectedIds = function() { + api.getSelectedIds = function () { return ctx.store.getSelectedIds(); }; - api.getSelected = function() { + api.getSelected = function () { return { type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store.getSelectedIds().map(id => ctx.store.get(id)).map(feature => feature.toGeoJSON()) + features: ctx.store + .getSelectedIds() + .map(id => ctx.store.get(id)) + .map(feature => feature.toGeoJSON()) }; }; - api.getSelectedPoints = function() { + api.getSelectedPoints = function () { return { type: Constants.geojsonTypes.FEATURE_COLLECTION, features: ctx.store.getSelectedCoordinates().map(coordinate => ({ @@ -56,8 +62,12 @@ export default function(ctx, api) { }; }; - api.set = function(featureCollection) { - if (featureCollection.type === undefined || featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || !Array.isArray(featureCollection.features)) { + api.set = function (featureCollection) { + if ( + featureCollection.type === undefined || + featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || + !Array.isArray(featureCollection.features) + ) { throw new Error('Invalid FeatureCollection'); } const renderBatch = ctx.store.createRenderBatch(); @@ -74,17 +84,20 @@ export default function(ctx, api) { return newIds; }; - api.add = function(geojson) { + api.add = function (geojson) { const featureCollection = JSON.parse(JSON.stringify(normalize(geojson))); - const ids = featureCollection.features.map((feature) => { + const ids = featureCollection.features.map(feature => { feature.id = feature.id || generateID(); if (feature.geometry === null) { throw new Error('Invalid geometry: null'); } - if (ctx.store.get(feature.id) === undefined || ctx.store.get(feature.id).type !== feature.geometry.type) { + if ( + ctx.store.get(feature.id) === undefined || + ctx.store.get(feature.id).type !== feature.geometry.type + ) { // If the feature has not yet been created ... const Model = featureTypes[feature.geometry.type]; if (Model === undefined) { @@ -100,7 +113,12 @@ export default function(ctx, api) { if (!isEqual(originalProperties, feature.properties)) { ctx.store.featureChanged(internalFeature.id, { silent }); } - if (!isEqual(internalFeature.getCoordinates(), feature.geometry.coordinates)) { + if ( + !isEqual( + internalFeature.getCoordinates(), + feature.geometry.coordinates + ) + ) { internalFeature.incomingCoords(feature.geometry.coordinates); } } @@ -111,27 +129,31 @@ export default function(ctx, api) { return ids; }; - - api.get = function(id) { + api.get = function (id) { const feature = ctx.store.get(id); if (feature) { return feature.toGeoJSON(); } }; - api.getAll = function() { + api.getAll = function () { return { type: Constants.geojsonTypes.FEATURE_COLLECTION, features: ctx.store.getAll().map(feature => feature.toGeoJSON()) }; }; - api.delete = function(featureIds) { + api.delete = function (featureIds) { ctx.store.delete(featureIds, { silent }); // If we were in direct select mode and our selected feature no longer exists // (because it was deleted), we need to get out of that mode. - if (api.getMode() === Constants.modes.DIRECT_SELECT && !ctx.store.getSelectedIds().length) { - ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { silent }); + if ( + api.getMode() === Constants.modes.DIRECT_SELECT && + !ctx.store.getSelectedIds().length + ) { + ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { + silent + }); } else { ctx.store.render(); } @@ -139,12 +161,14 @@ export default function(ctx, api) { return api; }; - api.deleteAll = function() { + api.deleteAll = function () { ctx.store.delete(ctx.store.getAllIds(), { silent }); // If we were in direct select mode, now our selected feature no longer exists, // so escape that mode. if (api.getMode() === Constants.modes.DIRECT_SELECT) { - ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { silent }); + ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { + silent + }); } else { ctx.store.render(); } @@ -152,10 +176,19 @@ export default function(ctx, api) { return api; }; - api.changeMode = function(mode, modeOptions = {}) { + api.changeMode = function (mode, modeOptions = {}) { // Avoid changing modes just to re-select what's already selected - if (mode === Constants.modes.SIMPLE_SELECT && api.getMode() === Constants.modes.SIMPLE_SELECT) { - if (stringSetsAreEqual((modeOptions.featureIds || []), ctx.store.getSelectedIds())) return api; + if ( + mode === Constants.modes.SIMPLE_SELECT && + api.getMode() === Constants.modes.SIMPLE_SELECT + ) { + if ( + stringSetsAreEqual( + modeOptions.featureIds || [], + ctx.store.getSelectedIds() + ) + ) + return api; // And if we are changing the selection within simple_select mode, just change the selection, // instead of stopping and re-starting the mode ctx.store.setSelected(modeOptions.featureIds, { silent }); @@ -163,8 +196,11 @@ export default function(ctx, api) { return api; } - if (mode === Constants.modes.DIRECT_SELECT && api.getMode() === Constants.modes.DIRECT_SELECT && - modeOptions.featureId === ctx.store.getSelectedIds()[0]) { + if ( + mode === Constants.modes.DIRECT_SELECT && + api.getMode() === Constants.modes.DIRECT_SELECT && + modeOptions.featureId === ctx.store.getSelectedIds()[0] + ) { return api; } @@ -172,26 +208,26 @@ export default function(ctx, api) { return api; }; - api.getMode = function() { + api.getMode = function () { return ctx.events.getMode(); }; - api.trash = function() { + api.trash = function () { ctx.events.trash({ silent }); return api; }; - api.combineFeatures = function() { + api.combineFeatures = function () { ctx.events.combineFeatures({ silent }); return api; }; - api.uncombineFeatures = function() { + api.uncombineFeatures = function () { ctx.events.uncombineFeatures({ silent }); return api; }; - api.setFeatureProperty = function(featureId, property, value) { + api.setFeatureProperty = function (featureId, property, value) { ctx.store.setFeatureProperty(featureId, property, value, { silent }); return api; }; diff --git a/src/events.ts b/src/events.ts index 73d52f26..58eb3207 100644 --- a/src/events.ts +++ b/src/events.ts @@ -6,8 +6,7 @@ import isTap from './lib/is_tap'; import * as Constants from './constants'; import objectToMode from './modes/object_to_mode'; -export default function(ctx) { - +export default function (ctx) { const modes = Object.keys(ctx.options.modes).reduce((m, k) => { m[k] = objectToMode(ctx.options.modes[k]); return m; @@ -19,11 +18,13 @@ export default function(ctx) { let currentModeName = null; let currentMode = null; - events.drag = function(event, isDrag) { - if (isDrag({ - point: event.point, - time: new Date().getTime() - })) { + events.drag = function (event, isDrag) { + if ( + isDrag({ + point: event.point, + time: new Date().getTime() + }) + ) { ctx.ui.queueMapClasses({ mouse: Constants.cursors.DRAG }); currentMode.drag(event); } else { @@ -31,16 +32,19 @@ export default function(ctx) { } }; - events.mousedrag = function(event) { + events.mousedrag = function (event) { events.drag(event, endInfo => !isClick(mouseDownInfo, endInfo)); }; - events.touchdrag = function(event) { + events.touchdrag = function (event) { events.drag(event, endInfo => !isTap(touchStartInfo, endInfo)); }; - events.mousemove = function(event) { - const button = event.originalEvent.buttons !== undefined ? event.originalEvent.buttons : event.originalEvent.which; + events.mousemove = function (event) { + const button = + event.originalEvent.buttons !== undefined + ? event.originalEvent.buttons + : event.originalEvent.which; if (button === 1) { return events.mousedrag(event); } @@ -49,7 +53,7 @@ export default function(ctx) { currentMode.mousemove(event); }; - events.mousedown = function(event) { + events.mousedown = function (event) { mouseDownInfo = { time: new Date().getTime(), point: event.point @@ -59,25 +63,27 @@ export default function(ctx) { currentMode.mousedown(event); }; - events.mouseup = function(event) { + events.mouseup = function (event) { const target = getFeatureAtAndSetCursors(event, ctx); event.featureTarget = target; - if (isClick(mouseDownInfo, { - point: event.point, - time: new Date().getTime() - })) { + if ( + isClick(mouseDownInfo, { + point: event.point, + time: new Date().getTime() + }) + ) { currentMode.click(event); } else { currentMode.mouseup(event); } }; - events.mouseout = function(event) { + events.mouseout = function (event) { currentMode.mouseout(event); }; - events.touchstart = function(event) { + events.touchstart = function (event) { if (!ctx.options.touchEnabled) { return; } @@ -91,7 +97,7 @@ export default function(ctx) { currentMode.touchstart(event); }; - events.touchmove = function(event) { + events.touchmove = function (event) { if (!ctx.options.touchEnabled) { return; } @@ -100,7 +106,7 @@ export default function(ctx) { return events.touchdrag(event); }; - events.touchend = function(event) { + events.touchend = function (event) { // Prevent emulated mouse events because we will fully handle the touch here. // This does not stop the touch events from propogating to mapbox though. event.originalEvent.preventDefault(); @@ -110,10 +116,12 @@ export default function(ctx) { const target = featuresAt.touch(event, null, ctx)[0]; event.featureTarget = target; - if (isTap(touchStartInfo, { - time: new Date().getTime(), - point: event.point - })) { + if ( + isTap(touchStartInfo, { + time: new Date().getTime(), + point: event.point + }) + ) { currentMode.tap(event); } else { currentMode.touchend(event); @@ -122,13 +130,19 @@ export default function(ctx) { // 8 - Backspace // 46 - Delete - const isKeyModeValid = code => !(code === 8 || code === 46 || (code >= 48 && code <= 57)); + const isKeyModeValid = code => + !(code === 8 || code === 46 || (code >= 48 && code <= 57)); - events.keydown = function(event) { - const isMapElement = (event.srcElement || event.target).classList.contains(Constants.classes.CANVAS); + events.keydown = function (event) { + const isMapElement = (event.srcElement || event.target).classList.contains( + Constants.classes.CANVAS + ); if (!isMapElement) return; // we only handle events on the map - if ((event.keyCode === 8 || event.keyCode === 46) && ctx.options.controls.trash) { + if ( + (event.keyCode === 8 || event.keyCode === 46) && + ctx.options.controls.trash + ) { event.preventDefault(); currentMode.trash(); } else if (isKeyModeValid(event.keyCode)) { @@ -142,17 +156,17 @@ export default function(ctx) { } }; - events.keyup = function(event) { + events.keyup = function (event) { if (isKeyModeValid(event.keyCode)) { currentMode.keyup(event); } }; - events.zoomend = function() { + events.zoomend = function () { ctx.store.changeZoom(); }; - events.data = function(event) { + events.data = function (event) { if (event.dataType === 'style') { const { setup, map, options, store } = ctx; const hasLayers = options.styles.some(style => map.getLayer(style.id)); @@ -176,7 +190,7 @@ export default function(ctx) { currentMode = setupModeHandler(mode, ctx); if (!eventOptions.silent) { - ctx.map.fire(Constants.events.MODE_CHANGE, { mode: modename}); + ctx.map.fire(Constants.events.MODE_CHANGE, { mode: modename }); } ctx.store.setDirty(); @@ -191,12 +205,14 @@ export default function(ctx) { function actionable(actions) { let changed = false; - Object.keys(actions).forEach((action) => { - if (actionState[action] === undefined) throw new Error('Invalid action type'); + Object.keys(actions).forEach(action => { + if (actionState[action] === undefined) + throw new Error('Invalid action type'); if (actionState[action] !== actions[action]) changed = true; actionState[action] = actions[action]; }); - if (changed) ctx.map.fire(Constants.events.ACTIONABLE, { actions: actionState }); + if (changed) + ctx.map.fire(Constants.events.ACTIONABLE, { actions: actionState }); } const api = { diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index 37634487..8b63c782 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -1,7 +1,7 @@ -import {generateID} from '../lib/id'; +import { generateID } from '../lib/id'; import * as Constants from '../constants'; -const Feature = function(ctx, geojson) { +const Feature = function (ctx, geojson) { this.ctx = ctx; this.properties = geojson.properties || {}; this.coordinates = geojson.geometry.coordinates; @@ -9,40 +9,42 @@ const Feature = function(ctx, geojson) { this.type = geojson.geometry.type; }; -Feature.prototype.changed = function() { +Feature.prototype.changed = function () { this.ctx.store.featureChanged(this.id); }; -Feature.prototype.incomingCoords = function(coords) { +Feature.prototype.incomingCoords = function (coords) { this.setCoordinates(coords); }; -Feature.prototype.setCoordinates = function(coords) { +Feature.prototype.setCoordinates = function (coords) { this.coordinates = coords; this.changed(); }; -Feature.prototype.getCoordinates = function() { +Feature.prototype.getCoordinates = function () { return JSON.parse(JSON.stringify(this.coordinates)); }; -Feature.prototype.setProperty = function(property, value) { +Feature.prototype.setProperty = function (property, value) { this.properties[property] = value; }; -Feature.prototype.toGeoJSON = function() { - return JSON.parse(JSON.stringify({ - id: this.id, - type: Constants.geojsonTypes.FEATURE, - properties: this.properties, - geometry: { - coordinates: this.getCoordinates(), - type: this.type - } - })); +Feature.prototype.toGeoJSON = function () { + return JSON.parse( + JSON.stringify({ + id: this.id, + type: Constants.geojsonTypes.FEATURE, + properties: this.properties, + geometry: { + coordinates: this.getCoordinates(), + type: this.type + } + }) + ); }; -Feature.prototype.internal = function(mode) { +Feature.prototype.internal = function (mode) { const properties = { id: this.id, meta: Constants.meta.FEATURE, diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index 8e23ca8c..b768f551 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -1,32 +1,32 @@ import Feature from './feature.js'; -const LineString = function(ctx, geojson) { +const LineString = function (ctx, geojson) { Feature.call(this, ctx, geojson); }; LineString.prototype = Object.create(Feature.prototype); -LineString.prototype.isValid = function() { +LineString.prototype.isValid = function () { return this.coordinates.length > 1; }; -LineString.prototype.addCoordinate = function(path, lng, lat) { +LineString.prototype.addCoordinate = function (path, lng, lat) { this.changed(); const id = parseInt(path, 10); this.coordinates.splice(id, 0, [lng, lat]); }; -LineString.prototype.getCoordinate = function(path) { +LineString.prototype.getCoordinate = function (path) { const id = parseInt(path, 10); return JSON.parse(JSON.stringify(this.coordinates[id])); }; -LineString.prototype.removeCoordinate = function(path) { +LineString.prototype.removeCoordinate = function (path) { this.changed(); this.coordinates.splice(parseInt(path, 10), 1); }; -LineString.prototype.updateCoordinate = function(path, lng, lat) { +LineString.prototype.updateCoordinate = function (path, lng, lat) { const id = parseInt(path, 10); this.coordinates[id] = [lng, lat]; this.changed(); diff --git a/src/feature_types/multi_feature.ts b/src/feature_types/multi_feature.ts index 552d1433..d762cf85 100644 --- a/src/feature_types/multi_feature.ts +++ b/src/feature_types/multi_feature.ts @@ -1,4 +1,4 @@ -import {generateID} from '../lib/id'; +import { generateID } from '../lib/id'; import Feature from './feature'; import * as Constants from '../constants'; @@ -15,70 +15,79 @@ const models = { const takeAction = (features, action, path, lng, lat) => { const parts = path.split('.'); const idx = parseInt(parts[0], 10); - const tail = (!parts[1]) ? null : parts.slice(1).join('.'); + const tail = !parts[1] ? null : parts.slice(1).join('.'); return features[idx][action](tail, lng, lat); }; -const MultiFeature = function(ctx, geojson) { +const MultiFeature = function (ctx, geojson) { Feature.call(this, ctx, geojson); delete this.coordinates; this.model = models[geojson.geometry.type]; - if (this.model === undefined) throw new TypeError(`${geojson.geometry.type} is not a valid type`); + if (this.model === undefined) + throw new TypeError(`${geojson.geometry.type} is not a valid type`); this.features = this._coordinatesToFeatures(geojson.geometry.coordinates); }; MultiFeature.prototype = Object.create(Feature.prototype); -MultiFeature.prototype._coordinatesToFeatures = function(coordinates) { +MultiFeature.prototype._coordinatesToFeatures = function (coordinates) { const Model = this.model.bind(this); - return coordinates.map(coords => new Model(this.ctx, { - id: generateID(), - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - coordinates: coords, - type: this.type.replace('Multi', '') - } - })); + return coordinates.map( + coords => + new Model(this.ctx, { + id: generateID(), + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + coordinates: coords, + type: this.type.replace('Multi', '') + } + }) + ); }; -MultiFeature.prototype.isValid = function() { +MultiFeature.prototype.isValid = function () { return this.features.every(f => f.isValid()); }; -MultiFeature.prototype.setCoordinates = function(coords) { +MultiFeature.prototype.setCoordinates = function (coords) { this.features = this._coordinatesToFeatures(coords); this.changed(); }; -MultiFeature.prototype.getCoordinate = function(path) { +MultiFeature.prototype.getCoordinate = function (path) { return takeAction(this.features, 'getCoordinate', path); }; -MultiFeature.prototype.getCoordinates = function() { - return JSON.parse(JSON.stringify(this.features.map((f) => { - if (f.type === Constants.geojsonTypes.POLYGON) return f.getCoordinates(); - return f.coordinates; - }))); +MultiFeature.prototype.getCoordinates = function () { + return JSON.parse( + JSON.stringify( + this.features.map(f => { + if (f.type === Constants.geojsonTypes.POLYGON) + return f.getCoordinates(); + return f.coordinates; + }) + ) + ); }; -MultiFeature.prototype.updateCoordinate = function(path, lng, lat) { +MultiFeature.prototype.updateCoordinate = function (path, lng, lat) { takeAction(this.features, 'updateCoordinate', path, lng, lat); this.changed(); }; -MultiFeature.prototype.addCoordinate = function(path, lng, lat) { +MultiFeature.prototype.addCoordinate = function (path, lng, lat) { takeAction(this.features, 'addCoordinate', path, lng, lat); this.changed(); }; -MultiFeature.prototype.removeCoordinate = function(path) { +MultiFeature.prototype.removeCoordinate = function (path) { takeAction(this.features, 'removeCoordinate', path); this.changed(); }; -MultiFeature.prototype.getFeatures = function() { +MultiFeature.prototype.getFeatures = function () { return this.features; }; diff --git a/src/feature_types/point.ts b/src/feature_types/point.ts index f0cc3eaf..d6217431 100644 --- a/src/feature_types/point.ts +++ b/src/feature_types/point.ts @@ -1,17 +1,19 @@ import Feature from './feature.js'; -const Point = function(ctx, geojson) { +const Point = function (ctx, geojson) { Feature.call(this, ctx, geojson); }; Point.prototype = Object.create(Feature.prototype); -Point.prototype.isValid = function() { - return typeof this.coordinates[0] === 'number' && - typeof this.coordinates[1] === 'number'; +Point.prototype.isValid = function () { + return ( + typeof this.coordinates[0] === 'number' && + typeof this.coordinates[1] === 'number' + ); }; -Point.prototype.updateCoordinate = function(pathOrLng, lngOrLat, lat) { +Point.prototype.updateCoordinate = function (pathOrLng, lngOrLat, lat) { if (arguments.length === 3) { this.coordinates = [lngOrLat, lat]; } else { @@ -20,7 +22,7 @@ Point.prototype.updateCoordinate = function(pathOrLng, lngOrLat, lat) { this.changed(); }; -Point.prototype.getCoordinate = function() { +Point.prototype.getCoordinate = function () { return this.getCoordinates(); }; diff --git a/src/feature_types/polygon.ts b/src/feature_types/polygon.ts index 64297887..fb125080 100644 --- a/src/feature_types/polygon.ts +++ b/src/feature_types/polygon.ts @@ -1,30 +1,30 @@ import Feature from './feature.js'; -const Polygon = function(ctx, geojson) { +const Polygon = function (ctx, geojson) { Feature.call(this, ctx, geojson); this.coordinates = this.coordinates.map(ring => ring.slice(0, -1)); }; Polygon.prototype = Object.create(Feature.prototype); -Polygon.prototype.isValid = function() { +Polygon.prototype.isValid = function () { if (this.coordinates.length === 0) return false; return this.coordinates.every(ring => ring.length > 2); }; // Expects valid geoJSON polygon geometry: first and last positions must be equivalent. -Polygon.prototype.incomingCoords = function(coords) { +Polygon.prototype.incomingCoords = function (coords) { this.coordinates = coords.map(ring => ring.slice(0, -1)); this.changed(); }; // Does NOT expect valid geoJSON polygon geometry: first and last positions should not be equivalent. -Polygon.prototype.setCoordinates = function(coords) { +Polygon.prototype.setCoordinates = function (coords) { this.coordinates = coords; this.changed(); }; -Polygon.prototype.addCoordinate = function(path, lng, lat) { +Polygon.prototype.addCoordinate = function (path, lng, lat) { this.changed(); const ids = path.split('.').map(x => parseInt(x, 10)); @@ -33,7 +33,7 @@ Polygon.prototype.addCoordinate = function(path, lng, lat) { ring.splice(ids[1], 0, [lng, lat]); }; -Polygon.prototype.removeCoordinate = function(path) { +Polygon.prototype.removeCoordinate = function (path) { this.changed(); const ids = path.split('.').map(x => parseInt(x, 10)); const ring = this.coordinates[ids[0]]; @@ -45,17 +45,17 @@ Polygon.prototype.removeCoordinate = function(path) { } }; -Polygon.prototype.getCoordinate = function(path) { +Polygon.prototype.getCoordinate = function (path) { const ids = path.split('.').map(x => parseInt(x, 10)); const ring = this.coordinates[ids[0]]; return JSON.parse(JSON.stringify(ring[ids[1]])); }; -Polygon.prototype.getCoordinates = function() { +Polygon.prototype.getCoordinates = function () { return this.coordinates.map(coords => coords.concat([coords[0]])); }; -Polygon.prototype.updateCoordinate = function(path, lng, lat) { +Polygon.prototype.updateCoordinate = function (path, lng, lat) { this.changed(); const parts = path.split('.'); const ringId = parseInt(parts[0], 10); diff --git a/src/lib/common_selectors.ts b/src/lib/common_selectors.ts index f097c831..590dac96 100644 --- a/src/lib/common_selectors.ts +++ b/src/lib/common_selectors.ts @@ -1,7 +1,7 @@ import * as Constants from '../constants'; export function isOfMetaType(type) { - return function(e) { + return function (e) { const featureTarget = e.featureTarget; if (!featureTarget) return false; if (!featureTarget.properties) return false; @@ -18,15 +18,19 @@ export function isShiftMousedown(e) { export function isActiveFeature(e) { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; - return e.featureTarget.properties.active === Constants.activeStates.ACTIVE && - e.featureTarget.properties.meta === Constants.meta.FEATURE; + return ( + e.featureTarget.properties.active === Constants.activeStates.ACTIVE && + e.featureTarget.properties.meta === Constants.meta.FEATURE + ); } export function isInactiveFeature(e) { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; - return e.featureTarget.properties.active === Constants.activeStates.INACTIVE && - e.featureTarget.properties.meta === Constants.meta.FEATURE; + return ( + e.featureTarget.properties.active === Constants.activeStates.INACTIVE && + e.featureTarget.properties.meta === Constants.meta.FEATURE + ); } export function noTarget(e) { diff --git a/src/lib/constrain_feature_movement.ts b/src/lib/constrain_feature_movement.ts index 9a536535..7136a6a6 100644 --- a/src/lib/constrain_feature_movement.ts +++ b/src/lib/constrain_feature_movement.ts @@ -6,7 +6,7 @@ const { LAT_RENDERED_MIN, LAT_RENDERED_MAX, LNG_MIN, - LNG_MAX, + LNG_MAX } = Constants; function extent(feature) { const depth = { @@ -15,7 +15,7 @@ function extent(feature) { Polygon: 2, MultiPoint: 1, MultiLineString: 2, - MultiPolygon: 3, + MultiPolygon: 3 }[feature.geometry.type]; const coords = [feature.geometry.coordinates].flat(depth); @@ -30,7 +30,7 @@ function extent(feature) { // - any part of any feature to exceed the poles // - any feature to be completely lost in the space between the projection's // edge and the poles, such that it couldn't be re-selected and moved back -export default function(geojsonFeatures, delta) { +export default function (geojsonFeatures, delta) { // "inner edge" = a feature's latitude closest to the equator let northInnerEdge = LAT_MIN; let southInnerEdge = LAT_MAX; @@ -41,7 +41,7 @@ export default function(geojsonFeatures, delta) { let westEdge = LNG_MAX; let eastEdge = LNG_MIN; - geojsonFeatures.forEach((feature) => { + geojsonFeatures.forEach(feature => { const bounds = extent(feature); const featureSouthEdge = bounds[1]; const featureNorthEdge = bounds[3]; @@ -55,7 +55,6 @@ export default function(geojsonFeatures, delta) { if (featureEastEdge > eastEdge) eastEdge = featureEastEdge; }); - // These changes are not mutually exclusive: we might hit the inner // edge but also have hit the outer edge and therefore need // another readjustment @@ -73,10 +72,12 @@ export default function(geojsonFeatures, delta) { constrainedDelta.lat = LAT_MIN - southOuterEdge; } if (westEdge + constrainedDelta.lng <= LNG_MIN) { - constrainedDelta.lng += Math.ceil(Math.abs(constrainedDelta.lng) / 360) * 360; + constrainedDelta.lng += + Math.ceil(Math.abs(constrainedDelta.lng) / 360) * 360; } if (eastEdge + constrainedDelta.lng >= LNG_MAX) { - constrainedDelta.lng -= Math.ceil(Math.abs(constrainedDelta.lng) / 360) * 360; + constrainedDelta.lng -= + Math.ceil(Math.abs(constrainedDelta.lng) / 360) * 360; } return constrainedDelta; diff --git a/src/lib/create_midpoint.ts b/src/lib/create_midpoint.ts index 766eb854..db62f989 100644 --- a/src/lib/create_midpoint.ts +++ b/src/lib/create_midpoint.ts @@ -1,15 +1,17 @@ import * as Constants from '../constants'; -export default function(parent, startVertex, endVertex) { +export default function (parent, startVertex, endVertex) { const startCoord = startVertex.geometry.coordinates; const endCoord = endVertex.geometry.coordinates; // If a coordinate exceeds the projection, we can't calculate a midpoint, // so run away - if (startCoord[1] > Constants.LAT_RENDERED_MAX || + if ( + startCoord[1] > Constants.LAT_RENDERED_MAX || startCoord[1] < Constants.LAT_RENDERED_MIN || endCoord[1] > Constants.LAT_RENDERED_MAX || - endCoord[1] < Constants.LAT_RENDERED_MIN) { + endCoord[1] < Constants.LAT_RENDERED_MIN + ) { return null; } diff --git a/src/lib/create_supplementary_points.ts b/src/lib/create_supplementary_points.ts index 017a801b..a8a4033e 100644 --- a/src/lib/create_supplementary_points.ts +++ b/src/lib/create_supplementary_points.ts @@ -10,12 +10,17 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { if (type === Constants.geojsonTypes.POINT) { // For points, just create a vertex - supplementaryPoints.push(createVertex(featureId, coordinates, basePath, isSelectedPath(basePath))); + supplementaryPoints.push( + createVertex(featureId, coordinates, basePath, isSelectedPath(basePath)) + ); } else if (type === Constants.geojsonTypes.POLYGON) { // Cycle through a Polygon's rings and // process each line coordinates.forEach((line, lineIndex) => { - processLine(line, (basePath !== null) ? `${basePath}.${lineIndex}` : String(lineIndex)); + processLine( + line, + basePath !== null ? `${basePath}.${lineIndex}` : String(lineIndex) + ); }); } else if (type === Constants.geojsonTypes.LINE_STRING) { processLine(coordinates, basePath); @@ -27,8 +32,16 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { let firstPointString = ''; let lastVertex = null; line.forEach((point, pointIndex) => { - const pointPath = (lineBasePath !== undefined && lineBasePath !== null) ? `${lineBasePath}.${pointIndex}` : String(pointIndex); - const vertex = createVertex(featureId, point, pointPath, isSelectedPath(pointPath)); + const pointPath = + lineBasePath !== undefined && lineBasePath !== null + ? `${lineBasePath}.${pointIndex}` + : String(pointIndex); + const vertex = createVertex( + featureId, + point, + pointPath, + isSelectedPath(pointPath) + ); // If we're creating midpoints, check if there was a // vertex before this one. If so, add a midpoint @@ -73,7 +86,9 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { coordinates: subCoordinates } }; - supplementaryPoints = supplementaryPoints.concat(createSupplementaryPoints(subFeature, options, index)); + supplementaryPoints = supplementaryPoints.concat( + createSupplementaryPoints(subFeature, options, index) + ); }); } diff --git a/src/lib/create_vertex.ts b/src/lib/create_vertex.ts index e6ab9a95..2d9d90bb 100644 --- a/src/lib/create_vertex.ts +++ b/src/lib/create_vertex.ts @@ -12,14 +12,16 @@ import * as Constants from '../constants'; * @return {GeoJSON} Point */ -export default function(parentId, coordinates, path, selected) { +export default function (parentId, coordinates, path, selected) { return { type: Constants.geojsonTypes.FEATURE, properties: { meta: Constants.meta.VERTEX, parent: parentId, coord_path: path, - active: (selected) ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE + active: selected + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE }, geometry: { type: Constants.geojsonTypes.POINT, diff --git a/src/lib/double_click_zoom.ts b/src/lib/double_click_zoom.ts index 7bf3ca48..f753a09b 100644 --- a/src/lib/double_click_zoom.ts +++ b/src/lib/double_click_zoom.ts @@ -2,7 +2,14 @@ export default { enable(ctx) { setTimeout(() => { // First check we've got a map and some context. - if (!ctx.map || !ctx.map.doubleClickZoom || !ctx._ctx || !ctx._ctx.store || !ctx._ctx.store.getInitialConfigValue) return; + if ( + !ctx.map || + !ctx.map.doubleClickZoom || + !ctx._ctx || + !ctx._ctx.store || + !ctx._ctx.store.getInitialConfigValue + ) + return; // Now check initial state wasn't false (we leave it disabled if so) if (!ctx._ctx.store.getInitialConfigValue('doubleClickZoom')) return; ctx.map.doubleClickZoom.enable(); diff --git a/src/lib/euclidean_distance.ts b/src/lib/euclidean_distance.ts index 440fd237..4c0032cb 100644 --- a/src/lib/euclidean_distance.ts +++ b/src/lib/euclidean_distance.ts @@ -1,5 +1,5 @@ -export default function(a, b) { +export default function (a, b) { const x = a.x - b.x; const y = a.y - b.y; - return Math.sqrt((x * x) + (y * y)); + return Math.sqrt(x * x + y * y); } diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index bc0e3378..c160d138 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -28,21 +28,30 @@ function featuresAtTouch(event: Event, bbox: BBox, ctx: DrawCTX) { return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); } -export const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: number) => { +export const featuresAt = ( + event: Event, + bbox: BBox, + ctx: DrawCTX, + buffer: number +) => { if (ctx.map === null) return []; - const box = (event) ? mapEventToBoundingBox(event, buffer) : bbox; + const box = event ? mapEventToBoundingBox(event, buffer) : bbox; const queryParams = {}; - if (ctx.options.styles) queryParams.layers = ctx.options.styles.map(s => s.id).filter(id => ctx.map.getLayer(id) != null); + if (ctx.options.styles) + queryParams.layers = ctx.options.styles + .map(s => s.id) + .filter(id => ctx.map.getLayer(id) != null); - const features = ctx.map.queryRenderedFeatures(box, queryParams) + const features = ctx.map + .queryRenderedFeatures(box, queryParams) .filter(feature => META_TYPES.indexOf(feature?.properties?.meta) !== -1); const featureIds = new StringSet(); const uniqueFeatures = []; - features.forEach((feature) => { + features.forEach(feature => { const featureId = feature.properties?.id; if (featureIds.has(featureId)) return; featureIds.add(featureId); @@ -50,4 +59,4 @@ export const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: numbe }); return sortFeatures(uniqueFeatures); -} +}; diff --git a/src/lib/get_features_at_and_set_cursor.ts b/src/lib/get_features_at_and_set_cursor.ts index 45525d57..812ac143 100644 --- a/src/lib/get_features_at_and_set_cursor.ts +++ b/src/lib/get_features_at_and_set_cursor.ts @@ -7,8 +7,10 @@ export const getFeatureAtAndSetCursors = (event: Event, ctx: DrawCTX) => { const classes = { mouse: Constants.cursors.NONE }; if (features[0]) { - classes.mouse = (features[0].properties.active === Constants.activeStates.ACTIVE) ? - Constants.cursors.MOVE : Constants.cursors.POINTER; + classes.mouse = + features[0].properties.active === Constants.activeStates.ACTIVE + ? Constants.cursors.MOVE + : Constants.cursors.POINTER; classes.feature = features[0].properties.meta; } @@ -20,4 +22,4 @@ export const getFeatureAtAndSetCursors = (event: Event, ctx: DrawCTX) => { ctx.ui.updateMapClasses(); return features[0]; -} +}; diff --git a/src/lib/id.ts b/src/lib/id.ts index 6fc46762..f8e6ca33 100644 --- a/src/lib/id.ts +++ b/src/lib/id.ts @@ -1,6 +1,9 @@ import { customAlphabet } from 'nanoid/non-secure'; -const nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 32); +const nanoid = customAlphabet( + '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', + 32 +); export function generateID() { return nanoid(); diff --git a/src/lib/index.ts b/src/lib/index.ts index 2c205b2a..263bbdaa 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -39,5 +39,5 @@ export { stringSetsAreEqual, StringSet, theme, - toDenseArray, + toDenseArray }; diff --git a/src/lib/is_click.ts b/src/lib/is_click.ts index 06e6a235..6f65fa53 100644 --- a/src/lib/is_click.ts +++ b/src/lib/is_click.ts @@ -5,14 +5,18 @@ const GROSS_TOLERANCE = 12; const INTERVAL = 500; export default function isClick(start, end, options = {}) { - const fineTolerance = (options.fineTolerance != null) ? options.fineTolerance : FINE_TOLERANCE; - const grossTolerance = (options.grossTolerance != null) ? options.grossTolerance : GROSS_TOLERANCE; - const interval = (options.interval != null) ? options.interval : INTERVAL; + const fineTolerance = + options.fineTolerance != null ? options.fineTolerance : FINE_TOLERANCE; + const grossTolerance = + options.grossTolerance != null ? options.grossTolerance : GROSS_TOLERANCE; + const interval = options.interval != null ? options.interval : INTERVAL; start.point = start.point || end.point; start.time = start.time || end.time; const moveDistance = euclideanDistance(start.point, end.point); - return moveDistance < fineTolerance || - (moveDistance < grossTolerance && (end.time - start.time) < interval); + return ( + moveDistance < fineTolerance || + (moveDistance < grossTolerance && end.time - start.time < interval) + ); } diff --git a/src/lib/is_event_at_coordinates.ts b/src/lib/is_event_at_coordinates.ts index 790e0a49..e810f3b8 100644 --- a/src/lib/is_event_at_coordinates.ts +++ b/src/lib/is_event_at_coordinates.ts @@ -1,6 +1,8 @@ function isEventAtCoordinates(event, coordinates) { if (!event.lngLat) return false; - return event.lngLat.lng === coordinates[0] && event.lngLat.lat === coordinates[1]; + return ( + event.lngLat.lng === coordinates[0] && event.lngLat.lat === coordinates[1] + ); } export default isEventAtCoordinates; diff --git a/src/lib/is_tap.ts b/src/lib/is_tap.ts index 55e20c48..979f3d21 100644 --- a/src/lib/is_tap.ts +++ b/src/lib/is_tap.ts @@ -4,12 +4,13 @@ export const TAP_TOLERANCE = 25; export const TAP_INTERVAL = 250; export default function isTap(start, end, options = {}) { - const tolerance = (options.tolerance != null) ? options.tolerance : TAP_TOLERANCE; - const interval = (options.interval != null) ? options.interval : TAP_INTERVAL; + const tolerance = + options.tolerance != null ? options.tolerance : TAP_TOLERANCE; + const interval = options.interval != null ? options.interval : TAP_INTERVAL; start.point = start.point || end.point; start.time = start.time || end.time; const moveDistance = euclideanDistance(start.point, end.point); - return moveDistance < tolerance && (end.time - start.time) < interval; + return moveDistance < tolerance && end.time - start.time < interval; } diff --git a/src/lib/map_event_to_bounding_box.ts b/src/lib/map_event_to_bounding_box.ts index 5d6c164f..dca019d2 100644 --- a/src/lib/map_event_to_bounding_box.ts +++ b/src/lib/map_event_to_bounding_box.ts @@ -1,7 +1,10 @@ import type { Position } from 'geojson'; import type { MapMouseEvent, MapTouchEvent } from '../types/types'; -function mapEventToBoundingBox(mapEvent: MapMouseEvent | MapTouchEvent, buffer: number = 0): Position[] { +function mapEventToBoundingBox( + mapEvent: MapMouseEvent | MapTouchEvent, + buffer: number = 0 +): Position[] { return [ [mapEvent.point.x - buffer, mapEvent.point.y - buffer], [mapEvent.point.x + buffer, mapEvent.point.y + buffer] diff --git a/src/lib/mode_handler.ts b/src/lib/mode_handler.ts index b382471d..7c499f7a 100644 --- a/src/lib/mode_handler.ts +++ b/src/lib/mode_handler.ts @@ -1,6 +1,4 @@ - -const ModeHandler = function(mode, DrawContext) { - +const ModeHandler = function (mode, DrawContext) { const handlers = { drag: [], click: [], diff --git a/src/lib/move_features.ts b/src/lib/move_features.ts index f153b2e0..a6b1e1ac 100644 --- a/src/lib/move_features.ts +++ b/src/lib/move_features.ts @@ -1,13 +1,16 @@ import constrainFeatureMovement from './constrain_feature_movement'; import * as Constants from '../constants'; -export default function(features, delta) { - const constrainedDelta = constrainFeatureMovement(features.map(feature => feature.toGeoJSON()), delta); +export default function (features, delta) { + const constrainedDelta = constrainFeatureMovement( + features.map(feature => feature.toGeoJSON()), + delta + ); - features.forEach((feature) => { + features.forEach(feature => { const currentCoordinates = feature.getCoordinates(); - const moveCoordinate = (coord) => { + const moveCoordinate = coord => { const point = { lng: coord[0] + constrainedDelta.lng, lat: coord[1] + constrainedDelta.lat @@ -20,9 +23,15 @@ export default function(features, delta) { let nextCoordinates; if (feature.type === Constants.geojsonTypes.POINT) { nextCoordinates = moveCoordinate(currentCoordinates); - } else if (feature.type === Constants.geojsonTypes.LINE_STRING || feature.type === Constants.geojsonTypes.MULTI_POINT) { + } else if ( + feature.type === Constants.geojsonTypes.LINE_STRING || + feature.type === Constants.geojsonTypes.MULTI_POINT + ) { nextCoordinates = currentCoordinates.map(moveCoordinate); - } else if (feature.type === Constants.geojsonTypes.POLYGON || feature.type === Constants.geojsonTypes.MULTI_LINE_STRING) { + } else if ( + feature.type === Constants.geojsonTypes.POLYGON || + feature.type === Constants.geojsonTypes.MULTI_LINE_STRING + ) { nextCoordinates = currentCoordinates.map(moveRing); } else if (feature.type === Constants.geojsonTypes.MULTI_POLYGON) { nextCoordinates = currentCoordinates.map(moveMultiPolygon); diff --git a/src/lib/sort_features.ts b/src/lib/sort_features.ts index 133e7f35..ce071e55 100644 --- a/src/lib/sort_features.ts +++ b/src/lib/sort_features.ts @@ -17,7 +17,8 @@ interface DrawFeature extends Feature { } function comparator(a: DrawFeature, b: DrawFeature) { - const score = FEATURE_SORT_RANKS[a.geometry.type] - FEATURE_SORT_RANKS[b.geometry.type]; + const score = + FEATURE_SORT_RANKS[a.geometry.type] - FEATURE_SORT_RANKS[b.geometry.type]; if ( score === 0 && @@ -33,19 +34,22 @@ function comparator(a: DrawFeature, b: DrawFeature) { // Sort in the order above, then sort polygons by area ascending. function sortFeatures(features: Array) { - return features.map((feature) => { - if (feature.geometry.type === Constants.geojsonTypes.POLYGON) { - feature.area = area.geometry({ - type: Constants.geojsonTypes.FEATURE, - property: {}, - geometry: feature.geometry - }); - } - return feature; - }).sort(comparator).map((feature) => { - delete feature.area; - return feature; - }); + return features + .map(feature => { + if (feature.geometry.type === Constants.geojsonTypes.POLYGON) { + feature.area = area.geometry({ + type: Constants.geojsonTypes.FEATURE, + property: {}, + geometry: feature.geometry + }); + } + return feature; + }) + .sort(comparator) + .map(feature => { + delete feature.area; + return feature; + }); } export default sortFeatures; diff --git a/src/lib/string_set.ts b/src/lib/string_set.ts index d0865779..368c40ea 100644 --- a/src/lib/string_set.ts +++ b/src/lib/string_set.ts @@ -8,11 +8,10 @@ function StringSet(items) { if (items[i] === undefined) continue; if (typeof items[i] === 'string') this._items[items[i]] = i; else this._nums[items[i]] = i; - } } -StringSet.prototype.add = function(x) { +StringSet.prototype.add = function (x) { if (this.has(x)) return this; this._length++; if (typeof x === 'string') this._items[x] = this._length; @@ -20,7 +19,7 @@ StringSet.prototype.add = function(x) { return this; }; -StringSet.prototype.delete = function(x) { +StringSet.prototype.delete = function (x) { if (this.has(x) === false) return this; this._length--; delete this._items[x]; @@ -28,24 +27,24 @@ StringSet.prototype.delete = function(x) { return this; }; -StringSet.prototype.has = function(x) { +StringSet.prototype.has = function (x) { if (typeof x !== 'string' && typeof x !== 'number') return false; return this._items[x] !== undefined || this._nums[x] !== undefined; }; -StringSet.prototype.values = function() { +StringSet.prototype.values = function () { const values = []; - Object.keys(this._items).forEach((k) => { + Object.keys(this._items).forEach(k => { values.push({ k, v: this._items[k] }); }); - Object.keys(this._nums).forEach((k) => { + Object.keys(this._nums).forEach(k => { values.push({ k: JSON.parse(k), v: this._nums[k] }); }); return values.sort((a, b) => a.v - b.v).map(a => a.k); }; -StringSet.prototype.clear = function() { +StringSet.prototype.clear = function () { this._length = 0; this._items = {}; this._nums = {}; diff --git a/src/lib/string_sets_are_equal.ts b/src/lib/string_sets_are_equal.ts index 894f5a5d..3b92ade6 100644 --- a/src/lib/string_sets_are_equal.ts +++ b/src/lib/string_sets_are_equal.ts @@ -1,4 +1,7 @@ -export default function(a, b) { +export default function (a, b) { if (a.length !== b.length) return false; - return JSON.stringify(a.map(id => id).sort()) === JSON.stringify(b.map(id => id).sort()); + return ( + JSON.stringify(a.map(id => id).sort()) === + JSON.stringify(b.map(id => id).sort()) + ); } diff --git a/src/lib/theme.ts b/src/lib/theme.ts index 0f45b7d1..bd05f970 100644 --- a/src/lib/theme.ts +++ b/src/lib/theme.ts @@ -9,145 +9,100 @@ export default [ // Solid fill // Active state defines color { - 'id': 'gl-draw-polygon-fill', - 'type': 'fill', - 'filter': [ - 'all', - ['==', '$type', 'Polygon'], - ], - 'paint': { - 'fill-color': [ - 'case', - ['==', ['get', 'active'], 'true'], orange, - blue, - ], - 'fill-opacity': 0.1, - }, + id: 'gl-draw-polygon-fill', + type: 'fill', + filter: ['all', ['==', '$type', 'Polygon']], + paint: { + 'fill-color': ['case', ['==', ['get', 'active'], 'true'], orange, blue], + 'fill-opacity': 0.1 + } }, // Lines // Polygon // Matches Lines AND Polygons // Active state defines color { - 'id': 'gl-draw-lines', - 'type': 'line', - 'filter': [ - 'any', - ['==', '$type', 'LineString'], - ['==', '$type', 'Polygon'], - ], - 'layout': { + id: 'gl-draw-lines', + type: 'line', + filter: ['any', ['==', '$type', 'LineString'], ['==', '$type', 'Polygon']], + layout: { 'line-cap': 'round', - 'line-join': 'round', + 'line-join': 'round' }, - 'paint': { - 'line-color': [ - 'case', - ['==', ['get', 'active'], 'true'], orange, - blue, - ], + paint: { + 'line-color': ['case', ['==', ['get', 'active'], 'true'], orange, blue], 'line-dasharray': [ 'case', - ['==', ['get', 'active'], 'true'], [0.2, 2], - [2, 0], + ['==', ['get', 'active'], 'true'], + [0.2, 2], + [2, 0] ], - 'line-width': 2, - }, + 'line-width': 2 + } }, // Points // Circle with an outline // Active state defines size and color { - 'id': 'gl-draw-point-outer', - 'type': 'circle', - 'filter': [ - 'all', - ['==', '$type', 'Point'], - ['==', 'meta', 'feature'], - ], - 'paint': { - 'circle-radius': [ - 'case', - ['==', ['get', 'active'], 'true'], 7, - 5, - ], - 'circle-color': white, - }, + id: 'gl-draw-point-outer', + type: 'circle', + filter: ['all', ['==', '$type', 'Point'], ['==', 'meta', 'feature']], + paint: { + 'circle-radius': ['case', ['==', ['get', 'active'], 'true'], 7, 5], + 'circle-color': white + } }, { - 'id': 'gl-draw-point-inner', - 'type': 'circle', - 'filter': [ - 'all', - ['==', '$type', 'Point'], - ['==', 'meta', 'feature'], - ], - 'paint': { - 'circle-radius': [ - 'case', - ['==', ['get', 'active'], 'true'], 5, - 3, - ], - 'circle-color': [ - 'case', - ['==', ['get', 'active'], 'true'], orange, - blue, - ], - }, + id: 'gl-draw-point-inner', + type: 'circle', + filter: ['all', ['==', '$type', 'Point'], ['==', 'meta', 'feature']], + paint: { + 'circle-radius': ['case', ['==', ['get', 'active'], 'true'], 5, 3], + 'circle-color': ['case', ['==', ['get', 'active'], 'true'], orange, blue] + } }, // Vertex // Visible when editing polygons and lines // Similar behaviour to Points // Active state defines size { - 'id': 'gl-draw-vertex-outer', - 'type': 'circle', - 'filter': [ + id: 'gl-draw-vertex-outer', + type: 'circle', + filter: [ 'all', ['==', '$type', 'Point'], ['==', 'meta', 'vertex'], - ['!=', 'mode', 'simple_select'], + ['!=', 'mode', 'simple_select'] ], - 'paint': { - 'circle-radius': [ - 'case', - ['==', ['get', 'active'], 'true'], 7, - 5, - ], - 'circle-color': white, - }, + paint: { + 'circle-radius': ['case', ['==', ['get', 'active'], 'true'], 7, 5], + 'circle-color': white + } }, { - 'id': 'gl-draw-vertex-inner', - 'type': 'circle', - 'filter': [ + id: 'gl-draw-vertex-inner', + type: 'circle', + filter: [ 'all', ['==', '$type', 'Point'], ['==', 'meta', 'vertex'], - ['!=', 'mode', 'simple_select'], + ['!=', 'mode', 'simple_select'] ], - 'paint': { - 'circle-radius': [ - 'case', - ['==', ['get', 'active'], 'true'], 5, - 3, - ], - 'circle-color': orange, - }, + paint: { + 'circle-radius': ['case', ['==', ['get', 'active'], 'true'], 5, 3], + 'circle-color': orange + } }, // Midpoint // Visible when editing polygons and lines // Tapping or dragging them adds a new vertex to the feature { - 'id': 'gl-draw-midpoint', - 'type': 'circle', - 'filter': [ - 'all', - ['==', 'meta', 'midpoint'], - ], - 'paint': { + id: 'gl-draw-midpoint', + type: 'circle', + filter: ['all', ['==', 'meta', 'midpoint']], + paint: { 'circle-radius': 3, - 'circle-color': orange, - }, - }, + 'circle-color': orange + } + } ]; diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index cdb43f7f..1b68b0e4 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -1,4 +1,10 @@ -import { noTarget, isOfMetaType, isActiveFeature, isInactiveFeature, isShiftDown } from '../lib/common_selectors'; +import { + noTarget, + isOfMetaType, + isActiveFeature, + isInactiveFeature, + isShiftDown +} from '../lib/common_selectors'; import createSupplementaryPoints from '../lib/create_supplementary_points'; import constrainFeatureMovement from '../lib/constrain_feature_movement'; import doubleClickZoom from '../lib/double_click_zoom'; @@ -11,7 +17,6 @@ import type { MapMouseEvent } from 'mapbox-gl'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); - interface DirectSelectMode extends DrawCustomMode { fireUpdate(): void; clickInactive(): void; @@ -21,21 +26,21 @@ interface DirectSelectMode extends DrawCustomMode { } const DirectSelect: DirectSelectMode = { - clickInactive: function() { + clickInactive: function () { this.changeMode(Constants.modes.SIMPLE_SELECT); } }; // INTERNAL FUNCTIONS -DirectSelect.fireUpdate = function() { +DirectSelect.fireUpdate = function () { this.fire(Constants.events.UPDATE, { action: Constants.updateActions.CHANGE_COORDINATES, features: this.getSelected().map(f => f.toGeoJSON()) }); }; -DirectSelect.fireActionable = function(state) { +DirectSelect.fireActionable = function (state) { this.setActionableState({ combineFeatures: false, uncombineFeatures: false, @@ -43,7 +48,7 @@ DirectSelect.fireActionable = function(state) { }); }; -DirectSelect.startDragging = function(state, e) { +DirectSelect.startDragging = function (state, e) { if (state.initialDragPanState == null) { state.initialDragPanState = this.map.dragPan.isEnabled(); } @@ -53,7 +58,7 @@ DirectSelect.startDragging = function(state, e) { state.dragMoveLocation = e.lngLat; }; -DirectSelect.stopDragging = function(state) { +DirectSelect.stopDragging = function (state) { if (state.canDragMove && state.initialDragPanState === true) { this.map.dragPan.enable(); } @@ -74,11 +79,14 @@ DirectSelect.onVertex = function (state, e) { state.selectedCoordPaths.push(about.coord_path); } - const selectedCoordinates = this.pathsToCoordinates(state.featureId, state.selectedCoordPaths); + const selectedCoordinates = this.pathsToCoordinates( + state.featureId, + state.selectedCoordPaths + ); this.setSelectedCoordinates(selectedCoordinates); }; -DirectSelect.onMidpoint = function(state, e) { +DirectSelect.onMidpoint = function (state, e) { this.startDragging(state, e); const about = e.featureTarget.properties; state.feature.addCoordinate(about.coord_path, about.lng, about.lat); @@ -86,22 +94,24 @@ DirectSelect.onMidpoint = function(state, e) { state.selectedCoordPaths = [about.coord_path]; }; -DirectSelect.pathsToCoordinates = function(featureId, paths) { +DirectSelect.pathsToCoordinates = function (featureId, paths) { return paths.map(coord_path => ({ feature_id: featureId, coord_path })); }; -DirectSelect.onFeature = function(state, e) { +DirectSelect.onFeature = function (state, e) { if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); else this.stopDragging(state); }; -DirectSelect.dragFeature = function(state, e, delta) { +DirectSelect.dragFeature = function (state, e, delta) { moveFeatures(this.getSelected(), delta); state.dragMoveLocation = e.lngLat; }; -DirectSelect.dragVertex = function(state, e, delta) { - const selectedCoords = state.selectedCoordPaths.map(coord_path => state.feature.getCoordinate(coord_path)); +DirectSelect.dragVertex = function (state, e, delta) { + const selectedCoords = state.selectedCoordPaths.map(coord_path => + state.feature.getCoordinate(coord_path) + ); const selectedCoordPoints = selectedCoords.map(coords => ({ type: Constants.geojsonTypes.FEATURE, properties: {}, @@ -114,7 +124,11 @@ DirectSelect.dragVertex = function(state, e, delta) { const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); for (let i = 0; i < selectedCoords.length; i++) { const coord = selectedCoords[i]; - state.feature.updateCoordinate(state.selectedCoordPaths[i], coord[0] + constrainedDelta.lng, coord[1] + constrainedDelta.lat); + state.feature.updateCoordinate( + state.selectedCoordPaths[i], + coord[0] + constrainedDelta.lng, + coord[1] + constrainedDelta.lat + ); } }; @@ -130,7 +144,7 @@ DirectSelect.clickActiveFeature = function (state) { // EXTERNAL FUNCTIONS -DirectSelect.onSetup = function(opts) { +DirectSelect.onSetup = function (opts) { const featureId = opts.featureId; const feature = this.getFeature(featureId); @@ -139,7 +153,7 @@ DirectSelect.onSetup = function(opts) { } if (feature.type === Constants.geojsonTypes.POINT) { - throw new TypeError('direct_select mode doesn\'t handle point features'); + throw new TypeError("direct_select mode doesn't handle point features"); } const state = { @@ -148,10 +162,12 @@ DirectSelect.onSetup = function(opts) { dragMoveLocation: opts.startPos || null, dragMoving: false, canDragMove: false, - selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [], + selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] }; - this.setSelectedCoordinates(this.pathsToCoordinates(featureId, state.selectedCoordPaths)); + this.setSelectedCoordinates( + this.pathsToCoordinates(featureId, state.selectedCoordPaths) + ); this.setSelected(featureId); doubleClickZoom.disable(this); @@ -162,12 +178,12 @@ DirectSelect.onSetup = function(opts) { return state; }; -DirectSelect.onStop = function() { +DirectSelect.onStop = function () { doubleClickZoom.enable(this); this.clearSelectedCoordinates(); }; -DirectSelect.onTrash = function(state) { +DirectSelect.onTrash = function (state) { // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them // in reverse order so that we can remove by index safely. state.selectedCoordPaths @@ -183,14 +199,16 @@ DirectSelect.onTrash = function(state) { } }; -DirectSelect.onMouseMove = function(state, e) { +DirectSelect.onMouseMove = function (state, e) { // On mousemove that is not a drag, stop vertex movement. const isFeature = isActiveFeature(e); const onVertex = isVertex(e); const isMidPoint = isMidpoint(e); const noCoords = state.selectedCoordPaths.length === 0; - if (isFeature && noCoords) this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else if (onVertex && !noCoords) this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + if (isFeature && noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else if (onVertex && !noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); else this.updateUIClasses({ mouse: Constants.cursors.NONE }); const isDraggableItem = onVertex || isFeature || isMidPoint; @@ -202,7 +220,7 @@ DirectSelect.onMouseMove = function(state, e) { return true; }; -DirectSelect.onMouseOut = function(state) { +DirectSelect.onMouseOut = function (state) { // As soon as you mouse leaves the canvas, update the feature if (state.dragMoving) this.fireUpdate(); @@ -210,13 +228,13 @@ DirectSelect.onMouseOut = function(state) { return true; }; -DirectSelect.onTouchStart = DirectSelect.onMouseDown = function(state, e) { +DirectSelect.onTouchStart = DirectSelect.onMouseDown = function (state, e) { if (isVertex(e)) return this.onVertex(state, e); if (isActiveFeature(e)) return this.onFeature(state, e); if (isMidpoint(e)) return this.onMidpoint(state, e); }; -DirectSelect.onDrag = function(state, e) { +DirectSelect.onDrag = function (state, e) { if (state.canDragMove !== true) return; state.dragMoving = true; e.originalEvent.stopPropagation(); @@ -231,27 +249,27 @@ DirectSelect.onDrag = function(state, e) { state.dragMoveLocation = e.lngLat; }; -DirectSelect.onClick = function(state, e) { +DirectSelect.onClick = function (state, e) { if (noTarget(e)) return this.clickNoTarget(state, e); if (isActiveFeature(e)) return this.clickActiveFeature(state, e); if (isInactiveFeature(e)) return this.clickInactive(state, e); this.stopDragging(state); }; -DirectSelect.onTap = function(state, e) { +DirectSelect.onTap = function (state, e) { if (noTarget(e)) return this.clickNoTarget(state, e); if (isActiveFeature(e)) return this.clickActiveFeature(state, e); if (isInactiveFeature(e)) return this.clickInactive(state, e); }; -DirectSelect.onTouchEnd = DirectSelect.onMouseUp = function(state) { +DirectSelect.onTouchEnd = DirectSelect.onMouseUp = function (state) { if (state.dragMoving) { this.fireUpdate(); } this.stopDragging(state); }; -DirectSelect.toDisplayFeatures = function(state: DrawCTX, geojson, push) { +DirectSelect.toDisplayFeatures = function (state: DrawCTX, geojson, push) { if (state.featureId === geojson.properties.id) { geojson.properties.active = Constants.activeStates.ACTIVE; push(geojson); @@ -266,7 +284,6 @@ DirectSelect.toDisplayFeatures = function(state: DrawCTX, geojson, push) { } this.fireActionable(state); -} +}; export default DirectSelect; - diff --git a/src/modes/draw_line_string.ts b/src/modes/draw_line_string.ts index d747ced2..ba8e914e 100644 --- a/src/modes/draw_line_string.ts +++ b/src/modes/draw_line_string.ts @@ -6,7 +6,7 @@ import createVertex from '../lib/create_vertex'; const DrawLineString = {}; -DrawLineString.onSetup = function(opts) { +DrawLineString.onSetup = function (opts) { opts = opts || {}; const featureId = opts.featureId; @@ -18,27 +18,47 @@ DrawLineString.onSetup = function(opts) { throw new Error('Could not find a feature with the provided featureId'); } let from = opts.from; - if (from && from.type === 'Feature' && from.geometry && from.geometry.type === 'Point') { + if ( + from && + from.type === 'Feature' && + from.geometry && + from.geometry.type === 'Point' + ) { from = from.geometry; } - if (from && from.type === 'Point' && from.coordinates && from.coordinates.length === 2) { + if ( + from && + from.type === 'Point' && + from.coordinates && + from.coordinates.length === 2 + ) { from = from.coordinates; } if (!from || !Array.isArray(from)) { - throw new Error('Please use the `from` property to indicate which point to continue the line from'); + throw new Error( + 'Please use the `from` property to indicate which point to continue the line from' + ); } const lastCoord = line.coordinates.length - 1; - if (line.coordinates[lastCoord][0] === from[0] && line.coordinates[lastCoord][1] === from[1]) { + if ( + line.coordinates[lastCoord][0] === from[0] && + line.coordinates[lastCoord][1] === from[1] + ) { currentVertexPosition = lastCoord + 1; // add one new coordinate to continue from line.addCoordinate(currentVertexPosition, ...line.coordinates[lastCoord]); - } else if (line.coordinates[0][0] === from[0] && line.coordinates[0][1] === from[1]) { + } else if ( + line.coordinates[0][0] === from[0] && + line.coordinates[0][1] === from[1] + ) { direction = 'backwards'; currentVertexPosition = 0; // add one new coordinate to continue from line.addCoordinate(currentVertexPosition, ...line.coordinates[0]); } else { - throw new Error('`from` should match the point at either the start or the end of the provided LineString'); + throw new Error( + '`from` should match the point at either the start or the end of the provided LineString' + ); } } else { line = this.newFeature({ @@ -68,47 +88,75 @@ DrawLineString.onSetup = function(opts) { }; }; -DrawLineString.clickAnywhere = function(state, e) { - if (state.currentVertexPosition > 0 && isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition - 1]) || - state.direction === 'backwards' && isEventAtCoordinates(e, state.line.coordinates[state.currentVertexPosition + 1])) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] }); +DrawLineString.clickAnywhere = function (state, e) { + if ( + (state.currentVertexPosition > 0 && + isEventAtCoordinates( + e, + state.line.coordinates[state.currentVertexPosition - 1] + )) || + (state.direction === 'backwards' && + isEventAtCoordinates( + e, + state.line.coordinates[state.currentVertexPosition + 1] + )) + ) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.line.id] + }); } this.updateUIClasses({ mouse: Constants.cursors.ADD }); - state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat); + state.line.updateCoordinate( + state.currentVertexPosition, + e.lngLat.lng, + e.lngLat.lat + ); if (state.direction === 'forward') { state.currentVertexPosition++; - state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat); + state.line.updateCoordinate( + state.currentVertexPosition, + e.lngLat.lng, + e.lngLat.lat + ); } else { state.line.addCoordinate(0, e.lngLat.lng, e.lngLat.lat); } }; -DrawLineString.clickOnVertex = function(state) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] }); +DrawLineString.clickOnVertex = function (state) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.line.id] + }); }; -DrawLineString.onMouseMove = function(state, e) { - state.line.updateCoordinate(state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat); +DrawLineString.onMouseMove = function (state, e) { + state.line.updateCoordinate( + state.currentVertexPosition, + e.lngLat.lng, + e.lngLat.lat + ); if (CommonSelectors.isVertex(e)) { this.updateUIClasses({ mouse: Constants.cursors.POINTER }); } }; -DrawLineString.onTap = DrawLineString.onClick = function(state, e) { +DrawLineString.onTap = DrawLineString.onClick = function (state, e) { if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); this.clickAnywhere(state, e); }; -DrawLineString.onKeyUp = function(state, e) { +DrawLineString.onKeyUp = function (state, e) { if (CommonSelectors.isEnterKey(e)) { - this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] }); + this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.line.id] + }); } else if (CommonSelectors.isEscapeKey(e)) { this.deleteFeature([state.line.id], { silent: true }); this.changeMode(Constants.modes.SIMPLE_SELECT); } }; -DrawLineString.onStop = function(state) { +DrawLineString.onStop = function (state) { doubleClickZoom.enable(this); this.activateUIButton(); @@ -127,24 +175,32 @@ DrawLineString.onStop = function(state) { } }; -DrawLineString.onTrash = function(state) { +DrawLineString.onTrash = function (state) { this.deleteFeature([state.line.id], { silent: true }); this.changeMode(Constants.modes.SIMPLE_SELECT); }; -DrawLineString.toDisplayFeatures = function(state, geojson, display) { +DrawLineString.toDisplayFeatures = function (state, geojson, display) { const isActiveLine = geojson.properties.id === state.line.id; - geojson.properties.active = (isActiveLine) ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE; + geojson.properties.active = isActiveLine + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; if (!isActiveLine) return display(geojson); // Only render the line if it has at least one real coordinate if (geojson.geometry.coordinates.length < 2) return; geojson.properties.meta = Constants.meta.FEATURE; - display(createVertex( - state.line.id, - geojson.geometry.coordinates[state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1], - `${state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1}`, - false - )); + display( + createVertex( + state.line.id, + geojson.geometry.coordinates[ + state.direction === 'forward' + ? geojson.geometry.coordinates.length - 2 + : 1 + ], + `${state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1}`, + false + ) + ); display(geojson); }; diff --git a/src/modes/draw_point.ts b/src/modes/draw_point.ts index d550834e..95af2608 100644 --- a/src/modes/draw_point.ts +++ b/src/modes/draw_point.ts @@ -3,7 +3,7 @@ import * as Constants from '../constants'; const DrawPoint = {}; -DrawPoint.onSetup = function() { +DrawPoint.onSetup = function () { const point = this.newFeature({ type: Constants.geojsonTypes.FEATURE, properties: {}, @@ -26,37 +26,41 @@ DrawPoint.onSetup = function() { return { point }; }; -DrawPoint.stopDrawingAndRemove = function(state) { +DrawPoint.stopDrawingAndRemove = function (state) { this.deleteFeature([state.point.id], { silent: true }); this.changeMode(Constants.modes.SIMPLE_SELECT); }; -DrawPoint.onTap = DrawPoint.onClick = function(state, e) { +DrawPoint.onTap = DrawPoint.onClick = function (state, e) { this.updateUIClasses({ mouse: Constants.cursors.MOVE }); state.point.updateCoordinate('', e.lngLat.lng, e.lngLat.lat); this.fire(Constants.events.CREATE, { features: [state.point.toGeoJSON()] }); - this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.point.id] }); + this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.point.id] + }); }; -DrawPoint.onStop = function(state) { +DrawPoint.onStop = function (state) { this.activateUIButton(); if (!state.point.getCoordinate().length) { this.deleteFeature([state.point.id], { silent: true }); } }; -DrawPoint.toDisplayFeatures = function(state, geojson, display) { +DrawPoint.toDisplayFeatures = function (state, geojson, display) { // Never render the point we're drawing const isActivePoint = geojson.properties.id === state.point.id; - geojson.properties.active = (isActivePoint) ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE; + geojson.properties.active = isActivePoint + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; if (!isActivePoint) return display(geojson); }; DrawPoint.onTrash = DrawPoint.stopDrawingAndRemove; -DrawPoint.onKeyUp = function(state, e) { +DrawPoint.onKeyUp = function (state, e) { if (CommonSelectors.isEscapeKey(e) || CommonSelectors.isEnterKey(e)) { return this.stopDrawingAndRemove(state, e); } diff --git a/src/modes/draw_polygon.ts b/src/modes/draw_polygon.ts index 816a4fd3..586352e1 100644 --- a/src/modes/draw_polygon.ts +++ b/src/modes/draw_polygon.ts @@ -6,7 +6,7 @@ import createVertex from '../lib/create_vertex'; const DrawPolygon = {}; -DrawPolygon.onSetup = function() { +DrawPolygon.onSetup = function () { const polygon = this.newFeature({ type: Constants.geojsonTypes.FEATURE, properties: {}, @@ -32,42 +32,66 @@ DrawPolygon.onSetup = function() { }; }; -DrawPolygon.clickAnywhere = function(state, e) { - if (state.currentVertexPosition > 0 && isEventAtCoordinates(e, state.polygon.coordinates[0][state.currentVertexPosition - 1])) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); +DrawPolygon.clickAnywhere = function (state, e) { + if ( + state.currentVertexPosition > 0 && + isEventAtCoordinates( + e, + state.polygon.coordinates[0][state.currentVertexPosition - 1] + ) + ) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.polygon.id] + }); } this.updateUIClasses({ mouse: Constants.cursors.ADD }); - state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat); + state.polygon.updateCoordinate( + `0.${state.currentVertexPosition}`, + e.lngLat.lng, + e.lngLat.lat + ); state.currentVertexPosition++; - state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat); + state.polygon.updateCoordinate( + `0.${state.currentVertexPosition}`, + e.lngLat.lng, + e.lngLat.lat + ); }; -DrawPolygon.clickOnVertex = function(state) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); +DrawPolygon.clickOnVertex = function (state) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.polygon.id] + }); }; -DrawPolygon.onMouseMove = function(state, e) { - state.polygon.updateCoordinate(`0.${state.currentVertexPosition}`, e.lngLat.lng, e.lngLat.lat); +DrawPolygon.onMouseMove = function (state, e) { + state.polygon.updateCoordinate( + `0.${state.currentVertexPosition}`, + e.lngLat.lng, + e.lngLat.lat + ); if (CommonSelectors.isVertex(e)) { this.updateUIClasses({ mouse: Constants.cursors.POINTER }); } }; -DrawPolygon.onTap = DrawPolygon.onClick = function(state, e) { +DrawPolygon.onTap = DrawPolygon.onClick = function (state, e) { if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); return this.clickAnywhere(state, e); }; -DrawPolygon.onKeyUp = function(state, e) { +DrawPolygon.onKeyUp = function (state, e) { if (CommonSelectors.isEscapeKey(e)) { this.deleteFeature([state.polygon.id], { silent: true }); this.changeMode(Constants.modes.SIMPLE_SELECT); } else if (CommonSelectors.isEnterKey(e)) { - this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] }); + this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.polygon.id] + }); } }; -DrawPolygon.onStop = function(state) { +DrawPolygon.onStop = function (state) { this.updateUIClasses({ mouse: Constants.cursors.NONE }); doubleClickZoom.enable(this); this.activateUIButton(); @@ -87,9 +111,11 @@ DrawPolygon.onStop = function(state) { } }; -DrawPolygon.toDisplayFeatures = function(state, geojson, display) { +DrawPolygon.toDisplayFeatures = function (state, geojson, display) { const isActivePolygon = geojson.properties.id === state.polygon.id; - geojson.properties.active = (isActivePolygon) ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE; + geojson.properties.active = isActivePolygon + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; if (!isActivePolygon) return display(geojson); // Don't render a polygon until it has two positions @@ -103,18 +129,39 @@ DrawPolygon.toDisplayFeatures = function(state, geojson, display) { return; } geojson.properties.meta = Constants.meta.FEATURE; - display(createVertex(state.polygon.id, geojson.geometry.coordinates[0][0], '0.0', false)); + display( + createVertex( + state.polygon.id, + geojson.geometry.coordinates[0][0], + '0.0', + false + ) + ); if (coordinateCount > 3) { // Add a start position marker to the map, clicking on this will finish the feature // This should only be shown when we're in a valid spot const endPos = geojson.geometry.coordinates[0].length - 3; - display(createVertex(state.polygon.id, geojson.geometry.coordinates[0][endPos], `0.${endPos}`, false)); + display( + createVertex( + state.polygon.id, + geojson.geometry.coordinates[0][endPos], + `0.${endPos}`, + false + ) + ); } if (coordinateCount <= 4) { // If we've only drawn two positions (plus the closer), // make a LineString instead of a Polygon const lineCoordinates = [ - [geojson.geometry.coordinates[0][0][0], geojson.geometry.coordinates[0][0][1]], [geojson.geometry.coordinates[0][1][0], geojson.geometry.coordinates[0][1][1]] + [ + geojson.geometry.coordinates[0][0][0], + geojson.geometry.coordinates[0][0][1] + ], + [ + geojson.geometry.coordinates[0][1][0], + geojson.geometry.coordinates[0][1][1] + ] ]; // create an initial vertex so that we can track the first point on mobile devices display({ @@ -133,7 +180,7 @@ DrawPolygon.toDisplayFeatures = function(state, geojson, display) { return display(geojson); }; -DrawPolygon.onTrash = function(state) { +DrawPolygon.onTrash = function (state) { this.deleteFeature([state.polygon.id], { silent: true }); this.changeMode(Constants.modes.SIMPLE_SELECT); }; diff --git a/src/modes/mode_interface.ts b/src/modes/mode_interface.ts index 3cb2fa11..e4a7974e 100644 --- a/src/modes/mode_interface.ts +++ b/src/modes/mode_interface.ts @@ -7,7 +7,7 @@ export default ModeInterface; * @name MODE.onSetup * @returns {Object} - this object will be passed to all other life cycle functions */ -ModeInterface.prototype.onSetup = function() {}; +ModeInterface.prototype.onSetup = function () {}; /** * Triggered when a drag event is detected on the map @@ -15,7 +15,7 @@ ModeInterface.prototype.onSetup = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onDrag = function() {}; +ModeInterface.prototype.onDrag = function () {}; /** * Triggered when the mouse is clicked @@ -23,7 +23,7 @@ ModeInterface.prototype.onDrag = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onClick = function() {}; +ModeInterface.prototype.onClick = function () {}; /** * Triggered with the mouse is moved @@ -31,7 +31,7 @@ ModeInterface.prototype.onClick = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onMouseMove = function() {}; +ModeInterface.prototype.onMouseMove = function () {}; /** * Triggered when the mouse button is pressed down @@ -39,7 +39,7 @@ ModeInterface.prototype.onMouseMove = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onMouseDown = function() {}; +ModeInterface.prototype.onMouseDown = function () {}; /** * Triggered when the mouse button is released @@ -47,7 +47,7 @@ ModeInterface.prototype.onMouseDown = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onMouseUp = function() {}; +ModeInterface.prototype.onMouseUp = function () {}; /** * Triggered when the mouse leaves the map's container @@ -55,7 +55,7 @@ ModeInterface.prototype.onMouseUp = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onMouseOut = function() {}; +ModeInterface.prototype.onMouseOut = function () {}; /** * Triggered when a key up event is detected @@ -63,7 +63,7 @@ ModeInterface.prototype.onMouseOut = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onKeyUp = function() {}; +ModeInterface.prototype.onKeyUp = function () {}; /** * Triggered when a key down event is detected @@ -71,7 +71,7 @@ ModeInterface.prototype.onKeyUp = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onKeyDown = function() {}; +ModeInterface.prototype.onKeyDown = function () {}; /** * Triggered when a touch event is started @@ -79,7 +79,7 @@ ModeInterface.prototype.onKeyDown = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onTouchStart = function() {}; +ModeInterface.prototype.onTouchStart = function () {}; /** * Triggered when one drags thier finger on a mobile device @@ -87,7 +87,7 @@ ModeInterface.prototype.onTouchStart = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onTouchMove = function() {}; +ModeInterface.prototype.onTouchMove = function () {}; /** * Triggered when one removes their finger from the map @@ -95,7 +95,7 @@ ModeInterface.prototype.onTouchMove = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onTouchEnd = function() {}; +ModeInterface.prototype.onTouchEnd = function () {}; /** * Triggered when one quicly taps the map @@ -103,35 +103,35 @@ ModeInterface.prototype.onTouchEnd = function() {}; * @param state {Object} - a mutible state object created by onSetup * @param e {Object} - the captured event that is triggering this life cycle event */ -ModeInterface.prototype.onTap = function() {}; +ModeInterface.prototype.onTap = function () {}; /** * Triggered when the mode is being exited, to be used for cleaning up artifacts such as invalid features * @name MODE.onStop * @param state {Object} - a mutible state object created by onSetup */ -ModeInterface.prototype.onStop = function() {}; +ModeInterface.prototype.onStop = function () {}; /** * Triggered when [draw.trash()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#trash-draw) is called. * @name MODE.onTrash * @param state {Object} - a mutible state object created by onSetup */ -ModeInterface.prototype.onTrash = function() {}; +ModeInterface.prototype.onTrash = function () {}; /** * Triggered when [draw.combineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#combinefeatures-draw) is called. * @name MODE.onCombineFeature * @param state {Object} - a mutible state object created by onSetup */ -ModeInterface.prototype.onCombineFeature = function() {}; +ModeInterface.prototype.onCombineFeature = function () {}; /** * Triggered when [draw.uncombineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#uncombinefeatures-draw) is called. * @name MODE.onUncombineFeature * @param state {Object} - a mutible state object created by onSetup */ -ModeInterface.prototype.onUncombineFeature = function() {}; +ModeInterface.prototype.onUncombineFeature = function () {}; /** * Triggered per feature on render to convert raw features into set of features for display on the map @@ -141,7 +141,6 @@ ModeInterface.prototype.onUncombineFeature = function() {}; * @param geojson {Object} - a geojson being evaulated. To render, pass to `display`. * @param display {Function} - all geojson objects passed to this be rendered onto the map */ -ModeInterface.prototype.toDisplayFeatures = function() { +ModeInterface.prototype.toDisplayFeatures = function () { throw new Error('You must overwrite toDisplayFeatures'); }; - diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index 932b6e2e..4bfe0983 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -16,7 +16,7 @@ export default function ModeInterface(ctx) { * @name this.setSelected * @param {DrawFeature[]} - whats selected as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) */ -ModeInterface.prototype.setSelected = function(features) { +ModeInterface.prototype.setSelected = function (features) { return this._ctx.store.setSelected(features); }; @@ -25,7 +25,7 @@ ModeInterface.prototype.setSelected = function(features) { * @name this.setSelectedCoordinates * @param {Object[]} coords - a array of {coord_path: 'string', feature_id: 'string'} */ -ModeInterface.prototype.setSelectedCoordinates = function(coords) { +ModeInterface.prototype.setSelectedCoordinates = function (coords) { this._ctx.store.setSelectedCoordinates(coords); coords.reduce((m, c) => { if (m[c.feature_id] === undefined) { @@ -41,7 +41,7 @@ ModeInterface.prototype.setSelectedCoordinates = function(coords) { * @name this.getSelected * @returns {DrawFeature[]} */ -ModeInterface.prototype.getSelected = function() { +ModeInterface.prototype.getSelected = function () { return this._ctx.store.getSelected(); }; @@ -50,7 +50,7 @@ ModeInterface.prototype.getSelected = function() { * @name this.getSelectedIds * @returns {String[]} */ -ModeInterface.prototype.getSelectedIds = function() { +ModeInterface.prototype.getSelectedIds = function () { return this._ctx.store.getSelectedIds(); }; @@ -60,7 +60,7 @@ ModeInterface.prototype.getSelectedIds = function() { * @param {String} id - a feature id * @returns {Boolean} */ -ModeInterface.prototype.isSelected = function(id) { +ModeInterface.prototype.isSelected = function (id) { return this._ctx.store.isSelected(id); }; @@ -70,7 +70,7 @@ ModeInterface.prototype.isSelected = function(id) { * @param {String} id - a feature id * @returns {DrawFeature} */ -ModeInterface.prototype.getFeature = function(id) { +ModeInterface.prototype.getFeature = function (id) { return this._ctx.store.get(id); }; @@ -79,7 +79,7 @@ ModeInterface.prototype.getFeature = function(id) { * @name this.select * @param {String} id */ -ModeInterface.prototype.select = function(id) { +ModeInterface.prototype.select = function (id) { return this._ctx.store.select(id); }; @@ -88,7 +88,7 @@ ModeInterface.prototype.select = function(id) { * @name this.delete * @param {String} id */ -ModeInterface.prototype.deselect = function(id) { +ModeInterface.prototype.deselect = function (id) { return this._ctx.store.deselect(id); }; @@ -97,7 +97,7 @@ ModeInterface.prototype.deselect = function(id) { * @name this.deleteFeature * @param {String} id - a feature id */ -ModeInterface.prototype.deleteFeature = function(id, opts = {}) { +ModeInterface.prototype.deleteFeature = function (id, opts = {}) { return this._ctx.store.delete(id, opts); }; @@ -107,21 +107,21 @@ ModeInterface.prototype.deleteFeature = function(id, opts = {}) { * @name this.addFeature * @param {DrawFeature} feature - the feature to add */ -ModeInterface.prototype.addFeature = function(feature, opts = {}) { +ModeInterface.prototype.addFeature = function (feature, opts = {}) { return this._ctx.store.add(feature, opts); }; /** * Clear all selected features */ -ModeInterface.prototype.clearSelectedFeatures = function() { +ModeInterface.prototype.clearSelectedFeatures = function () { return this._ctx.store.clearSelected(); }; /** * Clear all selected coordinates */ -ModeInterface.prototype.clearSelectedCoordinates = function() { +ModeInterface.prototype.clearSelectedCoordinates = function () { return this._ctx.store.clearSelectedCoordinates(); }; @@ -131,7 +131,7 @@ ModeInterface.prototype.clearSelectedCoordinates = function() { * @name this.setActionableState * @param {Object} actions */ -ModeInterface.prototype.setActionableState = function(actions = {}) { +ModeInterface.prototype.setActionableState = function (actions = {}) { const newSet = { trash: actions.trash || false, combineFeatures: actions.combineFeatures || false, @@ -147,7 +147,11 @@ ModeInterface.prototype.setActionableState = function(actions = {}) { * @param {Object} opts - the options object to pass to the new mode * @param {Object} eventOpts - used to control what kind of events are emitted. */ -ModeInterface.prototype.changeMode = function(mode, opts = {}, eventOpts = {}) { +ModeInterface.prototype.changeMode = function ( + mode, + opts = {}, + eventOpts = {} +) { return this._ctx.events.changeMode(mode, opts, eventOpts); }; @@ -157,7 +161,7 @@ ModeInterface.prototype.changeMode = function(mode, opts = {}, eventOpts = {}) { * @param {String} eventName - the event name. * @param {Object} eventData - the event data object. */ -ModeInterface.prototype.fire = function(eventName, eventData) { +ModeInterface.prototype.fire = function (eventName, eventData) { return this._ctx.events.fire(eventName, eventData); }; @@ -166,7 +170,7 @@ ModeInterface.prototype.fire = function(eventName, eventData) { * @name this.updateUIClasses * @param {Object} opts */ -ModeInterface.prototype.updateUIClasses = function(opts) { +ModeInterface.prototype.updateUIClasses = function (opts) { return this._ctx.ui.queueMapClasses(opts); }; @@ -175,7 +179,7 @@ ModeInterface.prototype.updateUIClasses = function(opts) { * @name this.activateUIButton * @param {String?} name - name of the button to make active, leave as undefined to set buttons to be inactive */ -ModeInterface.prototype.activateUIButton = function(name) { +ModeInterface.prototype.activateUIButton = function (name) { return this._ctx.ui.setActiveButton(name); }; @@ -186,8 +190,13 @@ ModeInterface.prototype.activateUIButton = function(name) { * @param {BBOX||NULL} bbox - the area to get features from * @param {String} bufferType - is this `click` or `tap` event, defaults to click */ -ModeInterface.prototype.featuresAt = function(event, bbox, bufferType = 'click') { - if (bufferType !== 'click' && bufferType !== 'touch') throw new Error('invalid buffer type'); +ModeInterface.prototype.featuresAt = function ( + event, + bbox, + bufferType = 'click' +) { + if (bufferType !== 'click' && bufferType !== 'touch') + throw new Error('invalid buffer type'); return featuresAt[bufferType](event, bbox, this._ctx); }; @@ -197,11 +206,14 @@ ModeInterface.prototype.featuresAt = function(event, bbox, bufferType = 'click') * @param {GeoJSONFeature} geojson * @returns {DrawFeature} */ -ModeInterface.prototype.newFeature = function(geojson) { +ModeInterface.prototype.newFeature = function (geojson) { const type = geojson.geometry.type; - if (type === Constants.geojsonTypes.POINT) return new Point(this._ctx, geojson); - if (type === Constants.geojsonTypes.LINE_STRING) return new LineString(this._ctx, geojson); - if (type === Constants.geojsonTypes.POLYGON) return new Polygon(this._ctx, geojson); + if (type === Constants.geojsonTypes.POINT) + return new Point(this._ctx, geojson); + if (type === Constants.geojsonTypes.LINE_STRING) + return new LineString(this._ctx, geojson); + if (type === Constants.geojsonTypes.POLYGON) + return new Polygon(this._ctx, geojson); return new MultiFeature(this._ctx, geojson); }; @@ -212,10 +224,12 @@ ModeInterface.prototype.newFeature = function(geojson) { * @param {Object} feature - the object that needs to be checked * @returns {Boolean} */ -ModeInterface.prototype.isInstanceOf = function(type, feature) { +ModeInterface.prototype.isInstanceOf = function (type, feature) { if (type === Constants.geojsonTypes.POINT) return feature instanceof Point; - if (type === Constants.geojsonTypes.LINE_STRING) return feature instanceof LineString; - if (type === Constants.geojsonTypes.POLYGON) return feature instanceof Polygon; + if (type === Constants.geojsonTypes.LINE_STRING) + return feature instanceof LineString; + if (type === Constants.geojsonTypes.POLYGON) + return feature instanceof Polygon; if (type === 'MultiFeature') return feature instanceof MultiFeature; throw new Error(`Unknown feature class: ${type}`); }; @@ -225,7 +239,6 @@ ModeInterface.prototype.isInstanceOf = function(type, feature) { * @name this.doRender * @param {String} id - a feature id */ -ModeInterface.prototype.doRender = function(id) { +ModeInterface.prototype.doRender = function (id) { return this._ctx.store.featureChanged(id); }; - diff --git a/src/modes/object_to_mode.ts b/src/modes/object_to_mode.ts index d71f4c60..73d0f70e 100644 --- a/src/modes/object_to_mode.ts +++ b/src/modes/object_to_mode.ts @@ -17,10 +17,10 @@ const eventMapper = { const eventKeys = Object.keys(eventMapper); -export default function(modeObject) { +export default function (modeObject) { const modeObjectKeys = Object.keys(modeObject); - return function(ctx, startOpts = {}) { + return function (ctx, startOpts = {}) { let state = {}; const mode = modeObjectKeys.reduce((m, k) => { @@ -41,7 +41,7 @@ export default function(modeObject) { // handlers that are not present in the mode // to reduce on render calls for functions that // have no logic - eventKeys.forEach((key) => { + eventKeys.forEach(key => { const modeHandler = eventMapper[key]; let selector = () => false; if (modeObject[modeHandler]) { @@ -49,7 +49,6 @@ export default function(modeObject) { } this.on(key, selector, wrapper(modeHandler)); }); - }, stop() { mode.onStop(state); diff --git a/src/modes/simple_select.ts b/src/modes/simple_select.ts index 649867d5..347bc565 100644 --- a/src/modes/simple_select.ts +++ b/src/modes/simple_select.ts @@ -8,7 +8,7 @@ import * as Constants from '../constants'; const SimpleSelect = {}; -SimpleSelect.onSetup = function(opts) { +SimpleSelect.onSetup = function (opts) { // turn the opts into state. const state = { dragMoveLocation: null, @@ -22,7 +22,11 @@ SimpleSelect.onSetup = function(opts) { initiallySelectedFeatureIds: opts.featureIds || [] }; - this.setSelected(state.initiallySelectedFeatureIds.filter(id => this.getFeature(id) !== undefined)); + this.setSelected( + state.initiallySelectedFeatureIds.filter( + id => this.getFeature(id) !== undefined + ) + ); this.fireActionable(); this.setActionableState({ @@ -34,18 +38,18 @@ SimpleSelect.onSetup = function(opts) { return state; }; -SimpleSelect.fireUpdate = function() { +SimpleSelect.fireUpdate = function () { this.fire(Constants.events.UPDATE, { action: Constants.updateActions.MOVE, features: this.getSelected().map(f => f.toGeoJSON()) }); }; -SimpleSelect.fireActionable = function() { +SimpleSelect.fireActionable = function () { const selectedFeatures = this.getSelected(); - const multiFeatures = selectedFeatures.filter( - feature => this.isInstanceOf('MultiFeature', feature) + const multiFeatures = selectedFeatures.filter(feature => + this.isInstanceOf('MultiFeature', feature) ); let combineFeatures = false; @@ -53,7 +57,7 @@ SimpleSelect.fireActionable = function() { if (selectedFeatures.length > 1) { combineFeatures = true; const featureType = selectedFeatures[0].type.replace('Multi', ''); - selectedFeatures.forEach((feature) => { + selectedFeatures.forEach(feature => { if (feature.type.replace('Multi', '') !== featureType) { combineFeatures = false; } @@ -64,13 +68,16 @@ SimpleSelect.fireActionable = function() { const trash = selectedFeatures.length > 0; this.setActionableState({ - combineFeatures, uncombineFeatures, trash + combineFeatures, + uncombineFeatures, + trash }); }; -SimpleSelect.getUniqueIds = function(allFeatures) { +SimpleSelect.getUniqueIds = function (allFeatures) { if (!allFeatures.length) return []; - const ids = allFeatures.map(s => s.properties.id) + const ids = allFeatures + .map(s => s.properties.id) .filter(id => id !== undefined) .reduce((memo, id) => { memo.add(id); @@ -80,13 +87,17 @@ SimpleSelect.getUniqueIds = function(allFeatures) { return ids.values(); }; -SimpleSelect.stopExtendedInteractions = function(state) { +SimpleSelect.stopExtendedInteractions = function (state) { if (state.boxSelectElement) { - if (state.boxSelectElement.parentNode) state.boxSelectElement.parentNode.removeChild(state.boxSelectElement); + if (state.boxSelectElement.parentNode) + state.boxSelectElement.parentNode.removeChild(state.boxSelectElement); state.boxSelectElement = null; } - if ((state.canDragMove || state.canBoxSelect) && state.initialDragPanState === true) { + if ( + (state.canDragMove || state.canBoxSelect) && + state.initialDragPanState === true + ) { this.map.dragPan.enable(); } @@ -96,11 +107,11 @@ SimpleSelect.stopExtendedInteractions = function(state) { state.canDragMove = false; }; -SimpleSelect.onStop = function() { +SimpleSelect.onStop = function () { doubleClickZoom.enable(this); }; -SimpleSelect.onMouseMove = function(state, e) { +SimpleSelect.onMouseMove = function (state, e) { const isFeature = CommonSelectors.isFeature(e); if (isFeature && state.dragMoving) this.fireUpdate(); @@ -115,7 +126,7 @@ SimpleSelect.onMouseMove = function(state, e) { return true; }; -SimpleSelect.onMouseOut = function(state) { +SimpleSelect.onMouseOut = function (state) { // As soon as you mouse leaves the canvas, update the feature if (state.dragMoving) return this.fireUpdate(); @@ -123,10 +134,11 @@ SimpleSelect.onMouseOut = function(state) { return true; }; -SimpleSelect.onTap = SimpleSelect.onClick = function(state, e) { +SimpleSelect.onTap = SimpleSelect.onClick = function (state, e) { // Click (with or without shift) on no feature if (CommonSelectors.noTarget(e)) return this.clickAnywhere(state, e); // also tap - if (CommonSelectors.isOfMetaType(Constants.meta.VERTEX)(e)) return this.clickOnVertex(state, e); //tap + if (CommonSelectors.isOfMetaType(Constants.meta.VERTEX)(e)) + return this.clickOnVertex(state, e); //tap if (CommonSelectors.isFeature(e)) return this.clickOnFeature(state, e); }; @@ -141,7 +153,7 @@ SimpleSelect.clickAnywhere = function (state) { this.stopExtendedInteractions(state); }; -SimpleSelect.clickOnVertex = function(state, e) { +SimpleSelect.clickOnVertex = function (state, e) { // Enter direct select mode this.changeMode(Constants.modes.DIRECT_SELECT, { featureId: e.featureTarget.properties.parent, @@ -151,7 +163,7 @@ SimpleSelect.clickOnVertex = function(state, e) { this.updateUIClasses({ mouse: Constants.cursors.MOVE }); }; -SimpleSelect.startOnActiveFeature = function(state, e) { +SimpleSelect.startOnActiveFeature = function (state, e) { // Stop any already-underway extended interactions this.stopExtendedInteractions(state); @@ -166,7 +178,7 @@ SimpleSelect.startOnActiveFeature = function(state, e) { state.dragMoveLocation = e.lngLat; }; -SimpleSelect.clickOnFeature = function(state, e) { +SimpleSelect.clickOnFeature = function (state, e) { // Stop everything doubleClickZoom.disable(this); this.stopExtendedInteractions(state); @@ -177,7 +189,11 @@ SimpleSelect.clickOnFeature = function(state, e) { const isFeatureSelected = this.isSelected(featureId); // Click (without shift) on any selected feature but a point - if (!isShiftClick && isFeatureSelected && this.getFeature(featureId).type !== Constants.geojsonTypes.POINT) { + if ( + !isShiftClick && + isFeatureSelected && + this.getFeature(featureId).type !== Constants.geojsonTypes.POINT + ) { // Enter direct select mode return this.changeMode(Constants.modes.DIRECT_SELECT, { featureId @@ -192,12 +208,12 @@ SimpleSelect.clickOnFeature = function(state, e) { if (selectedFeatureIds.length === 1) { doubleClickZoom.enable(this); } - // Shift-click on an unselected feature + // Shift-click on an unselected feature } else if (!isFeatureSelected && isShiftClick) { // Add it to the selection this.select(featureId); this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - // Click (without shift) on an unselected feature + // Click (without shift) on an unselected feature } else if (!isFeatureSelected && !isShiftClick) { // Make it the only selected feature selectedFeatureIds.forEach(id => this.doRender(id)); @@ -209,30 +225,37 @@ SimpleSelect.clickOnFeature = function(state, e) { this.doRender(featureId); }; -SimpleSelect.onMouseDown = function(state, e) { +SimpleSelect.onMouseDown = function (state, e) { state.initialDragPanState = this.map.dragPan.isEnabled(); - if (CommonSelectors.isActiveFeature(e)) return this.startOnActiveFeature(state, e); - if (this.drawConfig.boxSelect && CommonSelectors.isShiftMousedown(e)) return this.startBoxSelect(state, e); + if (CommonSelectors.isActiveFeature(e)) + return this.startOnActiveFeature(state, e); + if (this.drawConfig.boxSelect && CommonSelectors.isShiftMousedown(e)) + return this.startBoxSelect(state, e); }; -SimpleSelect.startBoxSelect = function(state, e) { +SimpleSelect.startBoxSelect = function (state, e) { this.stopExtendedInteractions(state); this.map.dragPan.disable(); // Enable box select - state.boxSelectStartLocation = mouseEventPoint(e.originalEvent, this.map.getContainer()); + state.boxSelectStartLocation = mouseEventPoint( + e.originalEvent, + this.map.getContainer() + ); state.canBoxSelect = true; }; -SimpleSelect.onTouchStart = function(state, e) { - if (CommonSelectors.isActiveFeature(e)) return this.startOnActiveFeature(state, e); +SimpleSelect.onTouchStart = function (state, e) { + if (CommonSelectors.isActiveFeature(e)) + return this.startOnActiveFeature(state, e); }; -SimpleSelect.onDrag = function(state, e) { +SimpleSelect.onDrag = function (state, e) { if (state.canDragMove) return this.dragMove(state, e); - if (this.drawConfig.boxSelect && state.canBoxSelect) return this.whileBoxSelect(state, e); + if (this.drawConfig.boxSelect && state.canBoxSelect) + return this.whileBoxSelect(state, e); }; -SimpleSelect.whileBoxSelect = function(state, e) { +SimpleSelect.whileBoxSelect = function (state, e) { state.boxSelecting = true; this.updateUIClasses({ mouse: Constants.cursors.ADD }); @@ -256,7 +279,7 @@ SimpleSelect.whileBoxSelect = function(state, e) { state.boxSelectElement.style.height = `${maxY - minY}px`; }; -SimpleSelect.dragMove = function(state, e) { +SimpleSelect.dragMove = function (state, e) { // Dragging when drag move is enabled state.dragMoving = true; e.originalEvent.stopPropagation(); @@ -271,7 +294,7 @@ SimpleSelect.dragMove = function(state, e) { state.dragMoveLocation = e.lngLat; }; -SimpleSelect.onTouchEnd = SimpleSelect.onMouseUp = function(state, e) { +SimpleSelect.onTouchEnd = SimpleSelect.onMouseUp = function (state, e) { // End any extended interactions if (state.dragMoving) { this.fireUpdate(); @@ -281,8 +304,9 @@ SimpleSelect.onTouchEnd = SimpleSelect.onMouseUp = function(state, e) { mouseEventPoint(e.originalEvent, this.map.getContainer()) ]; const featuresInBox = this.featuresAt(null, bbox, 'click'); - const idsToSelect = this.getUniqueIds(featuresInBox) - .filter(id => !this.isSelected(id)); + const idsToSelect = this.getUniqueIds(featuresInBox).filter( + id => !this.isSelected(id) + ); if (idsToSelect.length) { this.select(idsToSelect); @@ -293,27 +317,32 @@ SimpleSelect.onTouchEnd = SimpleSelect.onMouseUp = function(state, e) { this.stopExtendedInteractions(state); }; -SimpleSelect.toDisplayFeatures = function(state, geojson, display) { - geojson.properties.active = (this.isSelected(geojson.properties.id)) ? - Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE; +SimpleSelect.toDisplayFeatures = function (state, geojson, display) { + geojson.properties.active = this.isSelected(geojson.properties.id) + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; display(geojson); this.fireActionable(); - if (geojson.properties.active !== Constants.activeStates.ACTIVE || - geojson.geometry.type === Constants.geojsonTypes.POINT) return; + if ( + geojson.properties.active !== Constants.activeStates.ACTIVE || + geojson.geometry.type === Constants.geojsonTypes.POINT + ) + return; createSupplementaryPoints(geojson).forEach(display); }; -SimpleSelect.onTrash = function() { +SimpleSelect.onTrash = function () { this.deleteFeature(this.getSelectedIds()); this.fireActionable(); }; -SimpleSelect.onCombineFeatures = function() { +SimpleSelect.onCombineFeatures = function () { const selectedFeatures = this.getSelected(); if (selectedFeatures.length === 0 || selectedFeatures.length < 2) return; - const coordinates = [], featuresCombined = []; + const coordinates = [], + featuresCombined = []; const featureType = selectedFeatures[0].type.replace('Multi', ''); for (let i = 0; i < selectedFeatures.length; i++) { @@ -323,7 +352,7 @@ SimpleSelect.onCombineFeatures = function() { return; } if (feature.type.includes('Multi')) { - feature.getCoordinates().forEach((subcoords) => { + feature.getCoordinates().forEach(subcoords => { coordinates.push(subcoords); }); } else { @@ -355,7 +384,7 @@ SimpleSelect.onCombineFeatures = function() { this.fireActionable(); }; -SimpleSelect.onUncombineFeatures = function() { +SimpleSelect.onUncombineFeatures = function () { const selectedFeatures = this.getSelected(); if (selectedFeatures.length === 0) return; @@ -366,7 +395,7 @@ SimpleSelect.onUncombineFeatures = function() { const feature = selectedFeatures[i]; if (this.isInstanceOf('MultiFeature', feature)) { - feature.getFeatures().forEach((subFeature) => { + feature.getFeatures().forEach(subFeature => { this.addFeature(subFeature); subFeature.properties = feature.properties; createdFeatures.push(subFeature.toGeoJSON()); diff --git a/src/options.ts b/src/options.ts index 0a36233b..956af34b 100644 --- a/src/options.ts +++ b/src/options.ts @@ -36,16 +36,17 @@ const hideControls = { }; function addSources(styles, sourceBucket) { - return styles.map((style) => { + return styles.map(style => { if (style.source) return style; return Object.assign({}, style, { id: `${style.id}.${sourceBucket}`, - source: (sourceBucket === 'hot') ? Constants.sources.HOT : Constants.sources.COLD + source: + sourceBucket === 'hot' ? Constants.sources.HOT : Constants.sources.COLD }); }); } -export default function(options = {}) { +export default function (options = {}) { let withDefaults = Object.assign({}, options); if (!options.controls) { @@ -61,7 +62,9 @@ export default function(options = {}) { withDefaults = Object.assign({}, defaultOptions, withDefaults); // Layers with a shared source should be adjacent for performance reasons - withDefaults.styles = addSources(withDefaults.styles, 'cold').concat(addSources(withDefaults.styles, 'hot')); + withDefaults.styles = addSources(withDefaults.styles, 'cold').concat( + addSources(withDefaults.styles, 'hot') + ); return withDefaults; } diff --git a/src/render.ts b/src/render.ts index 879ef055..f83f818a 100644 --- a/src/render.ts +++ b/src/render.ts @@ -3,7 +3,9 @@ import * as Constants from './constants'; export default function render() { // eslint-disable-next-line no-invalid-this const store = this; - const mapExists = store.ctx.map && store.ctx.map.getSource(Constants.sources.HOT) !== undefined; + const mapExists = + store.ctx.map && + store.ctx.map.getSource(Constants.sources.HOT) !== undefined; if (!mapExists) return cleanup(); const mode = store.ctx.events.currentModeName(); @@ -17,24 +19,34 @@ export default function render() { newColdIds = store.getAllIds(); } else { newHotIds = store.getChangedIds().filter(id => store.get(id) !== undefined); - newColdIds = store.sources.hot.filter(geojson => geojson.properties.id && newHotIds.indexOf(geojson.properties.id) === -1 && store.get(geojson.properties.id) !== undefined).map(geojson => geojson.properties.id); + newColdIds = store.sources.hot + .filter( + geojson => + geojson.properties.id && + newHotIds.indexOf(geojson.properties.id) === -1 && + store.get(geojson.properties.id) !== undefined + ) + .map(geojson => geojson.properties.id); } store.sources.hot = []; const lastColdCount = store.sources.cold.length; - store.sources.cold = store.isDirty ? [] : store.sources.cold.filter((geojson) => { - const id = geojson.properties.id || geojson.properties.parent; - return newHotIds.indexOf(id) === -1; - }); + store.sources.cold = store.isDirty + ? [] + : store.sources.cold.filter(geojson => { + const id = geojson.properties.id || geojson.properties.parent; + return newHotIds.indexOf(id) === -1; + }); - const coldChanged = lastColdCount !== store.sources.cold.length || newColdIds.length > 0; + const coldChanged = + lastColdCount !== store.sources.cold.length || newColdIds.length > 0; newHotIds.forEach(id => renderFeature(id, 'hot')); newColdIds.forEach(id => renderFeature(id, 'cold')); function renderFeature(id, source) { const feature = store.get(id); const featureInternal = feature.internal(mode); - store.ctx.events.currentModeRender(featureInternal, (geojson) => { + store.ctx.events.currentModeRender(featureInternal, geojson => { geojson.properties.mode = mode; store.sources[source].push(geojson); }); diff --git a/src/setup.ts b/src/setup.ts index c16c5677..8a5f9909 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -3,8 +3,7 @@ import Store from './store'; import ui from './ui'; import * as Constants from './constants'; -export default function(ctx) { - +export default function (ctx) { let controlContainer = null; let mapLoadedInterval = null; @@ -24,7 +23,8 @@ export default function(ctx) { ctx.container = null; ctx.store = null; - if (controlContainer && controlContainer.parentNode) controlContainer.parentNode.removeChild(controlContainer); + if (controlContainer && controlContainer.parentNode) + controlContainer.parentNode.removeChild(controlContainer); controlContainer = null; return this; @@ -43,7 +43,6 @@ export default function(ctx) { ctx.container = map.getContainer(); ctx.store = new Store(ctx); - controlContainer = ctx.ui.addButtons(); if (ctx.options.boxSelect) { @@ -63,7 +62,9 @@ export default function(ctx) { setup.connect(); } else { map.on('load', setup.connect); - mapLoadedInterval = setInterval(() => { if (map.loaded()) setup.connect(); }, 16); + mapLoadedInterval = setInterval(() => { + if (map.loaded()) setup.connect(); + }, 16); } ctx.events.start(); @@ -88,7 +89,7 @@ export default function(ctx) { type: 'geojson' }); - ctx.options.styles.forEach((style) => { + ctx.options.styles.forEach(style => { ctx.map.addLayer(style); }); @@ -98,7 +99,7 @@ export default function(ctx) { // Check for layers and sources before attempting to remove // If user adds draw control and removes it before the map is loaded, layers and sources will be missing removeLayers() { - ctx.options.styles.forEach((style) => { + ctx.options.styles.forEach(style => { if (ctx.map.getLayer(style.id)) { ctx.map.removeLayer(style.id); } diff --git a/src/store.ts b/src/store.ts index 3155ecc8..34058a02 100644 --- a/src/store.ts +++ b/src/store.ts @@ -55,10 +55,10 @@ export default function Store(ctx) { * Delays all rendering until the returned function is invoked * @return {Function} renderBatch */ -Store.prototype.createRenderBatch = function() { +Store.prototype.createRenderBatch = function () { const holdRender = this.render; let numRenders = 0; - this.render = function() { + this.render = function () { numRenders++; }; @@ -74,7 +74,7 @@ Store.prototype.createRenderBatch = function() { * Sets the store's state to dirty. * @return {Store} this */ -Store.prototype.setDirty = function() { +Store.prototype.setDirty = function () { this.isDirty = true; return this; }; @@ -84,10 +84,13 @@ Store.prototype.setDirty = function() { * @param {string} featureId * @return {Store} this */ -Store.prototype.featureCreated = function(featureId, options = {}) { +Store.prototype.featureCreated = function (featureId, options = {}) { this._changedFeatureIds.add(featureId); - const silent = options.silent != null ? options.silent : this.ctx.options.suppressAPIEvents; + const silent = + options.silent != null + ? options.silent + : this.ctx.options.suppressAPIEvents; if (silent !== true) { const feature = this.get(featureId); this.ctx.events.fire(Constants.events.CREATE, { @@ -103,13 +106,18 @@ Store.prototype.featureCreated = function(featureId, options = {}) { * @param {string} featureId * @return {Store} this */ -Store.prototype.featureChanged = function(featureId, options = {}) { +Store.prototype.featureChanged = function (featureId, options = {}) { this._changedFeatureIds.add(featureId); - const silent = options.silent != null ? options.silent : this.ctx.options.suppressAPIEvents; + const silent = + options.silent != null + ? options.silent + : this.ctx.options.suppressAPIEvents; if (silent !== true) { this.ctx.events.fire(Constants.events.UPDATE, { - action: options.action ? options.action : Constants.updateActions.CHANGE_COORDINATES, + action: options.action + ? options.action + : Constants.updateActions.CHANGE_COORDINATES, features: [this.get(featureId).toGeoJSON()] }); } @@ -121,7 +129,7 @@ Store.prototype.featureChanged = function(featureId, options = {}) { * Gets the ids of all features currently in changed state. * @return {Store} this */ -Store.prototype.getChangedIds = function() { +Store.prototype.getChangedIds = function () { return this._changedFeatureIds.values(); }; @@ -129,7 +137,7 @@ Store.prototype.getChangedIds = function() { * Sets all features to unchanged state. * @return {Store} this */ -Store.prototype.clearChangedIds = function() { +Store.prototype.clearChangedIds = function () { this._changedFeatureIds.clear(); return this; }; @@ -138,7 +146,7 @@ Store.prototype.clearChangedIds = function() { * Gets the ids of all features in the store. * @return {Store} this */ -Store.prototype.getAllIds = function() { +Store.prototype.getAllIds = function () { return this._featureIds.values(); }; @@ -150,10 +158,10 @@ Store.prototype.getAllIds = function() { * * @return {Store} this */ -Store.prototype.add = function(feature, options = {}) { +Store.prototype.add = function (feature, options = {}) { this._features[feature.id] = feature; this._featureIds.add(feature.id); - this.featureCreated(feature.id, {silent: options.silent}); + this.featureCreated(feature.id, { silent: options.silent }); return this; }; @@ -167,9 +175,9 @@ Store.prototype.add = function(feature, options = {}) { * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. * @return {Store} this */ -Store.prototype.delete = function(featureIds, options = {}) { +Store.prototype.delete = function (featureIds, options = {}) { const deletedFeaturesToEmit = []; - toDenseArray(featureIds).forEach((id) => { + toDenseArray(featureIds).forEach(id => { if (!this._featureIds.has(id)) return; this._featureIds.delete(id); this._selectedFeatureIds.delete(id); @@ -183,7 +191,9 @@ Store.prototype.delete = function(featureIds, options = {}) { }); if (deletedFeaturesToEmit.length) { - this.ctx.events.fire(Constants.events.DELETE, {features: deletedFeaturesToEmit}); + this.ctx.events.fire(Constants.events.DELETE, { + features: deletedFeaturesToEmit + }); } refreshSelectedCoordinates(this, options); @@ -194,7 +204,7 @@ Store.prototype.delete = function(featureIds, options = {}) { * Returns a feature in the store matching the specified value. * @return {Object | undefined} feature */ -Store.prototype.get = function(id) { +Store.prototype.get = function (id) { return this._features[id]; }; @@ -202,7 +212,7 @@ Store.prototype.get = function(id) { * Returns all features in the store. * @return {Array} */ -Store.prototype.getAll = function() { +Store.prototype.getAll = function () { return Object.keys(this._features).map(id => this._features[id]); }; @@ -213,8 +223,8 @@ Store.prototype.getAll = function() { * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. * @return {Store} this */ -Store.prototype.select = function(featureIds, options = {}) { - toDenseArray(featureIds).forEach((id) => { +Store.prototype.select = function (featureIds, options = {}) { + toDenseArray(featureIds).forEach(id => { if (this._selectedFeatureIds.has(id)) return; this._selectedFeatureIds.add(id); this._changedFeatureIds.add(id); @@ -232,8 +242,8 @@ Store.prototype.select = function(featureIds, options = {}) { * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. * @return {Store} this */ -Store.prototype.deselect = function(featureIds, options = {}) { - toDenseArray(featureIds).forEach((id) => { +Store.prototype.deselect = function (featureIds, options = {}) { + toDenseArray(featureIds).forEach(id => { if (!this._selectedFeatureIds.has(id)) return; this._selectedFeatureIds.delete(id); this._changedFeatureIds.add(id); @@ -251,7 +261,7 @@ Store.prototype.deselect = function(featureIds, options = {}) { * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. * @return {Store} this */ -Store.prototype.clearSelected = function(options = {}) { +Store.prototype.clearSelected = function (options = {}) { this.deselect(this._selectedFeatureIds.values(), { silent: options.silent }); return this; }; @@ -264,14 +274,22 @@ Store.prototype.clearSelected = function(options = {}) { * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. * @return {Store} this */ -Store.prototype.setSelected = function(featureIds, options = {}) { +Store.prototype.setSelected = function (featureIds, options = {}) { featureIds = toDenseArray(featureIds); // Deselect any features not in the new selection - this.deselect(this._selectedFeatureIds.values().filter(id => featureIds.indexOf(id) === -1), { silent: options.silent }); + this.deselect( + this._selectedFeatureIds + .values() + .filter(id => featureIds.indexOf(id) === -1), + { silent: options.silent } + ); // Select any features in the new selection that were not already selected - this.select(featureIds.filter(id => !this._selectedFeatureIds.has(id)), { silent: options.silent }); + this.select( + featureIds.filter(id => !this._selectedFeatureIds.has(id)), + { silent: options.silent } + ); return this; }; @@ -281,7 +299,7 @@ Store.prototype.setSelected = function(featureIds, options = {}) { * @param {Array>} coordinates * @return {Store} this */ -Store.prototype.setSelectedCoordinates = function(coordinates) { +Store.prototype.setSelectedCoordinates = function (coordinates) { this._selectedCoordinates = coordinates; this._emitSelectionChange = true; return this; @@ -292,7 +310,7 @@ Store.prototype.setSelectedCoordinates = function(coordinates) { * @param {Object} [options] * @return {Store} this */ -Store.prototype.clearSelectedCoordinates = function() { +Store.prototype.clearSelectedCoordinates = function () { this._selectedCoordinates = []; this._emitSelectionChange = true; return this; @@ -302,7 +320,7 @@ Store.prototype.clearSelectedCoordinates = function() { * Returns the ids of features in the current selection. * @return {Array} Selected feature ids. */ -Store.prototype.getSelectedIds = function() { +Store.prototype.getSelectedIds = function () { return this._selectedFeatureIds.values(); }; @@ -310,7 +328,7 @@ Store.prototype.getSelectedIds = function() { * Returns features in the current selection. * @return {Array} Selected features. */ -Store.prototype.getSelected = function() { +Store.prototype.getSelected = function () { return this.getSelectedIds().map(id => this.get(id)); }; @@ -318,8 +336,8 @@ Store.prototype.getSelected = function() { * Returns selected coordinates in the currently selected feature. * @return {Array} Selected coordinates. */ -Store.prototype.getSelectedCoordinates = function() { - const selected = this._selectedCoordinates.map((coordinate) => { +Store.prototype.getSelectedCoordinates = function () { + const selected = this._selectedCoordinates.map(coordinate => { const feature = this.get(coordinate.feature_id); return { coordinates: feature.getCoordinate(coordinate.coord_path) @@ -333,7 +351,7 @@ Store.prototype.getSelectedCoordinates = function() { * @param {string} featureId * @return {boolean} `true` if the feature is selected, `false` if not. */ -Store.prototype.isSelected = function(featureId) { +Store.prototype.isSelected = function (featureId) { return this._selectedFeatureIds.has(featureId); }; @@ -344,8 +362,13 @@ Store.prototype.isSelected = function(featureId) { * @param {string} property value * @param {Object} [options] * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. -*/ -Store.prototype.setFeatureProperty = function(featureId, property, value, options = {}) { + */ +Store.prototype.setFeatureProperty = function ( + featureId, + property, + value, + options = {} +) { this.get(featureId).setProperty(property, value); this.featureChanged(featureId, { @@ -355,8 +378,13 @@ Store.prototype.setFeatureProperty = function(featureId, property, value, option }; function refreshSelectedCoordinates(store, options = {}) { - const newSelectedCoordinates = store._selectedCoordinates.filter(point => store._selectedFeatureIds.has(point.feature_id)); - if (store._selectedCoordinates.length !== newSelectedCoordinates.length && !options.silent) { + const newSelectedCoordinates = store._selectedCoordinates.filter(point => + store._selectedFeatureIds.has(point.feature_id) + ); + if ( + store._selectedCoordinates.length !== newSelectedCoordinates.length && + !options.silent + ) { store._emitSelectionChange = true; } store._selectedCoordinates = newSelectedCoordinates; @@ -364,21 +392,22 @@ function refreshSelectedCoordinates(store, options = {}) { /** * Stores the initial config for a map, so that we can set it again after we're done. -*/ -Store.prototype.storeMapConfig = function() { - Constants.interactions.forEach((interaction) => { + */ +Store.prototype.storeMapConfig = function () { + Constants.interactions.forEach(interaction => { const interactionSet = this.ctx.map[interaction]; if (interactionSet) { - this._mapInitialConfig[interaction] = this.ctx.map[interaction].isEnabled(); + this._mapInitialConfig[interaction] = + this.ctx.map[interaction].isEnabled(); } }); }; /** * Restores the initial config for a map, ensuring all is well. -*/ -Store.prototype.restoreMapConfig = function() { - Object.keys(this._mapInitialConfig).forEach((key) => { + */ +Store.prototype.restoreMapConfig = function () { + Object.keys(this._mapInitialConfig).forEach(key => { const value = this._mapInitialConfig[key]; if (value) { this.ctx.map[key].enable(); @@ -393,8 +422,8 @@ Store.prototype.restoreMapConfig = function() { * @param {string} interaction * @return {boolean} `true` if the interaction is enabled, `false` if not. * Defaults to `true`. (Todo: include defaults.) -*/ -Store.prototype.getInitialConfigValue = function(interaction) { + */ +Store.prototype.getInitialConfigValue = function (interaction) { if (this._mapInitialConfig[interaction] !== undefined) { return this._mapInitialConfig[interaction]; } else { diff --git a/src/types/types.ts b/src/types/types.ts index 49522f3b..f5856064 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,12 +1,21 @@ import { modes, meta, types } from '../constants'; -import { BBox, Feature, FeatureCollection, GeoJSON, GeoJsonTypes, Geometry, Point, Position } from 'geojson'; +import { + BBox, + Feature, + FeatureCollection, + GeoJSON, + GeoJsonTypes, + Geometry, + Point, + Position +} from 'geojson'; import type { ControlPosition, IControl, Map, Layer, MapMouseEvent as MapboxMapMouseEvent, - MapTouchEvent as MapboxMapTouchEvent, + MapTouchEvent as MapboxMapTouchEvent } from 'mapbox-gl'; export interface MapMouseEvent extends MapboxMapMouseEvent { @@ -25,7 +34,7 @@ export interface DrawOptions { touchBuffer: number; controls: Controls; displayControlsDefault: boolean; - styles: Array + styles: Array; } export interface Controls { @@ -33,8 +42,8 @@ export interface Controls { line_string: boolean; polygon: boolean; trash: boolean; - combine_features: boolean - uncombine_features: boolean + combine_features: boolean; + uncombine_features: boolean; } type Modes = typeof modes; @@ -65,14 +74,14 @@ interface DrawPolygon extends DrawFeatureBase { } interface DrawFeatureBase { - readonly properties: Readonly; + readonly properties: Readonly; readonly coordinates: Coordinates; - readonly id: NonNullable; + readonly id: NonNullable; readonly type: GeoJsonTypes; changed(): void; isValid(): boolean; - incomingCoords: this["setCoordinates"]; + incomingCoords: this['setCoordinates']; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; getCoordinate(path: string): Position; @@ -81,23 +90,27 @@ interface DrawFeatureBase { toGeoJSON(): GeoJSON; } -interface DrawMultiFeature extends - Omit< +interface DrawMultiFeature< + Type extends 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' +> extends Omit< DrawFeatureBase< | (Type extends 'MultiPoint' ? Array : never) - | (Type extends 'MultiLineString' ? Array : never) - | (Type extends 'MultiPolygon' ? Array : never) + | (Type extends 'MultiLineString' + ? Array + : never) + | (Type extends 'MultiPolygon' + ? Array + : never) >, - "coordinates" - > -{ + 'coordinates' + > { readonly type: Type; readonly features: Array< | (Type extends 'MultiPoint' ? DrawPoint : never) | (Type extends 'MultiLineString' ? DrawLineString : never) | (Type extends 'MultiPolygon' ? DrawPolygon : never) >; - getFeatures(): this["features"]; + getFeatures(): this['features']; } type DrawFeature = @@ -118,7 +131,9 @@ export interface DrawCTX { map: Map; drawConfig: DrawOptions; setSelected(features?: string | string[]): void; - setSelectedCoordinates(coords: Array<{ coord_path: string; feature_id: string }>): void; + setSelectedCoordinates( + coords: Array<{ coord_path: string; feature_id: string }> + ): void; getSelected(): DrawFeature[]; getSelectedIds(): string[]; isSelected(id: string): boolean; @@ -133,25 +148,72 @@ export interface DrawCTX { changeMode(mode: Modes, opts?: object, eventOpts?: object): void; updateUIClasses(opts: object): void; activateUIButton(name?: string): void; - featuresAt(event: Event, bbox: BBox, bufferType: 'click' | 'tap'): DrawFeature[]; + featuresAt( + event: Event, + bbox: BBox, + bufferType: 'click' | 'tap' + ): DrawFeature[]; newFeature(geojson: GeoJSON): DrawFeature; isInstanceOf(type: string, feature: object): boolean; doRender(id: string): void; } -export interface DrawCustomMode { +export interface DrawCustomMode< + CustomModeState = unknown, + CustomModeOptions = unknown +> { onSetup?(this: DrawCTX & this, options: CustomModeOptions): CustomModeState; onDrag?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onClick?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseMove?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseDown?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseUp?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseOut?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onKeyUp?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; - onKeyDown?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; - onTouchStart?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; - onTouchMove?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; - onTouchEnd?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onClick?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseMove?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseDown?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseUp?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseOut?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onKeyUp?( + this: DrawCTX & this, + state: CustomModeState, + e: KeyboardEvent + ): void; + onKeyDown?( + this: DrawCTX & this, + state: CustomModeState, + e: KeyboardEvent + ): void; + onTouchStart?( + this: DrawCTX & this, + state: CustomModeState, + e: MapTouchEvent + ): void; + onTouchMove?( + this: DrawCTX & this, + state: CustomModeState, + e: MapTouchEvent + ): void; + onTouchEnd?( + this: DrawCTX & this, + state: CustomModeState, + e: MapTouchEvent + ): void; onTap?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; onStop?(this: DrawCTX & this, state: CustomModeState): void; onTrash?(this: DrawCTX & this, state: CustomModeState): void; @@ -161,7 +223,7 @@ export interface DrawCustomMode void, + display: (geojson: GeoJSON) => void ): void; } @@ -185,14 +247,23 @@ export declare class Draw implements IControl { combineFeatures(): this; uncombineFeatures(): this; getMode(): (Modes & {}) | string; - changeMode(mode: typeof modes['SIMPLE_SELECT'], options?: { featureIds: string[] }): this; - changeMode(mode: typeof modes['DIRECT_SELECT'], options: { featureId: string }): this; changeMode( - mode: typeof modes['DRAW_LINE_STRING'], - options?: { featureId: string; from: Feature | Point | number[] }, + mode: (typeof modes)['SIMPLE_SELECT'], + options?: { featureIds: string[] } + ): this; + changeMode( + mode: (typeof modes)['DIRECT_SELECT'], + options: { featureId: string } + ): this; + changeMode( + mode: (typeof modes)['DRAW_LINE_STRING'], + options?: { featureId: string; from: Feature | Point | number[] } ): this; changeMode(mode: Modes): this; - changeMode(mode: T & (T extends Modes ? never : T), options?: object): this; + changeMode( + mode: T & (T extends Modes ? never : T), + options?: object + ): this; setFeatureProperty(featureId: string, property: string, value: any): this; onAdd(map: Map): HTMLElement; onRemove(map: Map): unknown; diff --git a/src/ui.ts b/src/ui.ts index 22b8f1ec..2815d2b7 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -2,9 +2,7 @@ import * as Constants from './constants'; const classTypes = ['mode', 'feature', 'mouse']; -export default function(ctx) { - - +export default function (ctx) { const buttonElements = {}; let activeButton = null; @@ -21,7 +19,7 @@ export default function(ctx) { }; function clearMapClasses() { - queueMapClasses({mode:null, feature:null, mouse:null}); + queueMapClasses({ mode: null, feature: null, mouse: null }); updateMapClasses(); } @@ -35,7 +33,7 @@ export default function(ctx) { const classesToRemove = []; const classesToAdd = []; - classTypes.forEach((type) => { + classTypes.forEach(type => { if (nextMapClasses[type] === currentMapClasses[type]) return; classesToRemove.push(`${type}-${currentMapClasses[type]}`); @@ -61,20 +59,24 @@ export default function(ctx) { button.setAttribute('title', options.title); options.container.appendChild(button); - button.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - - const clickedButton = e.target; - if (clickedButton === activeButton) { - deactivateButtons(); - options.onDeactivate(); - return; - } + button.addEventListener( + 'click', + e => { + e.preventDefault(); + e.stopPropagation(); + + const clickedButton = e.target; + if (clickedButton === activeButton) { + deactivateButtons(); + options.onDeactivate(); + return; + } - setActiveButton(id); - options.onActivate(); - }, true); + setActiveButton(id); + options.onActivate(); + }, + true + ); return button; } @@ -105,34 +107,43 @@ export default function(ctx) { if (!controls) return controlGroup; if (controls[Constants.types.POINT]) { - buttonElements[Constants.types.POINT] = createControlButton(Constants.types.POINT, { - container: controlGroup, - className: Constants.classes.CONTROL_BUTTON_POINT, - title: `Marker tool ${ctx.options.keybindings ? '(1)' : ''}`, - onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POINT), - onDeactivate: () => ctx.events.trash() - }); + buttonElements[Constants.types.POINT] = createControlButton( + Constants.types.POINT, + { + container: controlGroup, + className: Constants.classes.CONTROL_BUTTON_POINT, + title: `Marker tool ${ctx.options.keybindings ? '(1)' : ''}`, + onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POINT), + onDeactivate: () => ctx.events.trash() + } + ); } - if (controls[Constants.types.LINE]) { - buttonElements[Constants.types.LINE] = createControlButton(Constants.types.LINE, { - container: controlGroup, - className: Constants.classes.CONTROL_BUTTON_LINE, - title: `LineString tool ${ctx.options.keybindings ? '(2)' : ''}`, - onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_LINE_STRING), - onDeactivate: () => ctx.events.trash() - }); + buttonElements[Constants.types.LINE] = createControlButton( + Constants.types.LINE, + { + container: controlGroup, + className: Constants.classes.CONTROL_BUTTON_LINE, + title: `LineString tool ${ctx.options.keybindings ? '(2)' : ''}`, + onActivate: () => + ctx.events.changeMode(Constants.modes.DRAW_LINE_STRING), + onDeactivate: () => ctx.events.trash() + } + ); } if (controls[Constants.types.POLYGON]) { - buttonElements[Constants.types.POLYGON] = createControlButton(Constants.types.POLYGON, { - container: controlGroup, - className: Constants.classes.CONTROL_BUTTON_POLYGON, - title: `Polygon tool ${ctx.options.keybindings ? '(3)' : ''}`, - onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POLYGON), - onDeactivate: () => ctx.events.trash() - }); + buttonElements[Constants.types.POLYGON] = createControlButton( + Constants.types.POLYGON, + { + container: controlGroup, + className: Constants.classes.CONTROL_BUTTON_POLYGON, + title: `Polygon tool ${ctx.options.keybindings ? '(3)' : ''}`, + onActivate: () => ctx.events.changeMode(Constants.modes.DRAW_POLYGON), + onDeactivate: () => ctx.events.trash() + } + ); } if (controls.trash) { @@ -158,21 +169,24 @@ export default function(ctx) { } if (controls.uncombine_features) { - buttonElements.uncombine_features = createControlButton('uncombineFeatures', { - container: controlGroup, - className: Constants.classes.CONTROL_BUTTON_UNCOMBINE_FEATURES, - title: 'Uncombine', - onActivate: () => { - ctx.events.uncombineFeatures(); + buttonElements.uncombine_features = createControlButton( + 'uncombineFeatures', + { + container: controlGroup, + className: Constants.classes.CONTROL_BUTTON_UNCOMBINE_FEATURES, + title: 'Uncombine', + onActivate: () => { + ctx.events.uncombineFeatures(); + } } - }); + ); } return controlGroup; } function removeButtons() { - Object.keys(buttonElements).forEach((buttonId) => { + Object.keys(buttonElements).forEach(buttonId => { const button = buttonElements[buttonId]; if (button.parentNode) { button.parentNode.removeChild(button); diff --git a/test/api.test.js b/test/api.test.js index 7f5fb924..fb6c76d5 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -1,13 +1,13 @@ /* eslint no-shadow:[0] */ -import {test, beforeEach, afterEach} from 'node:test'; +import { test, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import * as Constants from '../src/constants'; import MapboxDraw from '../index'; import createMap from './utils/create_map'; import getGeoJSON from './utils/get_geojson'; -import {setupAfterNextRender} from './utils/after_next_render'; +import { setupAfterNextRender } from './utils/after_next_render'; import getPublicMemberKeys from './utils/get_public_member_keys'; let map; @@ -33,7 +33,7 @@ afterEach(() => { deleteSpy = null; }); -test('Draw.add', async (t) => { +test('Draw.add', async t => { await t.test('should generate unique ID', () => { const [id] = Draw.add(getGeoJSON('point')); @@ -56,7 +56,11 @@ test('Draw.getFeatureIdsAt', async () => { }); assert.equal(featureIds.length, 1, 'should return the added feature'); - assert.equal(featureIds[0], id, 'selected feature should match desired feature'); + assert.equal( + featureIds[0], + id, + 'selected feature should match desired feature' + ); Draw.deleteAll(); }); @@ -66,18 +70,13 @@ test('Draw.getSelectedIds', () => { const [polygonId] = Draw.add(getGeoJSON('polygon')); Draw.changeMode('simple_select', { featureIds: [lineId, pointId] }); const selected = Draw.getSelectedIds(); - assert.equal(selected.length, 2, - 'returns correct number of ids'); - assert.notEqual(selected.indexOf(lineId), -1, - 'result contains line'); - assert.notEqual(selected.indexOf(pointId), -1, - 'result contains point'); + assert.equal(selected.length, 2, 'returns correct number of ids'); + assert.notEqual(selected.indexOf(lineId), -1, 'result contains line'); + assert.notEqual(selected.indexOf(pointId), -1, 'result contains point'); Draw.changeMode('simple_select', { featureIds: [polygonId] }); const nextSelected = Draw.getSelectedIds(); - assert.equal(nextSelected.length, 1, - 'updates length'); - assert.equal(nextSelected[0], polygonId, - 'updates content'); + assert.equal(nextSelected.length, 1, 'updates length'); + assert.equal(nextSelected[0], polygonId, 'updates content'); }); test('Draw.getSelected', () => { @@ -90,18 +89,13 @@ test('Draw.getSelected', () => { assert.equal(typeof fc.features, 'object', 'we have a feature collection'); const selected = fc.features.map(f => f.id); - assert.equal(selected.length, 2, - 'returns correct number of ids'); - assert.notEqual(selected.indexOf(lineId), -1, - 'result contains line'); - assert.notEqual(selected.indexOf(pointId), -1, - 'result contains point'); + assert.equal(selected.length, 2, 'returns correct number of ids'); + assert.notEqual(selected.indexOf(lineId), -1, 'result contains line'); + assert.notEqual(selected.indexOf(pointId), -1, 'result contains point'); Draw.changeMode('simple_select', { featureIds: [polygonId] }); const nextSelected = Draw.getSelected().features.map(f => f.id); - assert.equal(nextSelected.length, 1, - 'updates length'); - assert.equal(nextSelected[0], polygonId, - 'updates content'); + assert.equal(nextSelected.length, 1, 'updates length'); + assert.equal(nextSelected[0], polygonId, 'updates content'); }); test('Draw.set', () => { @@ -115,19 +109,22 @@ test('Draw.set', () => { features: [point, line, polygon] }; const drawInstance = Draw.set(collection); - assert.equal(drawInstance.length, 3, - 'return value is correct length'); + assert.equal(drawInstance.length, 3, 'return value is correct length'); const pointId = drawInstance[0]; const lineId = drawInstance[1]; const polygonId = drawInstance[2]; - assert.equal(Draw.get(pointId).geometry.type, 'Point', - 'point id returned'); - assert.equal(Draw.get(lineId).geometry.type, 'LineString', - 'line id returned'); - assert.equal(Draw.get(polygonId).geometry.type, 'Polygon', - 'polygon id returned'); - assert.equal(Draw.getAll().features.length, 3, - 'all features loaded'); + assert.equal(Draw.get(pointId).geometry.type, 'Point', 'point id returned'); + assert.equal( + Draw.get(lineId).geometry.type, + 'LineString', + 'line id returned' + ); + assert.equal( + Draw.get(polygonId).geometry.type, + 'Polygon', + 'polygon id returned' + ); + assert.equal(Draw.getAll().features.length, 3, 'all features loaded'); // Then set to another addSpy.resetHistory(); @@ -137,22 +134,28 @@ test('Draw.set', () => { features: [polygon] }; const nextDrawInstance = Draw.set(nextCollection); - assert.equal(nextDrawInstance.length, 1, - 'return value is correct length'); + assert.equal(nextDrawInstance.length, 1, 'return value is correct length'); const nextPolygonId = nextDrawInstance[0]; - assert.equal(Draw.get(nextPolygonId).geometry.type, 'Polygon', - 'polygon id returned'); - assert.equal(Draw.getAll().features.length, 1, - 'all features replaced with new ones'); - assert.ok(addSpy.calledWith(nextCollection), - 'Draw.add called with new collection'); - assert.equal(deleteSpy.callCount, 1, - 'Draw.delete called'); - assert.deepEqual(deleteSpy.getCall(0).args[0], [ - pointId, - lineId, - polygonId - ], 'Draw.delete called with old features'); + assert.equal( + Draw.get(nextPolygonId).geometry.type, + 'Polygon', + 'polygon id returned' + ); + assert.equal( + Draw.getAll().features.length, + 1, + 'all features replaced with new ones' + ); + assert.ok( + addSpy.calledWith(nextCollection), + 'Draw.add called with new collection' + ); + assert.equal(deleteSpy.callCount, 1, 'Draw.delete called'); + assert.deepEqual( + deleteSpy.getCall(0).args[0], + [pointId, lineId, polygonId], + 'Draw.delete called with old features' + ); // Then set to another that contains a feature // with an already-used id @@ -166,21 +169,33 @@ test('Draw.set', () => { features: [newLine, overlappingPolygon] }; const overlappingDrawInstance = Draw.set(overlappingCollection); - assert.equal(overlappingDrawInstance.length, 2, - 'return value is correct length'); + assert.equal( + overlappingDrawInstance.length, + 2, + 'return value is correct length' + ); const newLineId = overlappingDrawInstance[0]; const overlappingPolygonId = overlappingDrawInstance[1]; - assert.equal(Draw.get(newLineId).geometry.type, 'LineString', - 'new line id returned'); - assert.equal(Draw.get(overlappingPolygonId).geometry.type, 'Polygon', - 'overlapping polygon id returned'); - assert.equal(overlappingPolygonId, nextPolygonId, - 'overlapping polygon id did not change'); - assert.ok(addSpy.calledWith(overlappingCollection), - 'Draw.add called with overlapping collection'); - assert.equal(deleteSpy.callCount, 0, - 'Draw.delete not called'); - + assert.equal( + Draw.get(newLineId).geometry.type, + 'LineString', + 'new line id returned' + ); + assert.equal( + Draw.get(overlappingPolygonId).geometry.type, + 'Polygon', + 'overlapping polygon id returned' + ); + assert.equal( + overlappingPolygonId, + nextPolygonId, + 'overlapping polygon id did not change' + ); + assert.ok( + addSpy.calledWith(overlappingCollection), + 'Draw.add called with overlapping collection' + ); + assert.equal(deleteSpy.callCount, 0, 'Draw.delete not called'); }); test('Draw.set errors', () => { @@ -202,8 +217,11 @@ test('Draw.add -- point', () => { test('Draw.add -- FeatureCollection', () => { const listOfIds = Draw.add(getGeoJSON('featureCollection')); - assert.equal(listOfIds.length, getGeoJSON('featureCollection').features.length, - 'valid string id returned when adding a featureCollection'); + assert.equal( + listOfIds.length, + getGeoJSON('featureCollection').features.length, + 'valid string id returned when adding a featureCollection' + ); Draw.deleteAll(); }); @@ -255,7 +273,7 @@ test('Draw.add -- existing feature with changed properties', async () => { await afterNextRender(); - point.properties = {'testing': 123}; + point.properties = { testing: 123 }; Draw.add(point); point = Draw.get(id); assert.equal('testing', Object.keys(point.properties)[0]); @@ -272,8 +290,11 @@ test('Draw.get', () => { 'the geometry added is the same returned by Draw.get' ); - assert.equal(Draw.get('foo'), undefined, - 'returned undefined when no feature found'); + assert.equal( + Draw.get('foo'), + undefined, + 'returned undefined when no feature found' + ); Draw.deleteAll(); }); @@ -292,7 +313,11 @@ test('Draw.delete one feature', () => { const id = Draw.add(getGeoJSON('point'))[0]; const drawInstance = Draw.delete(id); assert.equal(drawInstance, Draw, 'returns Draw instance'); - assert.equal(Draw.getAll().features.length, 0, 'can remove a feature by its id'); + assert.equal( + Draw.getAll().features.length, + 0, + 'can remove a feature by its id' + ); }); test('Draw.delete multiple features', () => { @@ -301,9 +326,16 @@ test('Draw.delete multiple features', () => { Draw.add(getGeoJSON('polygon')); const drawInstance = Draw.delete([pointId, lineId]); assert.equal(drawInstance, Draw, 'returns Draw instance'); - assert.equal(Draw.getAll().features.length, 1, 'can remove multiple features by id'); - assert.equal(Draw.getAll().features[0].geometry.type, 'Polygon', - 'the right features were removed'); + assert.equal( + Draw.getAll().features.length, + 1, + 'can remove multiple features by id' + ); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'Polygon', + 'the right features were removed' + ); Draw.deleteAll(); }); @@ -312,14 +344,22 @@ test('Draw.delete a feature that is direct_selected', () => { Draw.changeMode('direct_select', { featureId: id }); Draw.delete([id]); assert.equal(Draw.getAll().features.length, 0, 'removed the feature'); - assert.equal(Draw.getMode(), 'simple_select', 'changed modes to simple_select'); + assert.equal( + Draw.getMode(), + 'simple_select', + 'changed modes to simple_select' + ); }); test('Draw.deleteAll', () => { Draw.add(getGeoJSON('point')); const drawInstance = Draw.deleteAll(); assert.equal(drawInstance, Draw, 'returns Draw instance'); - assert.equal(Draw.getAll().features.length, 0, 'Draw.deleteAll removes all geometries'); + assert.equal( + Draw.getAll().features.length, + 0, + 'Draw.deleteAll removes all geometries' + ); }); test('Draw.deleteAll when in direct_select mode', async () => { @@ -330,10 +370,16 @@ test('Draw.deleteAll when in direct_select mode', async () => { await afterNextRender(); - assert.equal(Draw.getMode(), 'simple_select', - 'switches to simple_select mode'); - assert.equal(Draw.getAll().features.length, 0, - 'removes selected feature along with others'); + assert.equal( + Draw.getMode(), + 'simple_select', + 'switches to simple_select mode' + ); + assert.equal( + Draw.getAll().features.length, + 0, + 'removes selected feature along with others' + ); }); test('Draw.changeMode and Draw.getMode with no pre-existing feature', () => { @@ -341,20 +387,56 @@ test('Draw.changeMode and Draw.getMode with no pre-existing feature', () => { assert.equal(drawInstance, Draw, 'changeMode returns Draw instance'); assert.equal(Draw.getMode(), 'draw_polygon', 'changed to draw_polygon'); assert.equal(Draw.getAll().features.length, 1, 'one feature added'); - assert.equal(Draw.getAll().features[0].geometry.type, 'Polygon', 'and it is a polygon'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates, [[null]], 'and it is empty'); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'Polygon', + 'and it is a polygon' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates, + [[null]], + 'and it is empty' + ); Draw.changeMode('draw_line_string'); - assert.equal(Draw.getMode(), 'draw_line_string', 'changed to draw_line_string'); - assert.equal(Draw.getAll().features.length, 1, 'still only one feature added'); - assert.equal(Draw.getAll().features[0].geometry.type, 'LineString', 'and it is a line'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates, [], 'and it is empty'); + assert.equal( + Draw.getMode(), + 'draw_line_string', + 'changed to draw_line_string' + ); + assert.equal( + Draw.getAll().features.length, + 1, + 'still only one feature added' + ); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'LineString', + 'and it is a line' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates, + [], + 'and it is empty' + ); Draw.changeMode('draw_point'); assert.equal(Draw.getMode(), 'draw_point', 'changed to draw_point'); - assert.equal(Draw.getAll().features.length, 1, 'still only one feature added'); - assert.equal(Draw.getAll().features[0].geometry.type, 'Point', 'and it is a point'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates, [], 'and it is empty'); + assert.equal( + Draw.getAll().features.length, + 1, + 'still only one feature added' + ); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'Point', + 'and it is a point' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates, + [], + 'and it is empty' + ); Draw.changeMode('simple_select'); assert.equal(Draw.getMode(), 'simple_select', 'changed to simple_select'); @@ -363,7 +445,6 @@ test('Draw.changeMode and Draw.getMode with no pre-existing feature', () => { assert.throws(() => { Draw.changeMode('direct_select'); }, 'cannot enter direct_select mode with a featureId'); - }); test('Draw.changeMode to select and de-select pre-existing features', async () => { @@ -371,16 +452,26 @@ test('Draw.changeMode to select and de-select pre-existing features', async () = const [lineId] = Draw.add(getGeoJSON('line')); const [pointId] = Draw.add(getGeoJSON('point')); - const returnA = Draw.changeMode('simple_select', { featureIds: [polygonId, lineId]}); + const returnA = Draw.changeMode('simple_select', { + featureIds: [polygonId, lineId] + }); assert.equal(returnA, Draw, 'returns Draw instance'); assert.equal(Draw.getMode(), 'simple_select', 'changed to simple_select'); - assert.deepEqual(Draw.getSelectedIds(), [polygonId, lineId], - 'polygon and line are selected'); + assert.deepEqual( + Draw.getSelectedIds(), + [polygonId, lineId], + 'polygon and line are selected' + ); - const returnB = Draw.changeMode('simple_select', { featureIds: [polygonId, lineId]}); + const returnB = Draw.changeMode('simple_select', { + featureIds: [polygonId, lineId] + }); assert.equal(returnB, Draw, 'returns Draw instance'); - assert.deepEqual(Draw.getSelectedIds(), [polygonId, lineId], - 'polygon and line are still selected'); + assert.deepEqual( + Draw.getSelectedIds(), + [polygonId, lineId], + 'polygon and line are still selected' + ); const returnC = Draw.changeMode('simple_select', { featureIds: [pointId] }); assert.equal(returnC, Draw, 'returns Draw instance'); @@ -389,112 +480,204 @@ test('Draw.changeMode to select and de-select pre-existing features', async () = assert.ok('a render occurred when selection changed'); - assert.deepEqual(Draw.getSelectedIds(), [pointId], - 'change to simple_select with different featureIds to change selection'); + assert.deepEqual( + Draw.getSelectedIds(), + [pointId], + 'change to simple_select with different featureIds to change selection' + ); const returnD = Draw.changeMode('direct_select', { featureId: polygonId }); assert.equal(returnD, Draw, 'returns Draw instance'); - assert.deepEqual(Draw.getSelectedIds(), [polygonId], - 'change to direct_select changes selection'); + assert.deepEqual( + Draw.getSelectedIds(), + [polygonId], + 'change to direct_select changes selection' + ); const returnE = Draw.changeMode('direct_select', { featureId: polygonId }); assert.equal(returnE, Draw, 'returns Draw instance'); - assert.deepEqual(Draw.getSelectedIds(), [polygonId], - 'changing to direct_select with same selection does nothing'); + assert.deepEqual( + Draw.getSelectedIds(), + [polygonId], + 'changing to direct_select with same selection does nothing' + ); Draw.deleteAll(); }); test('Draw.modes', () => { - assert.equal(Draw.modes.SIMPLE_SELECT, Constants.modes.SIMPLE_SELECT, 'simple_select'); - assert.equal(Draw.modes.DIRECT_SELECT, Constants.modes.DIRECT_SELECT, 'direct_select'); + assert.equal( + Draw.modes.SIMPLE_SELECT, + Constants.modes.SIMPLE_SELECT, + 'simple_select' + ); + assert.equal( + Draw.modes.DIRECT_SELECT, + Constants.modes.DIRECT_SELECT, + 'direct_select' + ); assert.equal(Draw.modes.DRAW_POINT, Constants.modes.DRAW_POINT, 'draw_point'); - assert.equal(Draw.modes.DRAW_LINE_STRING, Constants.modes.DRAW_LINE_STRING, 'draw_line_string'); - assert.equal(Draw.modes.DRAW_POLYGON, Constants.modes.DRAW_POLYGON, 'draw_polygon'); - assert.equal(getPublicMemberKeys(Draw.modes).length, 5, 'no unexpected modes'); + assert.equal( + Draw.modes.DRAW_LINE_STRING, + Constants.modes.DRAW_LINE_STRING, + 'draw_line_string' + ); + assert.equal( + Draw.modes.DRAW_POLYGON, + Constants.modes.DRAW_POLYGON, + 'draw_polygon' + ); + assert.equal( + getPublicMemberKeys(Draw.modes).length, + 5, + 'no unexpected modes' + ); }); test('Draw.combineFeatures -- polygon + polygon = multiploygon', () => { const [polygonId] = Draw.add(getGeoJSON('polygon')); const [polygon2Id] = Draw.add(getGeoJSON('polygon2')); - Draw.changeMode('simple_select', { featureIds: [polygonId, polygon2Id]}); + Draw.changeMode('simple_select', { featureIds: [polygonId, polygon2Id] }); Draw.combineFeatures(); assert.equal(Draw.getAll().features.length, 1, 'can combine two features'); - assert.equal(Draw.getAll().features[0].geometry.type, 'MultiPolygon', 'can combine two polygons into MultiPolygon'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[0], getGeoJSON('polygon').geometry.coordinates, 'first set of coordinates in multipolygon matches with second polygon in selection'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[1], getGeoJSON('polygon2').geometry.coordinates, 'second set of coordinates in multipolygon matches with first polygon in selection'); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'MultiPolygon', + 'can combine two polygons into MultiPolygon' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[0], + getGeoJSON('polygon').geometry.coordinates, + 'first set of coordinates in multipolygon matches with second polygon in selection' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[1], + getGeoJSON('polygon2').geometry.coordinates, + 'second set of coordinates in multipolygon matches with first polygon in selection' + ); Draw.deleteAll(); }); test('Draw.combineFeatures -- point + point = multipoint', () => { const [pointId] = Draw.add(getGeoJSON('point')); const [point2Id] = Draw.add(getGeoJSON('point2')); - Draw.changeMode('simple_select', { featureIds: [pointId, point2Id]}); + Draw.changeMode('simple_select', { featureIds: [pointId, point2Id] }); Draw.combineFeatures(); assert.equal(Draw.getAll().features.length, 1, 'can combine two features'); - assert.equal(Draw.getAll().features[0].geometry.type, 'MultiPoint', 'can combine two points into MultiPoint'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[0], getGeoJSON('point').geometry.coordinates, 'first set of coordinates in multipoint matches with first point in selection'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[1], getGeoJSON('point2').geometry.coordinates, 'second set of coordinates in multipoint matches with second point in selection'); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'MultiPoint', + 'can combine two points into MultiPoint' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[0], + getGeoJSON('point').geometry.coordinates, + 'first set of coordinates in multipoint matches with first point in selection' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[1], + getGeoJSON('point2').geometry.coordinates, + 'second set of coordinates in multipoint matches with second point in selection' + ); Draw.deleteAll(); }); test('Draw.combineFeatures -- linestring + linestring = multilinestring', () => { const [lineId] = Draw.add(getGeoJSON('line')); const [line2Id] = Draw.add(getGeoJSON('line2')); - Draw.changeMode('simple_select', { featureIds: [lineId, line2Id]}); + Draw.changeMode('simple_select', { featureIds: [lineId, line2Id] }); Draw.combineFeatures(); assert.equal(Draw.getAll().features.length, 1, 'can combine two features'); - assert.equal(Draw.getAll().features[0].geometry.type, 'MultiLineString', 'can combine two linestrings into MultiLineString'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[0], getGeoJSON('line').geometry.coordinates, 'first set of coordinates in multilinestring matches with first line in selection'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[1], getGeoJSON('line2').geometry.coordinates, 'second set of coordinates in multilinestring matches with second line selection'); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'MultiLineString', + 'can combine two linestrings into MultiLineString' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[0], + getGeoJSON('line').geometry.coordinates, + 'first set of coordinates in multilinestring matches with first line in selection' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[1], + getGeoJSON('line2').geometry.coordinates, + 'second set of coordinates in multilinestring matches with second line selection' + ); Draw.deleteAll(); }); - test('Draw.combineFeatures -- point + multipoint = multipoint', () => { const [pointId] = Draw.add(getGeoJSON('point')); const [multipointId] = Draw.add(getGeoJSON('multiPoint')); - Draw.changeMode('simple_select', { featureIds: [pointId, multipointId]}); + Draw.changeMode('simple_select', { featureIds: [pointId, multipointId] }); Draw.combineFeatures(); assert.equal(Draw.getAll().features.length, 1, 'can combine two features'); - assert.equal(Draw.getAll().features[0].geometry.type, 'MultiPoint', 'can combine two points into MultiPoint'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[0], getGeoJSON('point').geometry.coordinates, 'first set of coordinates in multipoint matches with first point in selection'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[1], getGeoJSON('multiPoint').geometry.coordinates[0], 'second set of coordinates in multipoint matches with first set of coordinates in multipoint in selection'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates[2], getGeoJSON('multiPoint').geometry.coordinates[1], 'third set of coordinates in multipoint matches with second set of coordinates in multipoint in selection'); + assert.equal( + Draw.getAll().features[0].geometry.type, + 'MultiPoint', + 'can combine two points into MultiPoint' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[0], + getGeoJSON('point').geometry.coordinates, + 'first set of coordinates in multipoint matches with first point in selection' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[1], + getGeoJSON('multiPoint').geometry.coordinates[0], + 'second set of coordinates in multipoint matches with first set of coordinates in multipoint in selection' + ); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates[2], + getGeoJSON('multiPoint').geometry.coordinates[1], + 'third set of coordinates in multipoint matches with second set of coordinates in multipoint in selection' + ); Draw.deleteAll(); }); test('Draw.combineFeatures -- return on non-similar features', () => { const [lineId] = Draw.add(getGeoJSON('line')); const [polygonId] = Draw.add(getGeoJSON('polygon')); - Draw.changeMode('simple_select', { featureIds: [lineId, polygonId]}); + Draw.changeMode('simple_select', { featureIds: [lineId, polygonId] }); Draw.combineFeatures(); - assert.equal(Draw.getAll().features.length, 2, 'should not combine non similar features'); + assert.equal( + Draw.getAll().features.length, + 2, + 'should not combine non similar features' + ); Draw.deleteAll(); }); test('Draw.combineFeatures -- do nothing on non-similar features', () => { const [lineId] = Draw.add(getGeoJSON('line')); const [polygonId] = Draw.add(getGeoJSON('polygon')); - Draw.changeMode('simple_select', { featureIds: [lineId, polygonId]}); + Draw.changeMode('simple_select', { featureIds: [lineId, polygonId] }); Draw.combineFeatures(); - assert.equal(Draw.getAll().features.length, 2, 'should not combine non similar features'); + assert.equal( + Draw.getAll().features.length, + 2, + 'should not combine non similar features' + ); Draw.deleteAll(); }); test('Draw.combineFeatures -- work for multifeature + feature', () => { const [multipolygonId] = Draw.add(getGeoJSON('multiPolygon')); const [polygonId] = Draw.add(getGeoJSON('polygon')); - Draw.changeMode('simple_select', { featureIds: [polygonId, multipolygonId]}); + Draw.changeMode('simple_select', { featureIds: [polygonId, multipolygonId] }); Draw.combineFeatures(); - assert.equal(Draw.getAll().features.length, 1, 'should work for multifeature + feature'); + assert.equal( + Draw.getAll().features.length, + 1, + 'should work for multifeature + feature' + ); Draw.deleteAll(); }); @@ -504,33 +687,41 @@ test('Draw.combineFeatures -- should do nothing if nothing is selected', () => { Draw.changeMode('simple_select', {}); Draw.combineFeatures(); - assert.equal(Draw.getAll().features.length, 2, 'should do nothing if nothing is selected'); + assert.equal( + Draw.getAll().features.length, + 2, + 'should do nothing if nothing is selected' + ); Draw.deleteAll(); }); test('Draw.uncombineFeatures -- multilinestring', () => { const [multiLineStringId] = Draw.add(getGeoJSON('multiLineString')); - Draw.changeMode('simple_select', { featureIds: [multiLineStringId]}); + Draw.changeMode('simple_select', { featureIds: [multiLineStringId] }); Draw.uncombineFeatures(); const featuresInDraw = Draw.getAll().features; assert.equal(featuresInDraw.length, 2, 'can uncombine multiLineString'); - assert.deepEqual(featuresInDraw[0].geometry.coordinates, + assert.deepEqual( + featuresInDraw[0].geometry.coordinates, getGeoJSON('multiLineString').geometry.coordinates[0], - 'first set of coordinates in multilinestring matches with first lineString in selection'); + 'first set of coordinates in multilinestring matches with first lineString in selection' + ); - assert.deepEqual(featuresInDraw[1].geometry.coordinates, + assert.deepEqual( + featuresInDraw[1].geometry.coordinates, getGeoJSON('multiLineString').geometry.coordinates[1], - 'second set of coordinates in multilinestring matches with second lineString in selection'); + 'second set of coordinates in multilinestring matches with second lineString in selection' + ); Draw.deleteAll(); }); test('Draw.uncombineFeatures -- multipolygon', () => { const [multipolygon2Id] = Draw.add(getGeoJSON('multiPolygon2')); - Draw.changeMode('simple_select', { featureIds: [multipolygon2Id]}); + Draw.changeMode('simple_select', { featureIds: [multipolygon2Id] }); Draw.uncombineFeatures(); @@ -538,20 +729,24 @@ test('Draw.uncombineFeatures -- multipolygon', () => { assert.equal(featuresInDraw.length, 2, 'can uncombine multipolygon'); - assert.deepEqual(featuresInDraw[0].geometry.coordinates, + assert.deepEqual( + featuresInDraw[0].geometry.coordinates, getGeoJSON('multiPolygon2').geometry.coordinates[0], - 'first set of coordinates in multipolygon matches with first polygon in selection'); + 'first set of coordinates in multipolygon matches with first polygon in selection' + ); - assert.deepEqual(featuresInDraw[1].geometry.coordinates, + assert.deepEqual( + featuresInDraw[1].geometry.coordinates, getGeoJSON('multiPolygon2').geometry.coordinates[1], - 'second set of coordinates in multipolygon matches with second polygon in selection'); + 'second set of coordinates in multipolygon matches with second polygon in selection' + ); Draw.deleteAll(); }); test('Draw.uncombineFeatures -- multipoint', () => { const [multipointId] = Draw.add(getGeoJSON('multiPoint')); - Draw.changeMode('simple_select', { featureIds: [multipointId]}); + Draw.changeMode('simple_select', { featureIds: [multipointId] }); Draw.uncombineFeatures(); @@ -559,13 +754,17 @@ test('Draw.uncombineFeatures -- multipoint', () => { assert.equal(featuresInDraw.length, 2, 'can uncombine multipoint'); - assert.deepEqual(featuresInDraw[0].geometry.coordinates, + assert.deepEqual( + featuresInDraw[0].geometry.coordinates, getGeoJSON('multiPoint').geometry.coordinates[0], - 'first set of coordinates in multipoint matches with first point in selection'); + 'first set of coordinates in multipoint matches with first point in selection' + ); - assert.deepEqual(featuresInDraw[1].geometry.coordinates, + assert.deepEqual( + featuresInDraw[1].geometry.coordinates, getGeoJSON('multiPoint').geometry.coordinates[1], - 'second set of coordinates in multipoint matches with second point in selection'); + 'second set of coordinates in multipoint matches with second point in selection' + ); Draw.deleteAll(); }); @@ -576,17 +775,25 @@ test('Draw.uncombineFeatures -- should do nothing if nothing is selected', () => Draw.changeMode('simple_select', {}); Draw.uncombineFeatures(); - assert.equal(Draw.getAll().features.length, 2, 'should do nothing if nothing is selected'); + assert.equal( + Draw.getAll().features.length, + 2, + 'should do nothing if nothing is selected' + ); Draw.deleteAll(); }); test('Draw.uncombineFeatures -- should do nothing if nothing if only non multifeature is selected', () => { const [polygonId] = Draw.add(getGeoJSON('polygon')); const [pointId] = Draw.add(getGeoJSON('point')); - Draw.changeMode('simple_select', { featureIds: [polygonId, pointId]}); + Draw.changeMode('simple_select', { featureIds: [polygonId, pointId] }); Draw.uncombineFeatures(); - assert.equal(Draw.getAll().features.length, 2, 'should do nothing if nothing is selected'); + assert.equal( + Draw.getAll().features.length, + 2, + 'should do nothing if nothing is selected' + ); Draw.deleteAll(); }); @@ -595,7 +802,11 @@ test('Draw.setFeatureProperty', () => { const featureId = Draw.getAll().features[0].id; const drawInstance = Draw.setFeatureProperty(featureId, 'price', 200); assert.equal(drawInstance, Draw, 'returns Draw instance'); - assert.equal(Draw.get(featureId).properties.price, 200, 'Draw.setFeatureProperty adds a property'); + assert.equal( + Draw.get(featureId).properties.price, + 200, + 'Draw.setFeatureProperty adds a property' + ); }); test('Cleanup', () => { diff --git a/test/common_selectors.test.js b/test/common_selectors.test.js index d4fd1b27..6816459a 100644 --- a/test/common_selectors.test.js +++ b/test/common_selectors.test.js @@ -6,246 +6,353 @@ import * as commonSelectors from '../src/lib/common_selectors.js'; test('commonSelectors.isOfMetaType', () => { const isFoo = commonSelectors.isOfMetaType('foo'); assert.equal(typeof isFoo, 'function'); - assert.ok(isFoo({ - featureTarget: { - properties: { - meta: 'foo' + assert.ok( + isFoo({ + featureTarget: { + properties: { + meta: 'foo' + } } - } - })); + }) + ); assert.equal(isFoo({}), false); - assert.equal(isFoo({ - featureTarget: { - properties: { - meta: 'bar' + assert.equal( + isFoo({ + featureTarget: { + properties: { + meta: 'bar' + } } - } - }), false); + }), + false + ); }); test('commonSelectors.isShiftMousedown', () => { - assert.ok(commonSelectors.isShiftMousedown({ - originalEvent: { - shiftKey: true, - button: 0 - } - })); - - assert.equal(commonSelectors.isShiftMousedown({ - originalEvent: { - shiftKey: false, - button: 0 - } - }), false); - - assert.equal(commonSelectors.isShiftMousedown({ - originalEvent: { - shiftKey: true, - button: 1 - } - }), false); - - assert.equal(commonSelectors.isShiftMousedown({ - nothing: false - }), false); + assert.ok( + commonSelectors.isShiftMousedown({ + originalEvent: { + shiftKey: true, + button: 0 + } + }) + ); + + assert.equal( + commonSelectors.isShiftMousedown({ + originalEvent: { + shiftKey: false, + button: 0 + } + }), + false + ); + + assert.equal( + commonSelectors.isShiftMousedown({ + originalEvent: { + shiftKey: true, + button: 1 + } + }), + false + ); + + assert.equal( + commonSelectors.isShiftMousedown({ + nothing: false + }), + false + ); }); test('commonSelectors.isActiveFeature', () => { - assert.ok(commonSelectors.isActiveFeature({ - featureTarget: { - properties: { - active: 'true', - meta: 'feature' - } - } - })); - - assert.equal(commonSelectors.isActiveFeature({ - foo: 'bar' - }), false); - - assert.equal(commonSelectors.isActiveFeature({ - featureTarget: { - properties: { - active: 'false', - meta: 'feature' - } - } - }), false); - - assert.equal(commonSelectors.isActiveFeature({ - featureTarget: { - properties: { - active: 'true', - meta: 'something' - } - } - }), false); - - assert.equal(commonSelectors.isActiveFeature({ - featureTarget: { - properties: { - active: true, - meta: 'Feature' - } - } - }), false); - - assert.equal(commonSelectors.isActiveFeature({ - nothing: false - }), false); - - assert.equal(commonSelectors.isActiveFeature({ - featureTarget: {} - }), false); + assert.ok( + commonSelectors.isActiveFeature({ + featureTarget: { + properties: { + active: 'true', + meta: 'feature' + } + } + }) + ); + + assert.equal( + commonSelectors.isActiveFeature({ + foo: 'bar' + }), + false + ); + + assert.equal( + commonSelectors.isActiveFeature({ + featureTarget: { + properties: { + active: 'false', + meta: 'feature' + } + } + }), + false + ); + + assert.equal( + commonSelectors.isActiveFeature({ + featureTarget: { + properties: { + active: 'true', + meta: 'something' + } + } + }), + false + ); + + assert.equal( + commonSelectors.isActiveFeature({ + featureTarget: { + properties: { + active: true, + meta: 'Feature' + } + } + }), + false + ); + + assert.equal( + commonSelectors.isActiveFeature({ + nothing: false + }), + false + ); + + assert.equal( + commonSelectors.isActiveFeature({ + featureTarget: {} + }), + false + ); }); test('commonSelectors.isInactiveFeature', () => { - assert.ok(commonSelectors.isInactiveFeature({ - featureTarget: { - properties: { - active: 'false', - meta: 'feature' - } - } - })); - - assert.equal(commonSelectors.isInactiveFeature({ - foo: 'bar' - }), false); - - assert.equal(commonSelectors.isInactiveFeature({ - featureTarget: { - properties: { - active: 'true', - meta: 'feature' - } - } - }), false); - - assert.equal(commonSelectors.isInactiveFeature({ - featureTarget: { - properties: { - active: 'false', - meta: 'something' - } - } - }), false); - - assert.equal(commonSelectors.isInactiveFeature({ - featureTarget: { - properties: { - active: false, - meta: 'Feature' - } - } - }), false); - - assert.equal(commonSelectors.isInactiveFeature({ - nothing: false - }), false); - - assert.equal(commonSelectors.isInactiveFeature({ - featureTarget: {} - }), false); + assert.ok( + commonSelectors.isInactiveFeature({ + featureTarget: { + properties: { + active: 'false', + meta: 'feature' + } + } + }) + ); + + assert.equal( + commonSelectors.isInactiveFeature({ + foo: 'bar' + }), + false + ); + + assert.equal( + commonSelectors.isInactiveFeature({ + featureTarget: { + properties: { + active: 'true', + meta: 'feature' + } + } + }), + false + ); + + assert.equal( + commonSelectors.isInactiveFeature({ + featureTarget: { + properties: { + active: 'false', + meta: 'something' + } + } + }), + false + ); + + assert.equal( + commonSelectors.isInactiveFeature({ + featureTarget: { + properties: { + active: false, + meta: 'Feature' + } + } + }), + false + ); + + assert.equal( + commonSelectors.isInactiveFeature({ + nothing: false + }), + false + ); + + assert.equal( + commonSelectors.isInactiveFeature({ + featureTarget: {} + }), + false + ); }); test('commonSelectors.noTarget', () => { - assert.ok(commonSelectors.noTarget({ - something: 1 - })); - - assert.ok(commonSelectors.noTarget({ - FeatureTarget: 1 - })); - - assert.equal(commonSelectors.noTarget({ - featureTarget: {} - }), false); - - assert.equal(commonSelectors.noTarget({ - featureTarget: null - }), false); + assert.ok( + commonSelectors.noTarget({ + something: 1 + }) + ); + + assert.ok( + commonSelectors.noTarget({ + FeatureTarget: 1 + }) + ); + + assert.equal( + commonSelectors.noTarget({ + featureTarget: {} + }), + false + ); + + assert.equal( + commonSelectors.noTarget({ + featureTarget: null + }), + false + ); }); test('commonSelectors.isFeature', () => { - assert.ok(commonSelectors.isFeature({ - featureTarget: { - properties: { - meta: 'feature' + assert.ok( + commonSelectors.isFeature({ + featureTarget: { + properties: { + meta: 'feature' + } } - } - })); - - assert.equal(commonSelectors.isFeature({ - feee: 2 - }), false); - - assert.equal(commonSelectors.isFeature({ - featureTarget: { - properties: { - meta: 'nonfeature' + }) + ); + + assert.equal( + commonSelectors.isFeature({ + feee: 2 + }), + false + ); + + assert.equal( + commonSelectors.isFeature({ + featureTarget: { + properties: { + meta: 'nonfeature' + } } - } - }), false); - - assert.equal(commonSelectors.isFeature({ - nothing: false - }), false); - - assert.equal(commonSelectors.isFeature({ - featureTarget: {} - }), false); + }), + false + ); + + assert.equal( + commonSelectors.isFeature({ + nothing: false + }), + false + ); + + assert.equal( + commonSelectors.isFeature({ + featureTarget: {} + }), + false + ); }); test('commonSelectors.isShiftDown', () => { - assert.ok(commonSelectors.isShiftDown({ - originalEvent: { - shiftKey: true - } - })); - - assert.equal(commonSelectors.isShiftDown({ - originalEvent: { - shiftKey: false - } - }), false); - - assert.equal(commonSelectors.isShiftDown({ - originalEvent: {} - }), false); - - assert.equal(commonSelectors.isShiftDown({ - nothing: true - }), false); + assert.ok( + commonSelectors.isShiftDown({ + originalEvent: { + shiftKey: true + } + }) + ); + + assert.equal( + commonSelectors.isShiftDown({ + originalEvent: { + shiftKey: false + } + }), + false + ); + + assert.equal( + commonSelectors.isShiftDown({ + originalEvent: {} + }), + false + ); + + assert.equal( + commonSelectors.isShiftDown({ + nothing: true + }), + false + ); }); test('commonSelectors.isEscapeKey', () => { - assert.ok(commonSelectors.isEscapeKey({ - keyCode: 27 - })); - - assert.equal(commonSelectors.isEscapeKey({ - keyCode: 13 - }), false); - - assert.equal(commonSelectors.isEscapeKey({ - originalEvent: {} - }), false); + assert.ok( + commonSelectors.isEscapeKey({ + keyCode: 27 + }) + ); + + assert.equal( + commonSelectors.isEscapeKey({ + keyCode: 13 + }), + false + ); + + assert.equal( + commonSelectors.isEscapeKey({ + originalEvent: {} + }), + false + ); }); test('commonSelectors.isEnterKey', () => { - assert.ok(commonSelectors.isEnterKey({ - keyCode: 13 - })); - - assert.equal(commonSelectors.isEnterKey({ - keyCode: 27 - }), false); - - assert.equal(commonSelectors.isEnterKey({ - originalEvent: {} - }), false); + assert.ok( + commonSelectors.isEnterKey({ + keyCode: 13 + }) + ); + + assert.equal( + commonSelectors.isEnterKey({ + keyCode: 27 + }), + false + ); + + assert.equal( + commonSelectors.isEnterKey({ + originalEvent: {} + }), + false + ); }); test('commonSelectors.true', () => { diff --git a/test/constrain_feature_movement.test.js b/test/constrain_feature_movement.test.js index 5eba5725..6545d294 100644 --- a/test/constrain_feature_movement.test.js +++ b/test/constrain_feature_movement.test.js @@ -14,7 +14,6 @@ test('constrainFeatureMovement point, no constraint', () => { lat: 13, lng: 0 }); - }); test('constrainFeatureMovement point, requiring northern constraint', () => { @@ -24,11 +23,14 @@ test('constrainFeatureMovement point, requiring northern constraint', () => { lat: 80, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 65, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: 65, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement point, requiring southern constraint', () => { @@ -38,11 +40,14 @@ test('constrainFeatureMovement point, requiring southern constraint', () => { lat: -80, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -65, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: -65, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement point, requiring western wrap', () => { @@ -52,11 +57,14 @@ test('constrainFeatureMovement point, requiring western wrap', () => { lat: 10, lng: -300 }); - assert.deepEqual(constrainedDelta, { - lat: 10, - lng: 60 - }, 'stopped within bounds'); - + assert.deepEqual( + constrainedDelta, + { + lat: 10, + lng: 60 + }, + 'stopped within bounds' + ); }); test('constrainFeatureMovement point, requiring eastern wrap', () => { @@ -66,16 +74,23 @@ test('constrainFeatureMovement point, requiring eastern wrap', () => { lat: 10, lng: 300 }); - assert.deepEqual(constrainedDelta, { - lat: 10, - lng: -60 - }, 'stopped within bounds'); - + assert.deepEqual( + constrainedDelta, + { + lat: 10, + lng: -60 + }, + 'stopped within bounds' + ); }); test('constrainFeatureMovement line, no constraint', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[0, 0], [10, 10], [20, 20]]; + line.geometry.coordinates = [ + [0, 0], + [10, 10], + [20, 20] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: 13, lng: 0 @@ -84,68 +99,95 @@ test('constrainFeatureMovement line, no constraint', () => { lat: 13, lng: 0 }); - }); test('constrainFeatureMovement line, requiring northern inner constraint', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[80, 80], [81, 81]]; + line.geometry.coordinates = [ + [80, 80], + [81, 81] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: 7, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 5, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: 5, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement line, requiring northern outer constraint', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[30, 30], [81, 81]]; + line.geometry.coordinates = [ + [30, 30], + [81, 81] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: 12, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 9, - lng: 0 - }, 'stopped within poles'); - + assert.deepEqual( + constrainedDelta, + { + lat: 9, + lng: 0 + }, + 'stopped within poles' + ); }); test('constrainFeatureMovement line, requiring southern inner constraint', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[-80, -80], [-81, -81]]; + line.geometry.coordinates = [ + [-80, -80], + [-81, -81] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: -7, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -5, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: -5, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement line, requiring southern outer constraint', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[-30, -30], [-81, -81]]; + line.geometry.coordinates = [ + [-30, -30], + [-81, -81] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: -12, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -9, - lng: 0 - }, 'stopped within poles'); - + assert.deepEqual( + constrainedDelta, + { + lat: -9, + lng: 0 + }, + 'stopped within poles' + ); }); test('constrainFeatureMovement line, requiring western wrap', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[0, 0], [10, 10], [20, 20]]; + line.geometry.coordinates = [ + [0, 0], + [10, 10], + [20, 20] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: 0, lng: -280 @@ -154,12 +196,15 @@ test('constrainFeatureMovement line, requiring western wrap', () => { lat: 0, lng: 80 }); - }); test('constrainFeatureMovement line, requiring eastern wrap', () => { const line = getGeoJSON('line'); - line.geometry.coordinates = [[0, 0], [10, 10], [20, 20]]; + line.geometry.coordinates = [ + [0, 0], + [10, 10], + [20, 20] + ]; const constrainedDelta = constrainFeatureMovement([line], { lat: 0, lng: 255 @@ -168,12 +213,18 @@ test('constrainFeatureMovement line, requiring eastern wrap', () => { lat: 0, lng: -105 }); - }); test('constrainFeatureMovement polygon, no constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: 13, lng: 0 @@ -182,68 +233,114 @@ test('constrainFeatureMovement polygon, no constraint', () => { lat: 13, lng: 0 }); - }); test('constrainFeatureMovement polygon, requiring northern inner constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[80, 80], [81, 81], [81, 82], [80, 80]]]; + polygon.geometry.coordinates = [ + [ + [80, 80], + [81, 81], + [81, 82], + [80, 80] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: 7, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 5, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: 5, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement polygon, requiring northern outer constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[30, 30], [30, 40], [81, 81], [30, 30]]]; + polygon.geometry.coordinates = [ + [ + [30, 30], + [30, 40], + [81, 81], + [30, 30] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: 12, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 9, - lng: 0 - }, 'stopped within poles'); - + assert.deepEqual( + constrainedDelta, + { + lat: 9, + lng: 0 + }, + 'stopped within poles' + ); }); test('constrainFeatureMovement polygon, requiring southern inner constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[-80, -80], [-81, -81], [-81, -82], [-80, -80]]]; + polygon.geometry.coordinates = [ + [ + [-80, -80], + [-81, -81], + [-81, -82], + [-80, -80] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: -7, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -5, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: -5, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement polygon, requiring southern outer constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[-30, -30], [-30, -40], [-81, -81], [-30, -30]]]; + polygon.geometry.coordinates = [ + [ + [-30, -30], + [-30, -40], + [-81, -81], + [-30, -30] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: -12, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -9, - lng: 0 - }, 'stopped within poles'); - + assert.deepEqual( + constrainedDelta, + { + lat: -9, + lng: 0 + }, + 'stopped within poles' + ); }); test('constrainFeatureMovement polygon, requiring western wrap', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: 70, lng: -270 @@ -252,12 +349,18 @@ test('constrainFeatureMovement polygon, requiring western wrap', () => { lat: 70, lng: 90 }); - }); test('constrainFeatureMovement polygon, requiring eastern wrap', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const constrainedDelta = constrainFeatureMovement([polygon], { lat: 35, lng: 270 @@ -266,16 +369,25 @@ test('constrainFeatureMovement polygon, requiring eastern wrap', () => { lat: 35, lng: -90 }); - }); test('constrainFeatureMovement many features, no constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: 13, lng: 0 @@ -284,88 +396,149 @@ test('constrainFeatureMovement many features, no constraint', () => { lat: 13, lng: 0 }); - }); test('constrainFeatureMovement many features, requiring northern inner constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[80, 80], [81, 81], [81, 82], [80, 80]]]; + polygon.geometry.coordinates = [ + [ + [80, 80], + [81, 81], + [81, 82], + [80, 80] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: 13, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 5, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: 5, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement many features, requiring northern outer constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: 100, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: 65, - lng: 0 - }, 'stopped within poles'); - + assert.deepEqual( + constrainedDelta, + { + lat: 65, + lng: 0 + }, + 'stopped within poles' + ); }); test('constrainFeatureMovement many features, requiring southern inner constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[-80, -80], [-81, -81], [-81, -82], [-80, -80]]]; + polygon.geometry.coordinates = [ + [ + [-80, -80], + [-81, -81], + [-81, -82], + [-80, -80] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: -10, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -5, - lng: 0 - }, 'stopped within projection'); - + assert.deepEqual( + constrainedDelta, + { + lat: -5, + lng: 0 + }, + 'stopped within projection' + ); }); test('constrainFeatureMovement many features, requiring southern outer constraint', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: -200, lng: 0 }); - assert.deepEqual(constrainedDelta, { - lat: -90, - lng: 0 - }, 'stopped within poles'); - + assert.deepEqual( + constrainedDelta, + { + lat: -90, + lng: 0 + }, + 'stopped within poles' + ); }); test('constrainFeatureMovement many features, requiring western wrap', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: 27, lng: -310 @@ -374,16 +547,25 @@ test('constrainFeatureMovement many features, requiring western wrap', () => { lat: 27, lng: 50 }); - }); test('constrainFeatureMovement many features, requiring eastern wrap', () => { const polygon = getGeoJSON('polygon'); - polygon.geometry.coordinates = [[[0, 0], [10, 10], [20, 20], [0, 0]]]; + polygon.geometry.coordinates = [ + [ + [0, 0], + [10, 10], + [20, 20], + [0, 0] + ] + ]; const point = getGeoJSON('point'); point.geometry.coordinates = [15, 15]; const line = getGeoJSON('line'); - line.geometry.coordinates = [[15, 15], [25, 25]]; + line.geometry.coordinates = [ + [15, 15], + [25, 25] + ]; const constrainedDelta = constrainFeatureMovement([polygon, point, line], { lat: 27, lng: 260 @@ -392,5 +574,4 @@ test('constrainFeatureMovement many features, requiring eastern wrap', () => { lat: 27, lng: -100 }); - }); diff --git a/test/create_supplementary_points.test.js b/test/create_supplementary_points.test.js index b0b9d363..98cc3a38 100644 --- a/test/create_supplementary_points.test.js +++ b/test/create_supplementary_points.test.js @@ -17,21 +17,21 @@ test('createSupplementaryPoints with a point', () => { const result = createSupplementaryPoints(point); - assert.deepEqual(result, [{ - geometry: { - coordinates: [10, 15], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: null, - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }]); - - + assert.deepEqual(result, [ + { + geometry: { + coordinates: [10, 15], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: null, + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ]); }); test('createSupplementaryPoints with a line, no midpoints', () => { @@ -42,51 +42,61 @@ test('createSupplementaryPoints with a line, no midpoints', () => { }, geometry: { type: 'LineString', - coordinates: [[0, 0], [4, 4], [8, 8]] + coordinates: [ + [0, 0], + [4, 4], + [8, 8] + ] } }; const result = createSupplementaryPoints(line); - assert.deepEqual(result, [{ - geometry: { - coordinates: [0, 0], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [8, 8], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }], 'adds vertices'); - - + assert.deepEqual( + result, + [ + { + geometry: { + coordinates: [0, 0], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [8, 8], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ], + 'adds vertices' + ); }); test('createSupplementaryPoints with a polygon, no midpoints', () => { @@ -97,62 +107,77 @@ test('createSupplementaryPoints with a polygon, no midpoints', () => { }, geometry: { type: 'Polygon', - coordinates: [[[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]]] + coordinates: [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ] + ] } }; const result = createSupplementaryPoints(polygon); - assert.deepEqual(result, [{ - geometry: { - coordinates: [1, 1], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2, 2], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [3, 3], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.3', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }], 'adds vertices'); - - + assert.deepEqual( + result, + [ + { + geometry: { + coordinates: [1, 1], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2, 2], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [3, 3], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.3', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ], + 'adds vertices' + ); }); test('createSupplementaryPoints with line, midpoints, selected coordinate', () => { @@ -163,7 +188,11 @@ test('createSupplementaryPoints with line, midpoints, selected coordinate', () = }, geometry: { type: 'LineString', - coordinates: [[0, 0], [4, 4], [8, 8]] + coordinates: [ + [0, 0], + [4, 4], + [8, 8] + ] } }; const map = createMap(); @@ -174,71 +203,79 @@ test('createSupplementaryPoints with line, midpoints, selected coordinate', () = selectedPaths: '1' }); - assert.deepEqual(results, [{ - geometry: { - coordinates: [0, 0], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2, 2], - type: 'Point' - }, - properties: { - coord_path: '1', - lat: 2, - lng: 2, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'true', - coord_path: '1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [6, 6], - type: 'Point' - }, - properties: { - coord_path: '2', - lat: 6, - lng: 6, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [8, 8], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }], 'adds vertices and midpoints'); - - + assert.deepEqual( + results, + [ + { + geometry: { + coordinates: [0, 0], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2, 2], + type: 'Point' + }, + properties: { + coord_path: '1', + lat: 2, + lng: 2, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'true', + coord_path: '1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [6, 6], + type: 'Point' + }, + properties: { + coord_path: '2', + lat: 6, + lng: 6, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [8, 8], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ], + 'adds vertices and midpoints' + ); }); test('createSupplementaryPoints with polygon, midpoints, selection', () => { @@ -249,7 +286,15 @@ test('createSupplementaryPoints with polygon, midpoints, selection', () => { }, geometry: { type: 'Polygon', - coordinates: [[[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]]] + coordinates: [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ] + ] } }; @@ -261,109 +306,120 @@ test('createSupplementaryPoints with polygon, midpoints, selection', () => { selectedPaths: '0.1' }); - assert.deepEqual(results, [{ - geometry: { - coordinates: [1, 1], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [1.5, 1.5], - type: 'Point' - }, - properties: { - coord_path: '0.1', - lat: 1.5, - lng: 1.5, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2, 2], - type: 'Point' - }, - properties: { - active: 'true', - coord_path: '0.1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2.5, 2.5], - type: 'Point' - }, - properties: { - coord_path: '0.2', - lat: 2.5, - lng: 2.5, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [3, 3], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [3.5, 3.5], - type: 'Point' - }, - properties: { - coord_path: '0.3', - lat: 3.5, - lng: 3.5, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.3', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2.5, 2.5], - type: 'Point' - }, - properties: { - coord_path: '0.4', - lat: 2.5, - lng: 2.5, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }], 'adds vertices and midpoints'); - - + assert.deepEqual( + results, + [ + { + geometry: { + coordinates: [1, 1], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [1.5, 1.5], + type: 'Point' + }, + properties: { + coord_path: '0.1', + lat: 1.5, + lng: 1.5, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2, 2], + type: 'Point' + }, + properties: { + active: 'true', + coord_path: '0.1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2.5, 2.5], + type: 'Point' + }, + properties: { + coord_path: '0.2', + lat: 2.5, + lng: 2.5, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [3, 3], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [3.5, 3.5], + type: 'Point' + }, + properties: { + coord_path: '0.3', + lat: 3.5, + lng: 3.5, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.3', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2.5, 2.5], + type: 'Point' + }, + properties: { + coord_path: '0.4', + lat: 2.5, + lng: 2.5, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + } + ], + 'adds vertices and midpoints' + ); }); test('createSupplementaryPoints with MultiLineString, midpoints, selected coordinate', () => { @@ -375,8 +431,16 @@ test('createSupplementaryPoints with MultiLineString, midpoints, selected coordi geometry: { type: 'MultiLineString', coordinates: [ - [[0, 0], [4, 4], [8, 8]], - [[20, 20], [24, 24], [28, 28]] + [ + [0, 0], + [4, 4], + [8, 8] + ], + [ + [20, 20], + [24, 24], + [28, 28] + ] ] } }; @@ -388,133 +452,142 @@ test('createSupplementaryPoints with MultiLineString, midpoints, selected coordi selectedPaths: '1.2' }); - assert.deepEqual(results, [{ - geometry: { - coordinates: [0, 0], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2, 2], - type: 'Point' - }, - properties: { - coord_path: '0.1', - lat: 2, - lng: 2, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [6, 6], - type: 'Point' - }, - properties: { - coord_path: '0.2', - lat: 6, - lng: 6, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [8, 8], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0.2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [20, 20], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '1.0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [22, 22], - type: 'Point' - }, - properties: { - coord_path: '1.1', - lat: 22, - lng: 22, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [24, 24], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '1.1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [26, 26], - type: 'Point' - }, - properties: { - coord_path: '1.2', - lat: 26, - lng: 26, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [28, 28], - type: 'Point' - }, - properties: { - active: 'true', - coord_path: '1.2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }]); - - + assert.deepEqual(results, [ + { + geometry: { + coordinates: [0, 0], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2, 2], + type: 'Point' + }, + properties: { + coord_path: '0.1', + lat: 2, + lng: 2, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [6, 6], + type: 'Point' + }, + properties: { + coord_path: '0.2', + lat: 6, + lng: 6, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [8, 8], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0.2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [20, 20], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '1.0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [22, 22], + type: 'Point' + }, + properties: { + coord_path: '1.1', + lat: 22, + lng: 22, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [24, 24], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '1.1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [26, 26], + type: 'Point' + }, + properties: { + coord_path: '1.2', + lat: 26, + lng: 26, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [28, 28], + type: 'Point' + }, + properties: { + active: 'true', + coord_path: '1.2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ]); }); test('createSupplementaryPoints with a line, not all midpoints rendered because of vertex exceeding projection latitude north limit', () => { @@ -525,7 +598,11 @@ test('createSupplementaryPoints with a line, not all midpoints rendered because }, geometry: { type: 'LineString', - coordinates: [[0, 0], [4, 4], [7, 87]] + coordinates: [ + [0, 0], + [4, 4], + [7, 87] + ] } }; @@ -534,61 +611,67 @@ test('createSupplementaryPoints with a line, not all midpoints rendered because midpoints: true }); - assert.deepEqual(result, [{ - geometry: { - coordinates: [0, 0], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2, 2], - type: 'Point' - }, - properties: { - coord_path: '1', - lat: 2, - lng: 2, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [7, 87], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }], 'adds vertices'); - - + assert.deepEqual( + result, + [ + { + geometry: { + coordinates: [0, 0], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2, 2], + type: 'Point' + }, + properties: { + coord_path: '1', + lat: 2, + lng: 2, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [7, 87], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ], + 'adds vertices' + ); }); - test('createSupplementaryPoints with a line, not all midpoints rendered because of vertex exceeding projection latitude south limit', () => { const line = { type: 'Feature', @@ -597,7 +680,11 @@ test('createSupplementaryPoints with a line, not all midpoints rendered because }, geometry: { type: 'LineString', - coordinates: [[0, 0], [4, 4], [7, -87]] + coordinates: [ + [0, 0], + [4, 4], + [7, -87] + ] } }; @@ -606,56 +693,63 @@ test('createSupplementaryPoints with a line, not all midpoints rendered because midpoints: true }); - assert.deepEqual(result, [{ - geometry: { - coordinates: [0, 0], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '0', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [2, 2], - type: 'Point' - }, - properties: { - coord_path: '1', - lat: 2, - lng: 2, - meta: 'midpoint', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [4, 4], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '1', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }, { - geometry: { - coordinates: [7, -87], - type: 'Point' - }, - properties: { - active: 'false', - coord_path: '2', - meta: 'vertex', - parent: 'foo' - }, - type: 'Feature' - }], 'adds vertices'); - - + assert.deepEqual( + result, + [ + { + geometry: { + coordinates: [0, 0], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '0', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [2, 2], + type: 'Point' + }, + properties: { + coord_path: '1', + lat: 2, + lng: 2, + meta: 'midpoint', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [4, 4], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '1', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + }, + { + geometry: { + coordinates: [7, -87], + type: 'Point' + }, + properties: { + active: 'false', + coord_path: '2', + meta: 'vertex', + parent: 'foo' + }, + type: 'Feature' + } + ], + 'adds vertices' + ); }); diff --git a/test/create_vertex.test.js b/test/create_vertex.test.js index 0e0ae64f..ff5cd2ae 100644 --- a/test/create_vertex.test.js +++ b/test/create_vertex.test.js @@ -30,6 +30,4 @@ test('createVertex', () => { coordinates: [99, 199] } }); - - }); diff --git a/test/direct_select.test.js b/test/direct_select.test.js index 89f8d946..a6185fb2 100644 --- a/test/direct_select.test.js +++ b/test/direct_select.test.js @@ -3,19 +3,19 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import turfCentroid from '@turf/centroid'; import createSyntheticEvent from 'synthetic-dom-events'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import MapboxDraw from '../index'; import click from './utils/mouse_click'; import tap from './utils/touch_tap'; import getGeoJSON from './utils/get_geojson'; import createMap from './utils/create_map'; -import {setupAfterNextRender} from './utils/after_next_render'; +import { setupAfterNextRender } from './utils/after_next_render'; import makeMouseEvent from './utils/make_mouse_event'; import makeTouchEvent from './utils/make_touch_event'; import * as Constants from '../src/constants'; -test('direct_select', async (t) => { +test('direct_select', async t => { const mapContainer = document.createElement('div'); document.body.appendChild(mapContainer); const map = createMap({ container: mapContainer }); @@ -27,13 +27,13 @@ test('direct_select', async (t) => { const afterNextRender = setupAfterNextRender(map); - const cleanUp = async function() { + const cleanUp = async function () { Draw.deleteAll(); map.fire.resetHistory(); await afterNextRender(); }; - const getFireArgs = function() { + const getFireArgs = function () { const args = []; for (let i = 0; i < map.fire.callCount; i++) { args.push(map.fire.getCall(i).args); @@ -42,7 +42,7 @@ test('direct_select', async (t) => { }; t.test('direct_select - init map for tests', () => { - const done = function() { + const done = function () { map.off('load', done); }; @@ -53,246 +53,425 @@ test('direct_select', async (t) => { } }); - await t.test('direct_select - double click should not disable enabled dragPan', async () => { - const ids = Draw.add(getGeoJSON('polygon')); + await t.test( + 'direct_select - double click should not disable enabled dragPan', + async () => { + const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); - await afterNextRender(); - - spy(map.dragPan, 'enable'); - - for (let i = 0; i < 2; i++) { - map.fire('mousedown', makeMouseEvent(35, 25)); await afterNextRender(); - } - - map.fire('mousemove', makeMouseEvent(0, 0)); - assert.equal(map.dragPan.enable.callCount, 1, 'dragPan.enable called'); + spy(map.dragPan, 'enable'); - map.dragPan.enable.restore(); - }); - - - await t.test('direct_select - should fire correct actionable when no vertices selected', async () => { - const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: ids - }); - - await afterNextRender(); + for (let i = 0; i < 2; i++) { + map.fire('mousedown', makeMouseEvent(35, 25)); + await afterNextRender(); + } - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); + map.fire('mousemove', makeMouseEvent(0, 0)); - await afterNextRender(); + assert.equal(map.dragPan.enable.callCount, 1, 'dragPan.enable called'); - const actionableArgs = getFireArgs().filter(arg => arg[0] === 'draw.actionable'); - assert.ok(actionableArgs.length > 0, 'should have fired an actionable event'); - if (actionableArgs.length > 0) { - const actionable = actionableArgs[actionableArgs.length - 1][1]; - assert.equal(actionable.actions.combineFeatures, false, 'should fire correct combine actionable'); - assert.equal(actionable.actions.uncombineFeatures, false, 'should fire correct uncombine actionable'); - assert.equal(actionable.actions.trash, false, 'should fire correct trash actionable'); + map.dragPan.enable.restore(); } + ); - await cleanUp(); - }); - - await t.test('direct_select - should fire correct actionable when a vertex is selected by clicking', async () => { - const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); - const clickAt = getGeoJSON('polygon').geometry.coordinates[0][0]; - await afterNextRender(); + await t.test( + 'direct_select - should fire correct actionable when no vertices selected', + async () => { + const ids = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: ids + }); - click(map, makeMouseEvent(clickAt[0], clickAt[1])); + await afterNextRender(); - await afterNextRender(); - const actionableArgs = getFireArgs().filter(arg => arg[0] === 'draw.actionable'); - assert.ok(actionableArgs.length > 0, 'should have fired an actionable event'); - if (actionableArgs.length > 0) { - const actionable = actionableArgs[actionableArgs.length - 1][1]; - assert.equal(actionable.actions.combineFeatures, false, 'should fire correct combine actionable'); - assert.equal(actionable.actions.uncombineFeatures, false, 'should fire correct uncombine actionable'); - assert.equal(actionable.actions.trash, true, 'should fire correct trash actionable'); - } + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); - await cleanUp(); - }); - - await t.test('direct_select - should fire correct actionable when a vertex is selected by tapping', async () => { - const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); - const tapAt = getGeoJSON('polygon').geometry.coordinates[0][0]; - await afterNextRender(); + await afterNextRender(); - tap(map, makeTouchEvent(tapAt[0], tapAt[1])); - await afterNextRender(); + const actionableArgs = getFireArgs().filter( + arg => arg[0] === 'draw.actionable' + ); + assert.ok( + actionableArgs.length > 0, + 'should have fired an actionable event' + ); + if (actionableArgs.length > 0) { + const actionable = actionableArgs[actionableArgs.length - 1][1]; + assert.equal( + actionable.actions.combineFeatures, + false, + 'should fire correct combine actionable' + ); + assert.equal( + actionable.actions.uncombineFeatures, + false, + 'should fire correct uncombine actionable' + ); + assert.equal( + actionable.actions.trash, + false, + 'should fire correct trash actionable' + ); + } - const actionableArgs = getFireArgs().filter(arg => arg[0] === 'draw.actionable'); - assert.ok(actionableArgs.length > 0, 'should have fired an actionable event'); - if (actionableArgs.length > 0) { - const actionable = actionableArgs[actionableArgs.length - 1][1]; - assert.equal(actionable.actions.combineFeatures, false, 'should fire correct combine actionable'); - assert.equal(actionable.actions.uncombineFeatures, false, 'should fire correct uncombine actionable'); - assert.equal(actionable.actions.trash, true, 'should fire correct trash actionable'); + await cleanUp(); } + ); + + await t.test( + 'direct_select - should fire correct actionable when a vertex is selected by clicking', + async () => { + const ids = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); + const clickAt = getGeoJSON('polygon').geometry.coordinates[0][0]; + await afterNextRender(); - await cleanUp(); - }); + click(map, makeMouseEvent(clickAt[0], clickAt[1])); - await t.test('direct_select - trashing vertices should delete the correct ones', async () => { - const longLine = { - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [10, 0], [20, 0], [30, 0], [40, 0], [50, 0], [60, 0], [70, 0], [80, 0], [80, 10], [70, 10], [60, 10], [50, 10]] + await afterNextRender(); + const actionableArgs = getFireArgs().filter( + arg => arg[0] === 'draw.actionable' + ); + assert.ok( + actionableArgs.length > 0, + 'should have fired an actionable event' + ); + if (actionableArgs.length > 0) { + const actionable = actionableArgs[actionableArgs.length - 1][1]; + assert.equal( + actionable.actions.combineFeatures, + false, + 'should fire correct combine actionable' + ); + assert.equal( + actionable.actions.uncombineFeatures, + false, + 'should fire correct uncombine actionable' + ); + assert.equal( + actionable.actions.trash, + true, + 'should fire correct trash actionable' + ); } - }; - const ids = Draw.add(longLine); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); - await afterNextRender(); - // select multiple nodes at indices 9, 10, 11 - click(map, makeMouseEvent(70, 10, { shiftKey: true })); - click(map, makeMouseEvent(80, 10, { shiftKey: true })); - click(map, makeMouseEvent(60, 10, { shiftKey: true })); - await afterNextRender(); - Draw.trash(); - const afterTrash = Draw.get(ids[0]); - assert.deepEqual(afterTrash.geometry.coordinates, [[0, 0], [10, 0], [20, 0], [30, 0], [40, 0], [50, 0], [60, 0], [70, 0], [80, 0], [50, 10]]); - await cleanUp(); - }); - - await t.test('direct_select - a click on a vertex and than dragging the map shouldn\'t drag the vertex', async () => { - const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); - - const clickAt = getGeoJSON('polygon').geometry.coordinates[0][0]; - await afterNextRender(); - click(map, makeMouseEvent(clickAt[0], clickAt[1])); - await afterNextRender(); - map.fire('mousedown', makeMouseEvent(clickAt[0] + 15, clickAt[1] + 15)); - map.fire('mousemove', makeMouseEvent(clickAt[0] + 30, clickAt[1] + 30, { buttons: 1 })); - map.fire('mouseup', makeMouseEvent(clickAt[0] + 30, clickAt[1] + 30)); - const afterMove = Draw.get(ids[0]); - assert.deepEqual(getGeoJSON('polygon').geometry, afterMove.geometry, 'should be the same after the drag'); - await cleanUp(); - }); + await cleanUp(); + } + ); + + await t.test( + 'direct_select - should fire correct actionable when a vertex is selected by tapping', + async () => { + const ids = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); + const tapAt = getGeoJSON('polygon').geometry.coordinates[0][0]; + await afterNextRender(); - await t.test('direct_select - fire one update when dragging mouse leaves container and button is released outside', async () => { - const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); + tap(map, makeTouchEvent(tapAt[0], tapAt[1])); + await afterNextRender(); - const startPosition = getGeoJSON('polygon').geometry.coordinates[0][1]; - await afterNextRender(); - click(map, makeMouseEvent(startPosition[0], startPosition[1])); - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { buttons: 1 })); - mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30), { buttons: 1 }); - map.fire('mouseup', makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30)); - - const afterMove = Draw.get(ids[0]); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 1, 'draw.update called once'); - assert.equal(afterMove.geometry.coordinates[0][1][0], startPosition[0] + 15, 'point lng moved only the first amount'); - assert.equal(afterMove.geometry.coordinates[0][1][1], startPosition[1] + 15, 'point lat moved only the first amount'); - - await cleanUp(); - }); + const actionableArgs = getFireArgs().filter( + arg => arg[0] === 'draw.actionable' + ); + assert.ok( + actionableArgs.length > 0, + 'should have fired an actionable event' + ); + if (actionableArgs.length > 0) { + const actionable = actionableArgs[actionableArgs.length - 1][1]; + assert.equal( + actionable.actions.combineFeatures, + false, + 'should fire correct combine actionable' + ); + assert.equal( + actionable.actions.uncombineFeatures, + false, + 'should fire correct uncombine actionable' + ); + assert.equal( + actionable.actions.trash, + true, + 'should fire correct trash actionable' + ); + } - await t.test('direct_select - fire two updates when dragging mouse leaves container then returns and button is released inside', async () => { - const ids = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: ids[0] - }); + await cleanUp(); + } + ); + + await t.test( + 'direct_select - trashing vertices should delete the correct ones', + async () => { + const longLine = { + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [10, 0], + [20, 0], + [30, 0], + [40, 0], + [50, 0], + [60, 0], + [70, 0], + [80, 0], + [80, 10], + [70, 10], + [60, 10], + [50, 10] + ] + } + }; + const ids = Draw.add(longLine); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); - const startPosition = getGeoJSON('polygon').geometry.coordinates[0][1]; - await afterNextRender(); - click(map, makeMouseEvent(startPosition[0], startPosition[1])); - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { buttons: 1 })); - mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30, { buttons: 1 })); - map.fire('mouseup', makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30)); - - const afterMove = Draw.get(ids[0]); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 2, 'draw.update called twice'); - assert.equal(afterMove.geometry.coordinates[0][1][0], startPosition[0] + 30, 'point lng moved to the mouseup location'); - assert.equal(afterMove.geometry.coordinates[0][1][1], startPosition[1] + 30, 'point lat moved to the mouseup location'); - - await cleanUp(); - }); + await afterNextRender(); + // select multiple nodes at indices 9, 10, 11 + click(map, makeMouseEvent(70, 10, { shiftKey: true })); + click(map, makeMouseEvent(80, 10, { shiftKey: true })); + click(map, makeMouseEvent(60, 10, { shiftKey: true })); + await afterNextRender(); + Draw.trash(); + const afterTrash = Draw.get(ids[0]); + assert.deepEqual(afterTrash.geometry.coordinates, [ + [0, 0], + [10, 0], + [20, 0], + [30, 0], + [40, 0], + [50, 0], + [60, 0], + [70, 0], + [80, 0], + [50, 10] + ]); + await cleanUp(); + } + ); - await t.test('direct_select - drag feature if no vertices are selected', async () => { - const [polygonId] = Draw.add(getGeoJSON('polygon')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: polygonId - }); + await t.test( + "direct_select - a click on a vertex and than dragging the map shouldn't drag the vertex", + async () => { + const ids = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); - const startPosition = getGeoJSON('polygon').geometry.coordinates[0][1]; - const centroid = turfCentroid(getGeoJSON('polygon')).geometry.coordinates; - await afterNextRender(); - map.fire.resetHistory(); - click(map, makeMouseEvent(centroid[0], centroid[1])); - map.fire('mousedown', makeMouseEvent(centroid[0], centroid[1])); - map.fire('mousemove', makeMouseEvent(centroid[0] + 15, centroid[1] + 15, { buttons: 1 })); - map.fire('mouseup', makeMouseEvent(centroid[0] + 15, centroid[1] + 15)); - - const afterMove = Draw.get(polygonId); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 1, 'draw.update called once'); - assert.equal(afterMove.geometry.coordinates[0][1][0], startPosition[0] + 15, 'point lng moved to the mouseup location'); - assert.equal(afterMove.geometry.coordinates[0][1][1], startPosition[1] + 15, 'point lat moved to the mouseup location'); - - await cleanUp(); - }); + const clickAt = getGeoJSON('polygon').geometry.coordinates[0][0]; + await afterNextRender(); + click(map, makeMouseEvent(clickAt[0], clickAt[1])); + await afterNextRender(); + map.fire('mousedown', makeMouseEvent(clickAt[0] + 15, clickAt[1] + 15)); + map.fire( + 'mousemove', + makeMouseEvent(clickAt[0] + 30, clickAt[1] + 30, { buttons: 1 }) + ); + map.fire('mouseup', makeMouseEvent(clickAt[0] + 30, clickAt[1] + 30)); + const afterMove = Draw.get(ids[0]); + assert.deepEqual( + getGeoJSON('polygon').geometry, + afterMove.geometry, + 'should be the same after the drag' + ); + await cleanUp(); + } + ); - await t.test('direct_select - dragging a selected vertex updates stored coordinates', async () => { - const [lineId] = Draw.add(getGeoJSON('line')); - Draw.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: lineId - }); + await t.test( + 'direct_select - fire one update when dragging mouse leaves container and button is released outside', + async () => { + const ids = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); - assert.equal(Draw.getSelectedPoints().features[0], undefined, 'no initial selection'); + const startPosition = getGeoJSON('polygon').geometry.coordinates[0][1]; + await afterNextRender(); + click(map, makeMouseEvent(startPosition[0], startPosition[1])); + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { + buttons: 1 + }) + ); + mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30), + { buttons: 1 } + ); + map.fire( + 'mouseup', + makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30) + ); + + const afterMove = Draw.get(ids[0]); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 1, 'draw.update called once'); + assert.equal( + afterMove.geometry.coordinates[0][1][0], + startPosition[0] + 15, + 'point lng moved only the first amount' + ); + assert.equal( + afterMove.geometry.coordinates[0][1][1], + startPosition[1] + 15, + 'point lat moved only the first amount' + ); + + await cleanUp(); + } + ); - const startPosition = getGeoJSON('line').geometry.coordinates[0]; - const endPosition = [startPosition[0] + 10, startPosition[1] + 10]; - await afterNextRender(); + await t.test( + 'direct_select - fire two updates when dragging mouse leaves container then returns and button is released inside', + async () => { + const ids = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: ids[0] + }); - map.fire.resetHistory(); - click(map, makeMouseEvent(startPosition[0], startPosition[1])); - assert.deepEqual(Draw.getSelectedPoints().features[0].geometry.coordinates, startPosition, 'click saves selection'); + const startPosition = getGeoJSON('polygon').geometry.coordinates[0][1]; + await afterNextRender(); + click(map, makeMouseEvent(startPosition[0], startPosition[1])); + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { + buttons: 1 + }) + ); + mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30, { + buttons: 1 + }) + ); + map.fire( + 'mouseup', + makeMouseEvent(startPosition[0] + 30, startPosition[1] + 30) + ); + + const afterMove = Draw.get(ids[0]); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 2, 'draw.update called twice'); + assert.equal( + afterMove.geometry.coordinates[0][1][0], + startPosition[0] + 30, + 'point lng moved to the mouseup location' + ); + assert.equal( + afterMove.geometry.coordinates[0][1][1], + startPosition[1] + 30, + 'point lat moved to the mouseup location' + ); + + await cleanUp(); + } + ); + + await t.test( + 'direct_select - drag feature if no vertices are selected', + async () => { + const [polygonId] = Draw.add(getGeoJSON('polygon')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: polygonId + }); + + const startPosition = getGeoJSON('polygon').geometry.coordinates[0][1]; + const centroid = turfCentroid(getGeoJSON('polygon')).geometry.coordinates; + await afterNextRender(); + map.fire.resetHistory(); + click(map, makeMouseEvent(centroid[0], centroid[1])); + map.fire('mousedown', makeMouseEvent(centroid[0], centroid[1])); + map.fire( + 'mousemove', + makeMouseEvent(centroid[0] + 15, centroid[1] + 15, { buttons: 1 }) + ); + map.fire('mouseup', makeMouseEvent(centroid[0] + 15, centroid[1] + 15)); + + const afterMove = Draw.get(polygonId); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 1, 'draw.update called once'); + assert.equal( + afterMove.geometry.coordinates[0][1][0], + startPosition[0] + 15, + 'point lng moved to the mouseup location' + ); + assert.equal( + afterMove.geometry.coordinates[0][1][1], + startPosition[1] + 15, + 'point lat moved to the mouseup location' + ); + + await cleanUp(); + } + ); + + await t.test( + 'direct_select - dragging a selected vertex updates stored coordinates', + async () => { + const [lineId] = Draw.add(getGeoJSON('line')); + Draw.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: lineId + }); + + assert.equal( + Draw.getSelectedPoints().features[0], + undefined, + 'no initial selection' + ); + + const startPosition = getGeoJSON('line').geometry.coordinates[0]; + const endPosition = [startPosition[0] + 10, startPosition[1] + 10]; + await afterNextRender(); - map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - map.fire('mousemove', makeMouseEvent(endPosition[0], endPosition[1], { buttons: 1 })); - map.fire('mouseup', makeMouseEvent(endPosition[0], endPosition[1])); - await afterNextRender(); + map.fire.resetHistory(); + click(map, makeMouseEvent(startPosition[0], startPosition[1])); + assert.deepEqual( + Draw.getSelectedPoints().features[0].geometry.coordinates, + startPosition, + 'click saves selection' + ); + + map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); + map.fire( + 'mousemove', + makeMouseEvent(endPosition[0], endPosition[1], { buttons: 1 }) + ); + map.fire('mouseup', makeMouseEvent(endPosition[0], endPosition[1])); + await afterNextRender(); - assert.deepEqual(Draw.getSelectedPoints().features[0].geometry.coordinates, endPosition, 'selection is accurate after dragging'); - await cleanUp(); - }); + assert.deepEqual( + Draw.getSelectedPoints().features[0].geometry.coordinates, + endPosition, + 'selection is accurate after dragging' + ); + await cleanUp(); + } + ); document.body.removeChild(mapContainer); }); diff --git a/test/draw_line_string.test.js b/test/draw_line_string.test.js index a1023cf9..77fa3111 100644 --- a/test/draw_line_string.test.js +++ b/test/draw_line_string.test.js @@ -11,7 +11,7 @@ import LineString from '../src/feature_types/line_string.js'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; import objectToMode from '../src/modes/object_to_mode.js'; -import {setupAfterNextRender} from './utils/after_next_render.js'; +import { setupAfterNextRender } from './utils/after_next_render.js'; const drawLineStringMode = objectToMode(drawLineStringModeObject); @@ -40,8 +40,11 @@ test('draw_line_string mode initialization', () => { } }); // Strip ids for this comparison - assert.deepEqual(Object.assign({}, context.store.add.getCall(0).args[0], { id: null }), - Object.assign({}, emptyLine, { id: null }), 'with a new line'); + assert.deepEqual( + Object.assign({}, context.store.add.getCall(0).args[0], { id: null }), + Object.assign({}, emptyLine, { id: null }), + 'with a new line' + ); }); test('draw_line_string start', () => { @@ -50,17 +53,34 @@ test('draw_line_string start', () => { const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); - assert.equal(context.store.clearSelected.callCount, 1, 'store.clearSelected called'); - assert.equal(context.ui.queueMapClasses.callCount, 1, 'ui.queueMapClasses called'); - assert.deepEqual(context.ui.queueMapClasses.getCall(0).args, [{ mouse: 'add' }], - 'ui.queueMapClasses received correct arguments'); - assert.equal(context.ui.setActiveButton.callCount, 1, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(0).args, ['line_string'], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.store.clearSelected.callCount, + 1, + 'store.clearSelected called' + ); + assert.equal( + context.ui.queueMapClasses.callCount, + 1, + 'ui.queueMapClasses called' + ); + assert.deepEqual( + context.ui.queueMapClasses.getCall(0).args, + [{ mouse: 'add' }], + 'ui.queueMapClasses received correct arguments' + ); + assert.equal( + context.ui.setActiveButton.callCount, + 1, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(0).args, + ['line_string'], + 'ui.setActiveButton received correct arguments' + ); setTimeout(() => { assert.equal(context.map.doubleClickZoom.disable.callCount, 1); - }, 10); }); @@ -75,12 +95,17 @@ test('draw_line_string stop with valid line', () => { line.isValid = () => true; mode.stop.call(); - assert.equal(context.ui.setActiveButton.callCount, 2, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(1).args, [undefined], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.ui.setActiveButton.callCount, + 2, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(1).args, + [undefined], + 'ui.setActiveButton received correct arguments' + ); assert.equal(context.store.delete.callCount, 0, 'store.delete not called'); - - }); test('draw_line_string stop with invalid line', () => { @@ -94,18 +119,24 @@ test('draw_line_string stop with invalid line', () => { line.isValid = () => false; mode.stop.call(); - assert.equal(context.ui.setActiveButton.callCount, 2, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(1).args, [undefined], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.ui.setActiveButton.callCount, + 2, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(1).args, + [undefined], + 'ui.setActiveButton received correct arguments' + ); assert.equal(context.store.delete.callCount, 1, 'store.delete called'); if (context.store.delete.callCount > 0) { - assert.deepEqual(context.store.delete.getCall(0).args, [ - [line.id], - { silent: true } - ], 'store.delete received correct arguments'); + assert.deepEqual( + context.store.delete.getCall(0).args, + [[line.id], { silent: true }], + 'store.delete received correct arguments' + ); } - - }); test('draw_line_string render active line with 0 coordinates', () => { @@ -129,7 +160,6 @@ test('draw_line_string render active line with 0 coordinates', () => { }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 0, 'does not render'); - }); test('draw_line_string render active line with 1 coordinate', () => { @@ -153,7 +183,6 @@ test('draw_line_string render active line with 1 coordinate', () => { }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 0, 'does not render'); - }); test('draw_line_string render active line with 2 coordinates', () => { @@ -172,24 +201,33 @@ test('draw_line_string render active line with 2 coordinates', () => { }, geometry: { type: 'LineString', - coordinates: [[0, 0], [10, 10]] + coordinates: [ + [0, 0], + [10, 10] + ] } }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 2, 'does render'); - assert.deepEqual(memo[1], { - type: 'Feature', - properties: { - id: line.id, - active: 'true', - meta: 'feature' + assert.deepEqual( + memo[1], + { + type: 'Feature', + properties: { + id: line.id, + active: 'true', + meta: 'feature' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [10, 10] + ] + } }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [10, 10]] - } - }, 'with active: true, meta: feature'); - + 'with active: true, meta: feature' + ); }); test('draw_line_string render inactive feature', () => { @@ -211,21 +249,24 @@ test('draw_line_string render inactive feature', () => { }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 1, 'does render'); - assert.deepEqual(memo[0], { - type: 'Feature', - properties: { - active: 'false', - meta: 'nothing' + assert.deepEqual( + memo[0], + { + type: 'Feature', + properties: { + active: 'false', + meta: 'nothing' + }, + geometry: { + type: 'Point', + coordinates: [0, 0] + } }, - geometry: { - type: 'Point', - coordinates: [0, 0] - } - }, 'unaltered except active: false'); - + 'unaltered except active: false' + ); }); -test('draw_line_string mouse interaction', async (t) => { +test('draw_line_string mouse interaction', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -246,25 +287,54 @@ test('draw_line_string mouse interaction', async (t) => { const line = Draw.getAll().features[0]; assert.equal(line.geometry.type, 'LineString'); - assert.deepEqual(line.geometry.coordinates, [[10, 20], [10, 20]], 'starting coordinate added'); + assert.deepEqual( + line.geometry.coordinates, + [ + [10, 20], + [10, 20] + ], + 'starting coordinate added' + ); }); t.test('move mouse', () => { map.fire('mousemove', makeMouseEvent(15, 23)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[10, 20], [15, 23]], 'last coordinate added'); + assert.deepEqual( + line.geometry.coordinates, + [ + [10, 20], + [15, 23] + ], + 'last coordinate added' + ); }); t.test('move mouse again', () => { map.fire('mousemove', makeMouseEvent(30, 33)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[10, 20], [30, 33]], 'last coordinate replaced'); + assert.deepEqual( + line.geometry.coordinates, + [ + [10, 20], + [30, 33] + ], + 'last coordinate replaced' + ); }); t.test('click to add another vertex', () => { mouseClick(map, makeMouseEvent(35, 35)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[10, 20], [35, 35], [35, 35]], 'last coordinate replaced'); + assert.deepEqual( + line.geometry.coordinates, + [ + [10, 20], + [35, 35], + [35, 35] + ], + 'last coordinate replaced' + ); }); t.test('add more points then click on the last vertex to finish', () => { @@ -273,14 +343,30 @@ test('draw_line_string mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(55, 55)); mouseClick(map, makeMouseEvent(55, 55)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, - [[10, 20], [35, 35], [40, 40], [50, 50], [55, 55]], - 'all coordinates in place'); + assert.deepEqual( + line.geometry.coordinates, + [ + [10, 20], + [35, 35], + [40, 40], + [50, 50], + [55, 55] + ], + 'all coordinates in place' + ); mouseClick(map, makeMouseEvent(40, 40)); - assert.deepEqual(line.geometry.coordinates, - [[10, 20], [35, 35], [40, 40], [50, 50], [55, 55]], - 'since we exited draw_line_string mode, another click does not add a coordinate'); + assert.deepEqual( + line.geometry.coordinates, + [ + [10, 20], + [35, 35], + [40, 40], + [50, 50], + [55, 55] + ], + 'since we exited draw_line_string mode, another click does not add a coordinate' + ); }); await t.test('start a line but trash it before completion', () => { @@ -292,7 +378,12 @@ test('draw_line_string mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(3, 3)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [2, 2], [3, 3], [3, 3]]); + assert.deepEqual(line.geometry.coordinates, [ + [1, 1], + [2, 2], + [3, 3], + [3, 3] + ]); Draw.trash(); assert.equal(Draw.getAll().features.length, 0, 'no feature added'); @@ -310,7 +401,12 @@ test('draw_line_string mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(3, 3)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [2, 2], [3, 3], [3, 3]]); + assert.deepEqual(line.geometry.coordinates, [ + [1, 1], + [2, 2], + [3, 3], + [3, 3] + ]); container.dispatchEvent(escapeEvent); @@ -333,12 +429,25 @@ test('draw_line_string mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(3, 3)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [2, 2], [3, 3], [3, 3]]); + assert.deepEqual(line.geometry.coordinates, [ + [1, 1], + [2, 2], + [3, 3], + [3, 3] + ]); container.dispatchEvent(enterEvent); assert.equal(Draw.getAll().features.length, 1, 'the feature was added'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates, [[1, 1], [2, 2], [3, 3]], 'the line is correct'); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates, + [ + [1, 1], + [2, 2], + [3, 3] + ], + 'the line is correct' + ); mouseClick(map, makeMouseEvent(1, 1)); map.fire('mousemove', makeMouseEvent(16, 16)); @@ -370,59 +479,96 @@ test('draw_line_string mouse interaction', async (t) => { map.fire('mousemove', makeMouseEvent(16, 16)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [16, 16]], 'and has right coordinates'); + assert.deepEqual( + line.geometry.coordinates, + [ + [1, 1], + [16, 16] + ], + 'and has right coordinates' + ); container.dispatchEvent(enterEvent); assert.equal(Draw.getAll().features.length, 0, 'line_string was removed'); }); - t.test('start draw_line_string mode then start a point after one click', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_line_string'); - assert.equal(Draw.getAll().features.length, 1, 'line is added'); - mouseClick(map, makeMouseEvent(1, 1)); - map.fire('mousemove', makeMouseEvent(16, 16)); - - const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [16, 16]], 'and has right coordinates'); - - container.dispatchEvent(startPointEvent); - assert.equal(Draw.get(line.id), undefined, 'line_string was removed'); - }); - - t.test('start draw_line_string mode then start a line_string after one click', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_line_string'); - assert.equal(Draw.getAll().features.length, 1, 'line is added'); - mouseClick(map, makeMouseEvent(1, 1)); - map.fire('mousemove', makeMouseEvent(16, 16)); - - const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [16, 16]], 'and has right coordinates'); - - container.dispatchEvent(startLineStringEvent); - assert.equal(Draw.get(line.id), undefined, 'line_string was removed'); - }); - - t.test('start draw_line_string mode then start a polygon after one click', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_line_string'); - assert.equal(Draw.getAll().features.length, 1, 'line is added'); - mouseClick(map, makeMouseEvent(1, 1)); - map.fire('mousemove', makeMouseEvent(16, 16)); + t.test( + 'start draw_line_string mode then start a point after one click', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_line_string'); + assert.equal(Draw.getAll().features.length, 1, 'line is added'); + mouseClick(map, makeMouseEvent(1, 1)); + map.fire('mousemove', makeMouseEvent(16, 16)); + + const line = Draw.getAll().features[0]; + assert.deepEqual( + line.geometry.coordinates, + [ + [1, 1], + [16, 16] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startPointEvent); + assert.equal(Draw.get(line.id), undefined, 'line_string was removed'); + } + ); - const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[1, 1], [16, 16]], 'and has right coordinates'); + t.test( + 'start draw_line_string mode then start a line_string after one click', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_line_string'); + assert.equal(Draw.getAll().features.length, 1, 'line is added'); + mouseClick(map, makeMouseEvent(1, 1)); + map.fire('mousemove', makeMouseEvent(16, 16)); + + const line = Draw.getAll().features[0]; + assert.deepEqual( + line.geometry.coordinates, + [ + [1, 1], + [16, 16] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startLineStringEvent); + assert.equal(Draw.get(line.id), undefined, 'line_string was removed'); + } + ); - container.dispatchEvent(startPolygonEvent); - assert.equal(Draw.get(line.id), undefined, 'line_string was removed'); - }); + t.test( + 'start draw_line_string mode then start a polygon after one click', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_line_string'); + assert.equal(Draw.getAll().features.length, 1, 'line is added'); + mouseClick(map, makeMouseEvent(1, 1)); + map.fire('mousemove', makeMouseEvent(16, 16)); + + const line = Draw.getAll().features[0]; + assert.deepEqual( + line.geometry.coordinates, + [ + [1, 1], + [16, 16] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startPolygonEvent); + assert.equal(Draw.get(line.id), undefined, 'line_string was removed'); + } + ); t.test('start draw_line_string mode then double click', () => { Draw.deleteAll(); @@ -458,21 +604,28 @@ test('draw_line_string mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(16, 16)); lineString = Draw.get(lineString.id); assert.equal(lineString !== undefined, true, 'line_string is here'); - assert.deepEqual(lineString, { - id: lineString.id, - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [15, 15]] - } - }, 'line_string has the right coordinates'); + assert.deepEqual( + lineString, + { + id: lineString.id, + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [15, 15] + ] + } + }, + 'line_string has the right coordinates' + ); }); document.body.removeChild(container); }); -test('draw_line_string touch interaction', async (t) => { +test('draw_line_string touch interaction', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -492,13 +645,28 @@ test('draw_line_string touch interaction', async (t) => { const line = Draw.getAll().features[0]; assert.equal(line.geometry.type, 'LineString'); - assert.deepEqual(line.geometry.coordinates, [[100, 200], [100, 200]], 'starting coordinate added'); + assert.deepEqual( + line.geometry.coordinates, + [ + [100, 200], + [100, 200] + ], + 'starting coordinate added' + ); }); await t.test('tap to add another vertex', () => { touchTap(map, makeTouchEvent(200, 400)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[100, 200], [200, 400], [200, 400]], 'last coordinate replaced'); + assert.deepEqual( + line.geometry.coordinates, + [ + [100, 200], + [200, 400], + [200, 400] + ], + 'last coordinate replaced' + ); }); t.test('add more points then tap on the last vertex to finish', () => { @@ -507,14 +675,30 @@ test('draw_line_string touch interaction', async (t) => { touchTap(map, makeTouchEvent(200, 500)); touchTap(map, makeTouchEvent(200, 500)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, - [[100, 200], [200, 400], [400, 500], [300, 500], [200, 500]], - 'all coordinates in place'); + assert.deepEqual( + line.geometry.coordinates, + [ + [100, 200], + [200, 400], + [400, 500], + [300, 500], + [200, 500] + ], + 'all coordinates in place' + ); touchTap(map, makeTouchEvent(700, 700)); - assert.deepEqual(line.geometry.coordinates, - [[100, 200], [200, 400], [400, 500], [300, 500], [200, 500]], - 'since we exited draw_line_string mode, another tap does not add a coordinate'); + assert.deepEqual( + line.geometry.coordinates, + [ + [100, 200], + [200, 400], + [400, 500], + [300, 500], + [200, 500] + ], + 'since we exited draw_line_string mode, another tap does not add a coordinate' + ); }); await t.test('start a line but trash it before completion', () => { @@ -526,7 +710,12 @@ test('draw_line_string touch interaction', async (t) => { touchTap(map, makeTouchEvent(300, 300)); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[100, 100], [200, 200], [300, 300], [300, 300]]); + assert.deepEqual(line.geometry.coordinates, [ + [100, 100], + [200, 200], + [300, 300], + [300, 300] + ]); Draw.trash(); assert.equal(Draw.getAll().features.length, 0, 'no feature added'); @@ -544,7 +733,11 @@ test('draw_line_string continue LineString', () => { const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); - const coordinates = [[0, 0], [5, 5], [10, 10]]; + const coordinates = [ + [0, 0], + [5, 5], + [10, 10] + ]; const geojson = { type: 'Feature', id: 1, @@ -567,42 +760,70 @@ test('draw_line_string continue LineString', () => { 'no "from" prop' ); assert.throws( - () => drawLineStringMode(context, { featureId: 1, from: '[0, 0]' }).start.call(lifecycleContext), + () => + drawLineStringMode(context, { featureId: 1, from: '[0, 0]' }).start.call( + lifecycleContext + ), /from.*property/, 'incorrect from prop' ); assert.throws( - () => drawLineStringMode(context, { featureId: 1, from: [-1, -1] }).start.call(lifecycleContext), + () => + drawLineStringMode(context, { featureId: 1, from: [-1, -1] }).start.call( + lifecycleContext + ), /start or the end/, 'not on line' ); assert.throws( - () => drawLineStringMode(context, { featureId: 1, from: [5, 5] }).start.call(lifecycleContext), + () => + drawLineStringMode(context, { featureId: 1, from: [5, 5] }).start.call( + lifecycleContext + ), /start or the end/, 'not at line endpoint' ); - drawLineStringMode(context, { featureId: 1, from: [0, 0] }).start.call(lifecycleContext); + drawLineStringMode(context, { featureId: 1, from: [0, 0] }).start.call( + lifecycleContext + ); let testLine = context.store.get(context.store.getAllIds()[0]); assert.equal(testLine.id, 1, 'initialized with correct line'); - assert.deepEqual(testLine.coordinates, [[0, 0], ...coordinates], - 'added one coordinate at the start endpoint'); + assert.deepEqual( + testLine.coordinates, + [[0, 0], ...coordinates], + 'added one coordinate at the start endpoint' + ); - drawLineStringMode(context, { featureId: 1, from: [10, 10] }).start.call(lifecycleContext); + drawLineStringMode(context, { featureId: 1, from: [10, 10] }).start.call( + lifecycleContext + ); testLine = context.store.get(context.store.getAllIds()[0]); - assert.deepEqual(testLine.coordinates, [[0, 0], ...coordinates, [10, 10]], - 'added one coordinate at the end endpoint'); + assert.deepEqual( + testLine.coordinates, + [[0, 0], ...coordinates, [10, 10]], + 'added one coordinate at the end endpoint' + ); assert.doesNotThrow( - () => drawLineStringMode(context, { featureId: 1, from: { type: 'Point', coordinates: [0, 0] } }).start.call(lifecycleContext), + () => + drawLineStringMode(context, { + featureId: 1, + from: { type: 'Point', coordinates: [0, 0] } + }).start.call(lifecycleContext), 'initializes with Point' ); assert.doesNotThrow( - () => drawLineStringMode(context, { - featureId: 1, - from: { type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: {} } - }).start.call(lifecycleContext), + () => + drawLineStringMode(context, { + featureId: 1, + from: { + type: 'Feature', + geometry: { type: 'Point', coordinates: [0, 0] }, + properties: {} + } + }).start.call(lifecycleContext), 'initializes with a Feature' ); }); @@ -617,7 +838,11 @@ test('draw_line_string continue LineString mouseClick', async () => { await map.on('load'); - const coordinates = [[0, 0], [5, 5], [10, 10]]; + const coordinates = [ + [0, 0], + [5, 5], + [10, 10] + ]; const geojson = { type: 'Feature', id: 1, @@ -635,14 +860,22 @@ test('draw_line_string continue LineString mouseClick', async () => { await afterNextRender(); const line = Draw.getAll().features[0]; - assert.deepEqual(line.geometry.coordinates, [[-1, -1], [-1, -1], ...coordinates], 'line continues from the start'); + assert.deepEqual( + line.geometry.coordinates, + [[-1, -1], [-1, -1], ...coordinates], + 'line continues from the start' + ); Draw.changeMode('draw_line_string', { featureId: 1, from: [10, 10] }); mouseClick(map, makeMouseEvent(12, 12)); await afterNextRender(); const line2 = Draw.getAll().features[0]; - assert.deepEqual(line2.geometry.coordinates, [[-1, -1], ...coordinates, [12, 12], [12, 12]], 'line continues from the end'); + assert.deepEqual( + line2.geometry.coordinates, + [[-1, -1], ...coordinates, [12, 12], [12, 12]], + 'line continues from the end' + ); document.body.removeChild(container); }); diff --git a/test/draw_point.test.js b/test/draw_point.test.js index 7b283a34..1c551b04 100644 --- a/test/draw_point.test.js +++ b/test/draw_point.test.js @@ -10,7 +10,7 @@ import drawPointModeObject from '../src/modes/draw_point.js'; import Point from '../src/feature_types/point.js'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; -import {escapeEvent, enterEvent} from './utils/key_events.js'; +import { escapeEvent, enterEvent } from './utils/key_events.js'; import objectToMode from '../src/modes/object_to_mode.js'; const drawPointMode = objectToMode(drawPointModeObject); @@ -31,8 +31,11 @@ test('draw_point mode initialization', () => { } }); // Strip ids for this comparison - assert.deepEqual(Object.assign({}, context.store.add.getCall(0).args[0], { id: null }), - Object.assign({}, emptypoint, { id: null }), 'with a new line'); + assert.deepEqual( + Object.assign({}, context.store.add.getCall(0).args[0], { id: null }), + Object.assign({}, emptypoint, { id: null }), + 'with a new line' + ); }); test('draw_point start', () => { @@ -41,13 +44,31 @@ test('draw_point start', () => { const mode = drawPointMode(context); mode.start.call(lifecycleContext); - assert.equal(context.store.clearSelected.callCount, 1, 'store.clearSelected called'); - assert.equal(context.ui.queueMapClasses.callCount, 1, 'ui.queueMapClasses called'); - assert.deepEqual(context.ui.queueMapClasses.getCall(0).args, [{ mouse: 'add' }], - 'ui.queueMapClasses received correct arguments'); - assert.equal(context.ui.setActiveButton.callCount, 1, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(0).args, ['point'], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.store.clearSelected.callCount, + 1, + 'store.clearSelected called' + ); + assert.equal( + context.ui.queueMapClasses.callCount, + 1, + 'ui.queueMapClasses called' + ); + assert.deepEqual( + context.ui.queueMapClasses.getCall(0).args, + [{ mouse: 'add' }], + 'ui.queueMapClasses received correct arguments' + ); + assert.equal( + context.ui.setActiveButton.callCount, + 1, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(0).args, + ['point'], + 'ui.setActiveButton received correct arguments' + ); assert.equal(lifecycleContext.on.callCount, 12, 'this.on called'); }); @@ -64,9 +85,16 @@ test('draw_point stop with point placed', () => { point.updateCoordinate(10, 20); mode.stop.call(); - assert.equal(context.ui.setActiveButton.callCount, 2, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(1).args, [undefined], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.ui.setActiveButton.callCount, + 2, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(1).args, + [undefined], + 'ui.setActiveButton received correct arguments' + ); assert.equal(context.store.delete.callCount, 0, 'store.delete not called'); }); @@ -81,15 +109,22 @@ test('draw_point stop with no point placed', () => { mode.stop.call(); - - assert.equal(context.ui.setActiveButton.callCount, 2, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(1).args, [undefined], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.ui.setActiveButton.callCount, + 2, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(1).args, + [undefined], + 'ui.setActiveButton received correct arguments' + ); assert.equal(context.store.delete.callCount, 1, 'store.delete called'); - assert.deepEqual(context.store.delete.getCall(0).args, [ - [point.id], - { silent: true } - ], 'store.delete received correct arguments'); + assert.deepEqual( + context.store.delete.getCall(0).args, + [[point.id], { silent: true }], + 'store.delete received correct arguments' + ); }); test('draw_point render the active point', () => { @@ -114,7 +149,6 @@ test('draw_point render the active point', () => { }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 0, 'active point does not render'); - }); test('draw_point render an inactive feature', () => { @@ -131,26 +165,35 @@ test('draw_point render an inactive feature', () => { }, geometry: { type: 'LineString', - coordinates: [[10, 10], [20, 20]] + coordinates: [ + [10, 10], + [20, 20] + ] } }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 1, 'does render'); - assert.deepEqual(memo[0], { - type: 'Feature', - properties: { - active: 'false', - meta: 'nothing' + assert.deepEqual( + memo[0], + { + type: 'Feature', + properties: { + active: 'false', + meta: 'nothing' + }, + geometry: { + type: 'LineString', + coordinates: [ + [10, 10], + [20, 20] + ] + } }, - geometry: { - type: 'LineString', - coordinates: [[10, 10], [20, 20]] - } - }, 'unaltered except active: false'); - + 'unaltered except active: false' + ); }); -test('draw_point mouse interaction', async (t) => { +test('draw_point mouse interaction', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -174,7 +217,11 @@ test('draw_point mouse interaction', async (t) => { assert.deepEqual(point.geometry.coordinates, [10, 20], 'coordinate added'); mouseClick(map, makeMouseEvent(30, 30)); - assert.equal(features.length, 1, 'mode has changed, so another click does not create another point'); + assert.equal( + features.length, + 1, + 'mode has changed, so another click does not create another point' + ); }); await t.test('exist before clicking by hitting Escape', () => { @@ -185,7 +232,11 @@ test('draw_point mouse interaction', async (t) => { assert.equal(Draw.getAll().features.length, 0, 'no feature added'); mouseClick(map, makeMouseEvent(30, 30)); - assert.equal(Draw.getAll().features.length, 0, 'mode has changed, so a click does not create another point'); + assert.equal( + Draw.getAll().features.length, + 0, + 'mode has changed, so a click does not create another point' + ); }); await t.test('exist before clicking by hitting Enter', () => { @@ -196,7 +247,11 @@ test('draw_point mouse interaction', async (t) => { assert.equal(Draw.getAll().features.length, 0, 'no feature added'); mouseClick(map, makeMouseEvent(30, 30)); - assert.equal(Draw.getAll().features.length, 0, 'mode has changed, so a click does not create another point'); + assert.equal( + Draw.getAll().features.length, + 0, + 'mode has changed, so a click does not create another point' + ); }); t.test('exist before clicking with Trash', () => { @@ -207,14 +262,17 @@ test('draw_point mouse interaction', async (t) => { assert.equal(Draw.getAll().features.length, 0, 'no feature added'); mouseClick(map, makeMouseEvent(30, 30)); - assert.equal(Draw.getAll().features.length, 0, 'mode has changed, so a click does not create another point'); + assert.equal( + Draw.getAll().features.length, + 0, + 'mode has changed, so a click does not create another point' + ); }); document.body.removeChild(container); }); - -test('draw_point touch interaction', async (t) => { +test('draw_point touch interaction', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -237,7 +295,11 @@ test('draw_point touch interaction', async (t) => { assert.deepEqual(point.geometry.coordinates, [10, 20], 'coordinate added'); touchTap(map, makeTouchEvent(30, 30)); - assert.equal(features.length, 1, 'mode has changed, so another click does not create another point'); + assert.equal( + features.length, + 1, + 'mode has changed, so another click does not create another point' + ); }); document.body.removeChild(container); diff --git a/test/draw_polygon.test.js b/test/draw_polygon.test.js index f37c2dc3..40f6e2f4 100644 --- a/test/draw_polygon.test.js +++ b/test/draw_polygon.test.js @@ -10,7 +10,7 @@ import drawPolygonModeObject from '../src/modes/draw_polygon.js'; import Polygon from '../src/feature_types/polygon.js'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; -import {setupAfterNextRender} from './utils/after_next_render.js'; +import { setupAfterNextRender } from './utils/after_next_render.js'; import objectToMode from '../src/modes/object_to_mode.js'; const drawPolygonMode = objectToMode(drawPolygonModeObject); @@ -39,8 +39,11 @@ test('draw_polygon mode initialization', () => { } }); // Strip ids for this comparison - assert.deepEqual(Object.assign({}, context.store.add.getCall(0).args[0], { id: null }), - Object.assign({}, emptyPolygon, { id: null }), 'with a new polygon'); + assert.deepEqual( + Object.assign({}, context.store.add.getCall(0).args[0], { id: null }), + Object.assign({}, emptyPolygon, { id: null }), + 'with a new polygon' + ); }); test('draw_polygon start', async () => { @@ -49,13 +52,31 @@ test('draw_polygon start', async () => { const mode = drawPolygonMode(context); mode.start.call(lifecycleContext); - assert.equal(context.store.clearSelected.callCount, 1, 'store.clearSelected called'); - assert.equal(context.ui.queueMapClasses.callCount, 1, 'ui.queueMapClasses called'); - assert.deepEqual(context.ui.queueMapClasses.getCall(0).args, [{ mouse: 'add' }], - 'ui.queueMapClasses received correct arguments'); - assert.equal(context.ui.setActiveButton.callCount, 1, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(0).args, ['polygon'], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.store.clearSelected.callCount, + 1, + 'store.clearSelected called' + ); + assert.equal( + context.ui.queueMapClasses.callCount, + 1, + 'ui.queueMapClasses called' + ); + assert.deepEqual( + context.ui.queueMapClasses.getCall(0).args, + [{ mouse: 'add' }], + 'ui.queueMapClasses received correct arguments' + ); + assert.equal( + context.ui.setActiveButton.callCount, + 1, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(0).args, + ['polygon'], + 'ui.setActiveButton received correct arguments' + ); await new Promise(resolve => setTimeout(resolve, 10)); assert.equal(context.map.doubleClickZoom.disable.callCount, 1); @@ -72,9 +93,16 @@ test('draw_polygon stop with valid polygon', () => { testPolygon.isValid = () => true; mode.stop.call(); - assert.equal(context.ui.setActiveButton.callCount, 2, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(1).args, [undefined], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.ui.setActiveButton.callCount, + 2, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(1).args, + [undefined], + 'ui.setActiveButton received correct arguments' + ); assert.equal(context.store.delete.callCount, 0, 'store.delete not called'); }); @@ -89,14 +117,22 @@ test('draw_polygon stop with invalid polygon', () => { testPolygon.isValid = () => false; mode.stop.call(); - assert.equal(context.ui.setActiveButton.callCount, 2, 'ui.setActiveButton called'); - assert.deepEqual(context.ui.setActiveButton.getCall(1).args, [undefined], - 'ui.setActiveButton received correct arguments'); + assert.equal( + context.ui.setActiveButton.callCount, + 2, + 'ui.setActiveButton called' + ); + assert.deepEqual( + context.ui.setActiveButton.getCall(1).args, + [undefined], + 'ui.setActiveButton received correct arguments' + ); assert.equal(context.store.delete.callCount, 1, 'store.delete called'); - assert.deepEqual(context.store.delete.getCall(0).args, [ - [testPolygon.id], - { silent: true } - ], 'store.delete received correct arguments'); + assert.deepEqual( + context.store.delete.getCall(0).args, + [[testPolygon.id], { silent: true }], + 'store.delete received correct arguments' + ); }); test('draw_polygon render active polygon with no coordinates', () => { @@ -136,7 +172,12 @@ test('draw_polygon render active polygon with 1 coordinate (and closer)', () => }, geometry: { type: 'Polygon', - coordinates: [[[10, 10], [10, 10]]] + coordinates: [ + [ + [10, 10], + [10, 10] + ] + ] } }; mode.render(geojson, x => memo.push(x)); @@ -158,24 +199,36 @@ test('draw_polygon render active polygon with 2 coordinates (and closer)', () => }, geometry: { type: 'Polygon', - coordinates: [[[0, 0], [0, 10], [0, 0]]] + coordinates: [ + [ + [0, 0], + [0, 10], + [0, 0] + ] + ] } }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 2, 'does render'); - assert.deepEqual(memo[1], { - type: 'Feature', - properties: { - id: testPolygon.id, - active: 'true', - meta: 'feature' + assert.deepEqual( + memo[1], + { + type: 'Feature', + properties: { + id: testPolygon.id, + active: 'true', + meta: 'feature' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [0, 10] + ] + } }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [0, 10]] - } - }, 'renders as a LineString with meta: feature, active: true'); - + 'renders as a LineString with meta: feature, active: true' + ); }); test('draw_polygon render active polygon with 3 coordinates (and closer)', () => { @@ -193,50 +246,77 @@ test('draw_polygon render active polygon with 3 coordinates (and closer)', () => }, geometry: { type: 'Polygon', - coordinates: [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]] + coordinates: [ + [ + [0, 0], + [0, 10], + [10, 10], + [10, 0], + [0, 0] + ] + ] } }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 3, 'does render'); - assert.deepEqual(memo[0], { - type: 'Feature', - properties: { - parent: testPolygon.id, - meta: 'vertex', - coord_path: '0.0', - active: 'false' + assert.deepEqual( + memo[0], + { + type: 'Feature', + properties: { + parent: testPolygon.id, + meta: 'vertex', + coord_path: '0.0', + active: 'false' + }, + geometry: { + type: 'Point', + coordinates: [0, 0] + } }, - geometry: { - type: 'Point', - coordinates: [0, 0] - } - }, 'renders the start point point with meta: vertex'); - assert.deepEqual(memo[1], { - type: 'Feature', - properties: { - parent: testPolygon.id, - meta: 'vertex', - coord_path: '0.2', - active: 'false' + 'renders the start point point with meta: vertex' + ); + assert.deepEqual( + memo[1], + { + type: 'Feature', + properties: { + parent: testPolygon.id, + meta: 'vertex', + coord_path: '0.2', + active: 'false' + }, + geometry: { + type: 'Point', + coordinates: [10, 10] + } }, - geometry: { - type: 'Point', - coordinates: [10, 10] - } - }, 'renders end point with meta: vertex'); - assert.deepEqual(memo[2], { - type: 'Feature', - properties: { - id: testPolygon.id, - active: 'true', - meta: 'feature' + 'renders end point with meta: vertex' + ); + assert.deepEqual( + memo[2], + { + type: 'Feature', + properties: { + id: testPolygon.id, + active: 'true', + meta: 'feature' + }, + geometry: { + type: 'Polygon', + coordinates: [ + [ + [0, 0], + [0, 10], + [10, 10], + [10, 0], + [0, 0] + ] + ] + } }, - geometry: { - type: 'Polygon', - coordinates: [[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]]] - } - }, 'renders as a polygon with meta: feature, active: true'); - + 'renders as a polygon with meta: feature, active: true' + ); }); test('draw_polygon render inactive feature', () => { @@ -253,26 +333,35 @@ test('draw_polygon render inactive feature', () => { }, geometry: { type: 'LineString', - coordinates: [[0, 0], [0, 10]] + coordinates: [ + [0, 0], + [0, 10] + ] } }; mode.render(geojson, x => memo.push(x)); assert.equal(memo.length, 1, 'does render'); - assert.deepEqual(memo[0], { - type: 'Feature', - properties: { - active: 'false', - meta: 'meh' + assert.deepEqual( + memo[0], + { + type: 'Feature', + properties: { + active: 'false', + meta: 'meh' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [0, 10] + ] + } }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [0, 10]] - } - }, 'unaltered except active: false'); - + 'unaltered except active: false' + ); }); -test('draw_polygon mouse interaction', async (t) => { +test('draw_polygon mouse interaction', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -293,25 +382,66 @@ test('draw_polygon mouse interaction', async (t) => { const polygon = Draw.getAll().features[0]; assert.equal(polygon.geometry.type, 'Polygon'); - assert.deepEqual(polygon.geometry.coordinates, [[[10, 20], [10, 20], [10, 20]]], 'starting coordinate added'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [10, 20], + [10, 20], + [10, 20] + ] + ], + 'starting coordinate added' + ); }); await t.test('move mouse', () => { map.fire('mousemove', makeMouseEvent(15, 23)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[10, 20], [15, 23], [10, 20]]], 'middle coordinate added'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [10, 20], + [15, 23], + [10, 20] + ] + ], + 'middle coordinate added' + ); }); await t.test('move mouse again', () => { map.fire('mousemove', makeMouseEvent(30, 33)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[10, 20], [30, 33], [10, 20]]], 'middle coordinate replaced'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [10, 20], + [30, 33], + [10, 20] + ] + ], + 'middle coordinate replaced' + ); }); await t.test('click to add another vertex', () => { mouseClick(map, makeMouseEvent(35, 35)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[10, 20], [35, 35], [35, 35], [10, 20]]], 'middle coordinate replaced'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [10, 20], + [35, 35], + [35, 35], + [10, 20] + ] + ], + 'middle coordinate replaced' + ); }); t.test('add more points then click on the last vertex to finish', () => { @@ -320,14 +450,36 @@ test('draw_polygon mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(55, 55)); mouseClick(map, makeMouseEvent(55, 55)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, - [[[10, 20], [35, 35], [40, 40], [50, 50], [55, 55], [10, 20]]], - 'all coordinates in place'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [10, 20], + [35, 35], + [40, 40], + [50, 50], + [55, 55], + [10, 20] + ] + ], + 'all coordinates in place' + ); mouseClick(map, makeMouseEvent(40, 40)); - assert.deepEqual(polygon.geometry.coordinates, - [[[10, 20], [35, 35], [40, 40], [50, 50], [55, 55], [10, 20]]], - 'since we exited draw_polygon mode, another click does not add a coordinate'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [10, 20], + [35, 35], + [40, 40], + [50, 50], + [55, 55], + [10, 20] + ] + ], + 'since we exited draw_polygon mode, another click does not add a coordinate' + ); }); await t.test('start a polygon but trash it before completion', () => { @@ -339,7 +491,15 @@ test('draw_polygon mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(3, 3)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [2, 2], [3, 3], [3, 3], [1, 1]]]); + assert.deepEqual(polygon.geometry.coordinates, [ + [ + [1, 1], + [2, 2], + [3, 3], + [3, 3], + [1, 1] + ] + ]); Draw.trash(); assert.equal(Draw.getAll().features.length, 0, 'no feature added'); @@ -348,24 +508,35 @@ test('draw_polygon mouse interaction', async (t) => { assert.equal(Draw.getAll().features.length, 0, 'no longer drawing'); }); - await t.test('start a polygon but trash it with Escape before completion', () => { - // Start a new polygon - Draw.deleteAll(); - Draw.changeMode('draw_polygon'); - mouseClick(map, makeMouseEvent(1, 1)); - mouseClick(map, makeMouseEvent(2, 2)); - mouseClick(map, makeMouseEvent(3, 3)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [2, 2], [3, 3], [3, 3], [1, 1]]]); - - container.dispatchEvent(escapeEvent); - - assert.equal(Draw.getAll().features.length, 0, 'no feature added'); - - mouseClick(map, makeMouseEvent(1, 1)); - assert.equal(Draw.getAll().features.length, 0, 'no longer drawing'); - }); + await t.test( + 'start a polygon but trash it with Escape before completion', + () => { + // Start a new polygon + Draw.deleteAll(); + Draw.changeMode('draw_polygon'); + mouseClick(map, makeMouseEvent(1, 1)); + mouseClick(map, makeMouseEvent(2, 2)); + mouseClick(map, makeMouseEvent(3, 3)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual(polygon.geometry.coordinates, [ + [ + [1, 1], + [2, 2], + [3, 3], + [3, 3], + [1, 1] + ] + ]); + + container.dispatchEvent(escapeEvent); + + assert.equal(Draw.getAll().features.length, 0, 'no feature added'); + + mouseClick(map, makeMouseEvent(1, 1)); + assert.equal(Draw.getAll().features.length, 0, 'no longer drawing'); + } + ); // ZERO CLICK TESTS @@ -378,12 +549,31 @@ test('draw_polygon mouse interaction', async (t) => { mouseClick(map, makeMouseEvent(3, 3)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [2, 2], [3, 3], [3, 3], [1, 1]]]); + assert.deepEqual(polygon.geometry.coordinates, [ + [ + [1, 1], + [2, 2], + [3, 3], + [3, 3], + [1, 1] + ] + ]); container.dispatchEvent(enterEvent); assert.equal(Draw.getAll().features.length, 1, 'the feature was added'); - assert.deepEqual(Draw.getAll().features[0].geometry.coordinates, [[[1, 1], [2, 2], [3, 3], [1, 1]]], 'the polygon is correct'); + assert.deepEqual( + Draw.getAll().features[0].geometry.coordinates, + [ + [ + [1, 1], + [2, 2], + [3, 3], + [1, 1] + ] + ], + 'the polygon is correct' + ); mouseClick(map, makeMouseEvent(1, 1)); assert.equal(Draw.getAll().features.length, 1, 'no longer drawing'); @@ -414,59 +604,108 @@ test('draw_polygon mouse interaction', async (t) => { map.fire('mousemove', makeMouseEvent(16, 16)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [1, 1]]], 'and has right coordinates'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [1, 1] + ] + ], + 'and has right coordinates' + ); container.dispatchEvent(enterEvent); assert.equal(Draw.getAll().features.length, 0, 'polygon was removed'); }); - await t.test('start draw_polygon mode then start a point after one click', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_polygon'); - assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); - mouseClick(map, makeMouseEvent(1, 1)); - map.fire('mousemove', makeMouseEvent(16, 16)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [1, 1]]], 'and has right coordinates'); - - container.dispatchEvent(startPointEvent); - assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); - }); - - await t.test('start draw_polygon mode then start a line_string after one click', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_polygon'); - assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); - mouseClick(map, makeMouseEvent(1, 1)); - map.fire('mousemove', makeMouseEvent(16, 16)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [1, 1]]], 'and has right coordinates'); - - container.dispatchEvent(startLineStringEvent); - assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); - }); - - await t.test('start draw_polygon mode then start a new polygon after one click', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_polygon'); - assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); - mouseClick(map, makeMouseEvent(1, 1)); - map.fire('mousemove', makeMouseEvent(16, 16)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [1, 1]]], 'and has right coordinates'); - - container.dispatchEvent(startPolygonEvent); - assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); - }); + await t.test( + 'start draw_polygon mode then start a point after one click', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_polygon'); + assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); + mouseClick(map, makeMouseEvent(1, 1)); + map.fire('mousemove', makeMouseEvent(16, 16)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [1, 1] + ] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startPointEvent); + assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); + } + ); + + await t.test( + 'start draw_polygon mode then start a line_string after one click', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_polygon'); + assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); + mouseClick(map, makeMouseEvent(1, 1)); + map.fire('mousemove', makeMouseEvent(16, 16)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [1, 1] + ] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startLineStringEvent); + assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); + } + ); + + await t.test( + 'start draw_polygon mode then start a new polygon after one click', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_polygon'); + assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); + mouseClick(map, makeMouseEvent(1, 1)); + map.fire('mousemove', makeMouseEvent(16, 16)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [1, 1] + ] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startPolygonEvent); + assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); + } + ); await t.test('start draw_polygon mode then doubleclick', () => { Draw.deleteAll(); @@ -493,62 +732,115 @@ test('draw_polygon mouse interaction', async (t) => { map.fire('mousemove', makeMouseEvent(8, 0)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [8, 0], [1, 1]]], 'and has right coordinates'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [8, 0], + [1, 1] + ] + ], + 'and has right coordinates' + ); container.dispatchEvent(enterEvent); assert.equal(Draw.getAll().features.length, 0, 'polygon was removed'); }); - await t.test('start draw_polygon mode then start a point after two clicks', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_polygon'); - assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); - mouseClick(map, makeMouseEvent(1, 1)); - mouseClick(map, makeMouseEvent(16, 16)); - map.fire('mousemove', makeMouseEvent(8, 0)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [8, 0], [1, 1]]], 'and has right coordinates'); - - container.dispatchEvent(startPointEvent); - assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); - }); - - await t.test('start draw_polygon mode then start a line_string after two clicks', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_polygon'); - assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); - mouseClick(map, makeMouseEvent(1, 1)); - mouseClick(map, makeMouseEvent(16, 16)); - map.fire('mousemove', makeMouseEvent(8, 0)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [8, 0], [1, 1]]], 'and has right coordinates'); - - container.dispatchEvent(startLineStringEvent); - assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); - }); - - await t.test('start draw_polygon mode then start a new polygon after two clicks', () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - - Draw.changeMode('draw_polygon'); - assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); - mouseClick(map, makeMouseEvent(1, 1)); - mouseClick(map, makeMouseEvent(16, 16)); - map.fire('mousemove', makeMouseEvent(8, 0)); - - const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[1, 1], [16, 16], [8, 0], [1, 1]]], 'and has right coordinates'); - - container.dispatchEvent(startPolygonEvent); - assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); - }); + await t.test( + 'start draw_polygon mode then start a point after two clicks', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_polygon'); + assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); + mouseClick(map, makeMouseEvent(1, 1)); + mouseClick(map, makeMouseEvent(16, 16)); + map.fire('mousemove', makeMouseEvent(8, 0)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [8, 0], + [1, 1] + ] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startPointEvent); + assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); + } + ); + + await t.test( + 'start draw_polygon mode then start a line_string after two clicks', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_polygon'); + assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); + mouseClick(map, makeMouseEvent(1, 1)); + mouseClick(map, makeMouseEvent(16, 16)); + map.fire('mousemove', makeMouseEvent(8, 0)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [8, 0], + [1, 1] + ] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startLineStringEvent); + assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); + } + ); + + await t.test( + 'start draw_polygon mode then start a new polygon after two clicks', + () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + + Draw.changeMode('draw_polygon'); + assert.equal(Draw.getAll().features.length, 1, 'polygon is added'); + mouseClick(map, makeMouseEvent(1, 1)); + mouseClick(map, makeMouseEvent(16, 16)); + map.fire('mousemove', makeMouseEvent(8, 0)); + + const polygon = Draw.getAll().features[0]; + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [1, 1], + [16, 16], + [8, 0], + [1, 1] + ] + ], + 'and has right coordinates' + ); + + container.dispatchEvent(startPolygonEvent); + assert.equal(Draw.get(polygon.id), undefined, 'polygon was removed'); + } + ); t.test('start draw_polygon mode then doubleclick', () => { Draw.deleteAll(); @@ -565,32 +857,46 @@ test('draw_polygon mouse interaction', async (t) => { // FIVE CLICK TEST - await t.test('end draw_polygon mode by clicking on the start point', async () => { - Draw.deleteAll(); - assert.equal(Draw.getAll().features.length, 0, 'no features yet'); - Draw.changeMode('draw_polygon'); - let polygon = Draw.getAll().features[0]; - assert.equal(polygon !== undefined, true, 'polygon is added'); - mouseClick(map, makeMouseEvent(0, 0)); - mouseClick(map, makeMouseEvent(20, 0)); - mouseClick(map, makeMouseEvent(20, 20)); - mouseClick(map, makeMouseEvent(0, 20)); - - await afterNextRender(); - - map.fire('mousemove', makeMouseEvent(0, 0)); - mouseClick(map, makeMouseEvent(0, 0)); - - polygon = Draw.get(polygon.id); - assert.deepEqual(polygon.geometry.coordinates, [[[0, 0], [20, 0], [20, 20], [0, 20], [0, 0]]], 'and has right coordinates'); - Draw.deleteAll(); - }); + await t.test( + 'end draw_polygon mode by clicking on the start point', + async () => { + Draw.deleteAll(); + assert.equal(Draw.getAll().features.length, 0, 'no features yet'); + Draw.changeMode('draw_polygon'); + let polygon = Draw.getAll().features[0]; + assert.equal(polygon !== undefined, true, 'polygon is added'); + mouseClick(map, makeMouseEvent(0, 0)); + mouseClick(map, makeMouseEvent(20, 0)); + mouseClick(map, makeMouseEvent(20, 20)); + mouseClick(map, makeMouseEvent(0, 20)); + + await afterNextRender(); + + map.fire('mousemove', makeMouseEvent(0, 0)); + mouseClick(map, makeMouseEvent(0, 0)); + + polygon = Draw.get(polygon.id); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [0, 0], + [20, 0], + [20, 20], + [0, 20], + [0, 0] + ] + ], + 'and has right coordinates' + ); + Draw.deleteAll(); + } + ); document.body.removeChild(container); }); - -test('draw_polygon touch interaction', async (t) => { +test('draw_polygon touch interaction', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -610,13 +916,34 @@ test('draw_polygon touch interaction', async (t) => { const polygon = Draw.getAll().features[0]; assert.equal(polygon.geometry.type, 'Polygon'); - assert.deepEqual(polygon.geometry.coordinates, [[[100, 200], [100, 200], [100, 200]]], 'starting coordinate added'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [100, 200], + [100, 200], + [100, 200] + ] + ], + 'starting coordinate added' + ); }); await t.test('tap to add another vertex', () => { touchTap(map, makeTouchEvent(135, 135)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[100, 200], [135, 135], [135, 135], [100, 200]]], 'middle coordinate replaced'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [100, 200], + [135, 135], + [135, 135], + [100, 200] + ] + ], + 'middle coordinate replaced' + ); }); await t.test('add more points then tap on the last vertex to finish', () => { @@ -625,14 +952,36 @@ test('draw_polygon touch interaction', async (t) => { touchTap(map, makeTouchEvent(550, 550)); touchTap(map, makeTouchEvent(550, 550)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, - [[[100, 200], [135, 135], [400, 400], [500, 500], [550, 550], [100, 200]]], - 'all coordinates in place'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [100, 200], + [135, 135], + [400, 400], + [500, 500], + [550, 550], + [100, 200] + ] + ], + 'all coordinates in place' + ); touchTap(map, makeTouchEvent(400, 400)); - assert.deepEqual(polygon.geometry.coordinates, - [[[100, 200], [135, 135], [400, 400], [500, 500], [550, 550], [100, 200]]], - 'since we exited draw_polygon mode, another tap does not add a coordinate'); + assert.deepEqual( + polygon.geometry.coordinates, + [ + [ + [100, 200], + [135, 135], + [400, 400], + [500, 500], + [550, 550], + [100, 200] + ] + ], + 'since we exited draw_polygon mode, another tap does not add a coordinate' + ); }); await t.test('start a polygon but trash it before completion', () => { @@ -644,7 +993,15 @@ test('draw_polygon touch interaction', async (t) => { touchTap(map, makeTouchEvent(300, 300)); const polygon = Draw.getAll().features[0]; - assert.deepEqual(polygon.geometry.coordinates, [[[100, 100], [200, 200], [300, 300], [300, 300], [100, 100]]]); + assert.deepEqual(polygon.geometry.coordinates, [ + [ + [100, 100], + [200, 200], + [300, 300], + [300, 300], + [100, 100] + ] + ]); Draw.trash(); assert.equal(Draw.getAll().features.length, 0, 'no feature added'); diff --git a/test/euclidean_distance.test.js b/test/euclidean_distance.test.js index 461c0d82..4fb7ea86 100644 --- a/test/euclidean_distance.test.js +++ b/test/euclidean_distance.test.js @@ -3,6 +3,12 @@ import assert from 'node:assert/strict'; import euclideanDistance from '../src/lib/euclidean_distance.js'; test('euclideanDistance', () => { - assert.equal(euclideanDistance({ x: 1, y: 1 }, { x: 4, y: 4 }), 4.242640687119285); - assert.equal(euclideanDistance({ x: -10, y: 99.486354 }, { x: 0, y: -0.324736 }), 100.31078549681536); + assert.equal( + euclideanDistance({ x: 1, y: 1 }, { x: 4, y: 4 }), + 4.242640687119285 + ); + assert.equal( + euclideanDistance({ x: -10, y: 99.486354 }, { x: 0, y: -0.324736 }), + 100.31078549681536 + ); }); diff --git a/test/feature.test.js b/test/feature.test.js index 01bbfbb7..b4055783 100644 --- a/test/feature.test.js +++ b/test/feature.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import Feature from '../src/feature_types/feature.js'; import createFeature from './utils/create_feature.js'; import getPublicMemberKeys from './utils/get_public_member_keys.js'; @@ -14,21 +14,61 @@ test('Feature contrusctor and API', () => { // Instance members assert.equal(feature.ctx, ctx, 'feature.ctx'); - assert.equal(feature.coordinates, featureGeoJson.geometry.coordinates, 'feature.coordinates'); - assert.equal(feature.properties, featureGeoJson.properties, 'feature.properties'); + assert.equal( + feature.coordinates, + featureGeoJson.geometry.coordinates, + 'feature.coordinates' + ); + assert.equal( + feature.properties, + featureGeoJson.properties, + 'feature.properties' + ); assert.equal(feature.id, featureGeoJson.id, 'feature.id'); assert.equal(feature.type, featureGeoJson.geometry.type, 'feature.type'); - assert.equal(getPublicMemberKeys(feature).length, 5, 'no unexpected instance members'); + assert.equal( + getPublicMemberKeys(feature).length, + 5, + 'no unexpected instance members' + ); // Prototype members assert.equal(typeof Feature.prototype.changed, 'function', 'feature.changed'); - assert.equal(typeof Feature.prototype.incomingCoords, 'function', 'feature.incomingCoords'); - assert.equal(typeof Feature.prototype.setCoordinates, 'function', 'feature.setCoordinates'); - assert.equal(typeof Feature.prototype.getCoordinates, 'function', 'feature.getCoordinates'); - assert.equal(typeof Feature.prototype.toGeoJSON, 'function', 'feature.toGeoJSON'); - assert.equal(typeof Feature.prototype.internal, 'function', 'feature.internal'); - assert.equal(typeof Feature.prototype.setProperty, 'function', 'feature.setProperty'); - assert.equal(getPublicMemberKeys(Feature.prototype).length, 7, 'no unexpected prototype members'); + assert.equal( + typeof Feature.prototype.incomingCoords, + 'function', + 'feature.incomingCoords' + ); + assert.equal( + typeof Feature.prototype.setCoordinates, + 'function', + 'feature.setCoordinates' + ); + assert.equal( + typeof Feature.prototype.getCoordinates, + 'function', + 'feature.getCoordinates' + ); + assert.equal( + typeof Feature.prototype.toGeoJSON, + 'function', + 'feature.toGeoJSON' + ); + assert.equal( + typeof Feature.prototype.internal, + 'function', + 'feature.internal' + ); + assert.equal( + typeof Feature.prototype.setProperty, + 'function', + 'feature.setProperty' + ); + assert.equal( + getPublicMemberKeys(Feature.prototype).length, + 7, + 'no unexpected prototype members' + ); const simpleFeatureGeoJson = { type: 'Feature', @@ -38,7 +78,11 @@ test('Feature contrusctor and API', () => { } }; const featureWithDefaultsOnly = new Feature(ctx, simpleFeatureGeoJson); - assert.deepEqual(featureWithDefaultsOnly.properties, {}, 'feature.properties defaults to {}'); + assert.deepEqual( + featureWithDefaultsOnly.properties, + {}, + 'feature.properties defaults to {}' + ); assert.ok(featureWithDefaultsOnly.id, 'feature.id is provided'); }); @@ -49,8 +93,16 @@ test('Feature#changed', () => { ctx.store.featureChanged.resetHistory(); feature.changed(); - assert.equal(ctx.store.featureChanged.callCount, 1, 'called function on store'); - assert.deepEqual(ctx.store.featureChanged.getCall(0).args[0], featureGeoJson.id, 'with correct args'); + assert.equal( + ctx.store.featureChanged.callCount, + 1, + 'called function on store' + ); + assert.deepEqual( + ctx.store.featureChanged.getCall(0).args[0], + featureGeoJson.id, + 'with correct args' + ); }); test('Feature#incomingCoords', () => { @@ -63,7 +115,6 @@ test('Feature#incomingCoords', () => { feature.incomingCoords([1, 2]); assert.deepEqual(feature.coordinates, [1, 2]); assert.equal(changedSpy.callCount, 1); - }); test('Feature#setCoordinates, Feature#setCoordinates', () => { @@ -79,7 +130,6 @@ test('Feature#setCoordinates, Feature#setCoordinates', () => { assert.deepEqual(feature.coordinates, [1, 2]); assert.deepEqual(feature.getCoordinates(), [1, 2]); assert.equal(changedSpy.callCount, 1); - }); test('Feature#toGeoJSON', () => { @@ -95,11 +145,10 @@ test('Feature#toGeoJSON', () => { type: feature.type } }); - }); test('Feature#internal - when userProperties is true', () => { - const ctx = createMockCtx({userProperties: true}); + const ctx = createMockCtx({ userProperties: true }); const polygon = createFeature('polygon'); const feature = new Feature(ctx, polygon); assert.deepEqual(feature.internal('foo'), { @@ -118,11 +167,9 @@ test('Feature#internal - when userProperties is true', () => { type: feature.type } }); - - }); test('Feature#internal - when userProperties is false', () => { - const ctx = createMockCtx({userProperties: false}); + const ctx = createMockCtx({ userProperties: false }); const polygon = createFeature('polygon'); const feature = new Feature(ctx, polygon); assert.deepEqual(feature.internal('foo'), { @@ -139,7 +186,6 @@ test('Feature#internal - when userProperties is false', () => { type: feature.type } }); - }); test('Feature#setProperty', () => { @@ -148,5 +194,4 @@ test('Feature#setProperty', () => { const feature = new Feature(ctx, polygon); feature.setProperty('size', 200); assert.equal(feature.properties.size, 200); - }); diff --git a/test/features_at.test.js b/test/features_at.test.js index 1920be88..b7ced10c 100644 --- a/test/features_at.test.js +++ b/test/features_at.test.js @@ -22,52 +22,69 @@ function addLayers(ctx) { ctx.map.addSource(Constants.sources.HOT, { data: { type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: [{ - type: 'Feature', - properties: { - meta: 'feature', - id: 'foo' - }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [1, 1], [2, 2]] - } - }, { - type: 'Feature', - properties: { - meta: 'nothing', - id: 'bar' + features: [ + { + type: 'Feature', + properties: { + meta: 'feature', + id: 'foo' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [1, 1], + [2, 2] + ] + } }, - geometry: { - type: 'Polygon', - coordinates: [[[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]]] - } - }, { - type: 'Feature', - properties: { - meta: 'vertex', - id: 'baz' + { + type: 'Feature', + properties: { + meta: 'nothing', + id: 'bar' + }, + geometry: { + type: 'Polygon', + coordinates: [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ] + ] + } }, - geometry: { - type: 'Point', - coordinates: [10, 10] - } - }, { - type: 'Feature', - properties: { - meta: 'vertex', - id: 'baz' + { + type: 'Feature', + properties: { + meta: 'vertex', + id: 'baz' + }, + geometry: { + type: 'Point', + coordinates: [10, 10] + } }, - geometry: { - type: 'Point', - coordinates: [10, 10] + { + type: 'Feature', + properties: { + meta: 'vertex', + id: 'baz' + }, + geometry: { + type: 'Point', + coordinates: [10, 10] + } } - }] + ] }, type: 'geojson' }); - ctx.options.styles.forEach((style) => { + ctx.options.styles.forEach(style => { ctx.map.addLayer(style); }); } @@ -84,11 +101,11 @@ function createMockContext() { const style = { _layers, getLayer: id => _layers[id], - addLayer: ((layerObject) => { + addLayer: layerObject => { addSource(layerObject.id, layerObject); - }), + }, addSource, - removeSource: (id) => { + removeSource: id => { delete _layers[id]; }, queryRenderedFeatures: (bbox, params) => { @@ -99,16 +116,22 @@ function createMockContext() { const layer = _layers[layerId]; if (!layer) { // this layer is not in the style.layers array - throw new ErrorEvent(new Error(`The layer '${layerId}' does not exist in the map's style and cannot be queried for features.`)); + throw new ErrorEvent( + new Error( + `The layer '${layerId}' does not exist in the map's style and cannot be queried for features.` + ) + ); } includedSources[layer.source] = true; } } - Object.keys(includedSources).filter(source => includedSources[source] != null).forEach((source) => { - if (sources[source] && sources[source].data) { - features.push(...sources[source].data.features); - } - }); + Object.keys(includedSources) + .filter(source => includedSources[source] != null) + .forEach(source => { + if (sources[source] && sources[source].data) { + features.push(...sources[source].data.features); + } + }); return features; } }; @@ -118,9 +141,9 @@ function createMockContext() { styles }, map: { - setStyle: (newStyle) => { + setStyle: newStyle => { Object.keys(_layers).forEach(key => delete _layers[key]); - Object.values(newStyle).forEach((s) => { + Object.values(newStyle).forEach(s => { style.addLayer(s); }); }, @@ -128,16 +151,17 @@ function createMockContext() { sources[id] = source; style.addSource(id, source); }, - removeSource: (id) => { + removeSource: id => { style.removeSource(id); delete sources[id]; }, getLayer: id => style.getLayer(id), - addLayer: (layer) => { + addLayer: layer => { style.addLayer(layer); }, style, - queryRenderedFeatures: (bbox, params) => style.queryRenderedFeatures(bbox, params) + queryRenderedFeatures: (bbox, params) => + style.queryRenderedFeatures(bbox, params) } }; @@ -150,60 +174,92 @@ function createMockContext() { test('featuresAt with click bounding box', () => { const mockContext = createMockContext(); - const result = featuresAt.click(null, [[10, 10], [20, 20]], mockContext); - - assert.deepEqual(result, [{ - type: 'Feature', - properties: { - meta: 'vertex', - id: 'baz' - }, - geometry: { - type: 'Point', - coordinates: [10, 10] - } - }, { - type: 'Feature', - properties: { - meta: 'feature', - id: 'foo' - }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [1, 1], [2, 2]] - } - }], 'sorts, filters based on properties.meta, removes duplicates'); - + const result = featuresAt.click( + null, + [ + [10, 10], + [20, 20] + ], + mockContext + ); + assert.deepEqual( + result, + [ + { + type: 'Feature', + properties: { + meta: 'vertex', + id: 'baz' + }, + geometry: { + type: 'Point', + coordinates: [10, 10] + } + }, + { + type: 'Feature', + properties: { + meta: 'feature', + id: 'foo' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [1, 1], + [2, 2] + ] + } + } + ], + 'sorts, filters based on properties.meta, removes duplicates' + ); }); test('featuresAt with touch bounding box', () => { const mockContext = createMockContext(); - const result = featuresAt.touch(null, [[10, 10], [20, 20]], mockContext); - - assert.deepEqual(result, [{ - type: 'Feature', - properties: { - meta: 'vertex', - id: 'baz' - }, - geometry: { - type: 'Point', - coordinates: [10, 10] - } - }, { - type: 'Feature', - properties: { - meta: 'feature', - id: 'foo' - }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [1, 1], [2, 2]] - } - }], 'sorts, filters based on properties.meta, removes duplicates'); - + const result = featuresAt.touch( + null, + [ + [10, 10], + [20, 20] + ], + mockContext + ); + assert.deepEqual( + result, + [ + { + type: 'Feature', + properties: { + meta: 'vertex', + id: 'baz' + }, + geometry: { + type: 'Point', + coordinates: [10, 10] + } + }, + { + type: 'Feature', + properties: { + meta: 'feature', + id: 'foo' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [1, 1], + [2, 2] + ] + } + } + ], + 'sorts, filters based on properties.meta, removes duplicates' + ); }); test('featuresAt should not include missing style layers', () => { @@ -213,34 +269,61 @@ test('featuresAt should not include missing style layers', () => { mockContext.map.setStyle({}); // featuresAt should return no features if the styles have not finished adding back in - let result = featuresAt.touch(null, [[10, 10], [20, 20]], mockContext); - assert.deepEqual(result, [], 'sorts, filters based on properties.meta, removes duplicates'); + let result = featuresAt.touch( + null, + [ + [10, 10], + [20, 20] + ], + mockContext + ); + assert.deepEqual( + result, + [], + 'sorts, filters based on properties.meta, removes duplicates' + ); // mock adding layers back, similar to data event that fires and mapbox-gl-draw subsequently checks for any missing layers and adds them back in. addLayers(mockContext); - result = featuresAt.touch(null, [[10, 10], [20, 20]], mockContext); - assert.deepEqual(result, [{ - type: 'Feature', - properties: { - meta: 'vertex', - id: 'baz' - }, - geometry: { - type: 'Point', - coordinates: [10, 10] - } - }, { - type: 'Feature', - properties: { - meta: 'feature', - id: 'foo' - }, - geometry: { - type: 'LineString', - coordinates: [[0, 0], [1, 1], [2, 2]] - } - }], 'sorts, filters based on properties.meta, removes duplicates'); - - + result = featuresAt.touch( + null, + [ + [10, 10], + [20, 20] + ], + mockContext + ); + assert.deepEqual( + result, + [ + { + type: 'Feature', + properties: { + meta: 'vertex', + id: 'baz' + }, + geometry: { + type: 'Point', + coordinates: [10, 10] + } + }, + { + type: 'Feature', + properties: { + meta: 'feature', + id: 'foo' + }, + geometry: { + type: 'LineString', + coordinates: [ + [0, 0], + [1, 1], + [2, 2] + ] + } + } + ], + 'sorts, filters based on properties.meta, removes duplicates' + ); }); diff --git a/test/interaction_events.test.js b/test/interaction_events.test.js index 49784682..e2e81e9c 100644 --- a/test/interaction_events.test.js +++ b/test/interaction_events.test.js @@ -9,13 +9,9 @@ import createMap from './utils/create_map'; import { setupAfterNextRender } from './utils/after_next_render.js'; import makeMouseEvent from './utils/make_mouse_event.js'; -import { - backspaceEvent, - enterEvent, - escapeEvent -} from './utils/key_events.js'; +import { backspaceEvent, enterEvent, escapeEvent } from './utils/key_events.js'; -test('ensure user interactions fire right events', async (t) => { +test('ensure user interactions fire right events', async t => { const container = document.createElement('div'); document.body.appendChild(container); const map = createMap({ container }); @@ -40,7 +36,8 @@ test('ensure user interactions fire right events', async (t) => { const drawEvents = []; for (let i = 0; i < fireSpy.callCount; i++) { const eventName = fireSpy.getCall(i).args[0]; - if (typeof eventName !== 'string' || eventName.indexOf('draw.') !== 0) continue; + if (typeof eventName !== 'string' || eventName.indexOf('draw.') !== 0) + continue; // Ignore draw.render events for now if (eventName === 'draw.render') continue; // Ignore draw.actionable events for now @@ -86,10 +83,18 @@ test('ensure user interactions fire right events', async (t) => { } } - const pointButton = controlGroup.getElementsByClassName('mapbox-gl-draw_point')[0]; - const lineButton = controlGroup.getElementsByClassName('mapbox-gl-draw_line')[0]; - const trashButton = controlGroup.getElementsByClassName('mapbox-gl-draw_trash')[0]; - const polygonButton = controlGroup.getElementsByClassName('mapbox-gl-draw_polygon')[0]; + const pointButton = controlGroup.getElementsByClassName( + 'mapbox-gl-draw_point' + )[0]; + const lineButton = controlGroup.getElementsByClassName( + 'mapbox-gl-draw_line' + )[0]; + const trashButton = controlGroup.getElementsByClassName( + 'mapbox-gl-draw_trash' + )[0]; + const polygonButton = controlGroup.getElementsByClassName( + 'mapbox-gl-draw_polygon' + )[0]; // The sequence of these tests matters: each uses state established // in the prior tests. These variables keep track of bits of that state. @@ -102,7 +107,11 @@ test('ensure user interactions fire right events', async (t) => { firedWith('draw.modechange', { mode: 'draw_point' }); - assert.deepEqual(flushDrawEvents(), ['draw.modechange'], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange'], + 'no unexpected draw events' + ); }); const pointA = { @@ -135,11 +144,11 @@ test('ensure user interactions fire right events', async (t) => { points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.create', - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.create', 'draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('deselect that point', async () => { @@ -153,9 +162,11 @@ test('ensure user interactions fire right events', async (t) => { features: [], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('re-select that point', async () => { @@ -169,9 +180,11 @@ test('ensure user interactions fire right events', async (t) => { features: [pointA], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); const pointB = { @@ -186,7 +199,7 @@ test('ensure user interactions fire right events', async (t) => { await t.test('drag that point', async () => { // Now in `simple_select` mode ... map.fire('mousedown', makeMouseEvent(25, 25)); - repeat(10, (i) => { + repeat(10, i => { map.fire('mousemove', makeMouseEvent(25 + i, 25 - i, { buttons: 1 })); }); map.fire('mouseup', makeMouseEvent(35, 10)); @@ -195,9 +208,11 @@ test('ensure user interactions fire right events', async (t) => { action: 'move', features: [pointB] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update'], + 'no unexpected draw events' + ); }); await t.test('delete that point with the Trash button', async () => { @@ -207,9 +222,11 @@ test('ensure user interactions fire right events', async (t) => { firedWith('draw.delete', { features: [pointB] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.delete' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.delete'], + 'no unexpected draw events' + ); }); await t.test('enter draw_line_string mode', () => { @@ -218,9 +235,11 @@ test('ensure user interactions fire right events', async (t) => { firedWith('draw.modechange', { mode: 'draw_line_string' }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange'], + 'no unexpected draw events' + ); }); const lineA = { @@ -228,7 +247,11 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[10, 10], [30, 30], [50, 50]] + coordinates: [ + [10, 10], + [30, 30], + [50, 50] + ] } }; @@ -238,11 +261,11 @@ test('ensure user interactions fire right events', async (t) => { map.fire('mousemove', makeMouseEvent(10, 10)); map.fire('mousemove', makeMouseEvent(20, 20)); click(map, makeMouseEvent(10, 10)); - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(10 + i, 10 + i)); }); click(map, makeMouseEvent(30, 30)); - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(30 + i, 30 + i)); }); click(map, makeMouseEvent(50, 50)); @@ -263,11 +286,11 @@ test('ensure user interactions fire right events', async (t) => { points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.create', - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.create', 'draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('deselect that line', async () => { @@ -278,9 +301,11 @@ test('ensure user interactions fire right events', async (t) => { features: [], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('re-select that line', async () => { @@ -292,9 +317,11 @@ test('ensure user interactions fire right events', async (t) => { features: [lineA], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); const lineB = { @@ -302,7 +329,11 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[20, 0], [40, 20], [60, 40]] + coordinates: [ + [20, 0], + [40, 20], + [60, 40] + ] } }; @@ -311,7 +342,7 @@ test('ensure user interactions fire right events', async (t) => { // Mousedown anywhere on the line, not vertex map.fire('mousedown', makeMouseEvent(20, 20)); // Drag it a little bit - repeat(10, (i) => { + repeat(10, i => { map.fire('mousemove', makeMouseEvent(20 + i, 20 - i, { buttons: 1 })); }); // Release the mouse @@ -324,9 +355,11 @@ test('ensure user interactions fire right events', async (t) => { features: [lineB] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update'], + 'no unexpected draw events' + ); }); await t.test('select a vertex', async () => { @@ -342,20 +375,23 @@ test('ensure user interactions fire right events', async (t) => { firedWith('draw.selectionchange', { features: [lineB], - points: [{ - geometry: { - coordinates: [40, 20], - type: 'Point' - }, - properties: {}, - type: 'Feature' - }] + points: [ + { + geometry: { + coordinates: [40, 20], + type: 'Point' + }, + properties: {}, + type: 'Feature' + } + ] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); const lineC = { @@ -363,7 +399,11 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[20, 0], [62, 42], [60, 40]] + coordinates: [ + [20, 0], + [62, 42], + [60, 40] + ] } }; @@ -372,7 +412,7 @@ test('ensure user interactions fire right events', async (t) => { // Click the vertex again map.fire('mousedown', makeMouseEvent(40, 20)); // Drag it a little bit - repeat(22, (i) => { + repeat(22, i => { map.fire('mousemove', makeMouseEvent(40 + i, 20 + i, { buttons: 1 })); }); // Release the mouse @@ -384,10 +424,11 @@ test('ensure user interactions fire right events', async (t) => { action: 'change_coordinates', features: [lineC] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); const lineD = { @@ -395,7 +436,12 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[20, 0], [41, 21], [62, 42], [60, 40]] + coordinates: [ + [20, 0], + [41, 21], + [62, 42], + [60, 40] + ] } }; @@ -408,9 +454,11 @@ test('ensure user interactions fire right events', async (t) => { action: 'change_coordinates', features: [lineD] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update'], + 'no unexpected draw events' + ); }); const lineE = { @@ -418,7 +466,11 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[20, 0], [62, 42], [60, 40]] + coordinates: [ + [20, 0], + [62, 42], + [60, 40] + ] } }; @@ -432,10 +484,11 @@ test('ensure user interactions fire right events', async (t) => { action: 'change_coordinates', features: [lineE] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); // Leaving that line in place while moving on to @@ -456,10 +509,11 @@ test('ensure user interactions fire right events', async (t) => { points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); const polygonA = { @@ -467,22 +521,30 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[0, 0], [0, 30], [30, 30], [30, 0], [0, 0]]] + coordinates: [ + [ + [0, 0], + [0, 30], + [30, 30], + [30, 0], + [0, 0] + ] + ] } }; await t.test('create a polygon', async () => { // Now in `draw_polygon` mode ... click(map, makeMouseEvent(0, 0)); - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(0, 0 + i)); }); click(map, makeMouseEvent(0, 30)); - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(0 + i, 30)); }); click(map, makeMouseEvent(30, 30)); - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(30, 30 - i)); }); click(map, makeMouseEvent(30, 0)); @@ -503,11 +565,11 @@ test('ensure user interactions fire right events', async (t) => { points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.create', - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.create', 'draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('deselect the polygon', async () => { @@ -520,17 +582,22 @@ test('ensure user interactions fire right events', async (t) => { features: [], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('box-select the line and the polygon', async () => { // Now in `simple_select` mode ... // Mouse down with the shift key map.fire('mousedown', makeMouseEvent(200, 200, { shiftKey: true })); - repeat(20, (i) => { - map.fire('mousemove', makeMouseEvent(200 - (10 * i), 200 - (10 * i), { buttons: 1 })); + repeat(20, i => { + map.fire( + 'mousemove', + makeMouseEvent(200 - 10 * i, 200 - 10 * i, { buttons: 1 }) + ); }); map.fire('mouseup', makeMouseEvent(0, 0)); @@ -540,9 +607,11 @@ test('ensure user interactions fire right events', async (t) => { features: [lineE, polygonA], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); const lineF = { @@ -550,7 +619,11 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[40, -20], [82, 22], [80, 20]] + coordinates: [ + [40, -20], + [82, 22], + [80, 20] + ] } }; @@ -559,7 +632,15 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[20, -20], [20, 10], [50, 10], [50, -20], [20, -20]]] + coordinates: [ + [ + [20, -20], + [20, 10], + [50, 10], + [50, -20], + [20, -20] + ] + ] } }; @@ -568,7 +649,7 @@ test('ensure user interactions fire right events', async (t) => { // Mousedown anywhere on either feature, not a vertex map.fire('mousedown', makeMouseEvent(0, 15)); // Drag it a little bit - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(0 + i, 15 - i, { buttons: 1 })); }); // Release the mouse @@ -581,9 +662,11 @@ test('ensure user interactions fire right events', async (t) => { features: [lineF, polygonB] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update'], + 'no unexpected draw events' + ); }); await t.test('deselect both', async () => { @@ -596,9 +679,11 @@ test('ensure user interactions fire right events', async (t) => { features: [], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('select the polygon', async () => { @@ -611,9 +696,11 @@ test('ensure user interactions fire right events', async (t) => { features: [polygonB], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('select a vertex', async () => { @@ -628,27 +715,34 @@ test('ensure user interactions fire right events', async (t) => { firedWith('draw.selectionchange', { features: [polygonB], - points: [{ - geometry: { - coordinates: [20, -20], - type: 'Point' - }, - properties: {}, - type: 'Feature' - }] + points: [ + { + geometry: { + coordinates: [20, -20], + type: 'Point' + }, + properties: {}, + type: 'Feature' + } + ] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('add another vertex to the selection', async () => { // Now in `simple_select` mode ... click(map, makeMouseEvent(20, 10, { shiftKey: true })); await afterNextRender(); - assert.deepEqual(flushDrawEvents(), ['draw.selectionchange'], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); const polygonC = { @@ -656,7 +750,15 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[0, -20], [0, 10], [50, 10], [50, -20], [0, -20]]] + coordinates: [ + [ + [0, -20], + [0, 10], + [50, 10], + [50, -20], + [0, -20] + ] + ] } }; @@ -665,7 +767,7 @@ test('ensure user interactions fire right events', async (t) => { // Click a vertex again map.fire('mousedown', makeMouseEvent(20, 10)); // Drag it a little bit - repeat(20, (i) => { + repeat(20, i => { map.fire('mousemove', makeMouseEvent(20 - i, 10, { buttons: 1 })); }); // Release the mouse @@ -677,10 +779,11 @@ test('ensure user interactions fire right events', async (t) => { action: 'change_coordinates', features: [polygonC] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update', - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update', 'draw.selectionchange'], + 'no unexpected draw events' + ); }); const polygonD = { @@ -688,7 +791,16 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[0, -20], [0, 10], [25, 10], [50, 10], [50, -20], [0, -20]]] + coordinates: [ + [ + [0, -20], + [0, 10], + [25, 10], + [50, 10], + [50, -20], + [0, -20] + ] + ] } }; @@ -703,9 +815,11 @@ test('ensure user interactions fire right events', async (t) => { action: 'change_coordinates', features: [polygonD] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.update'], + 'no unexpected draw events' + ); }); const polygonE = { @@ -713,27 +827,38 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[0, 10], [50, 10], [50, -20], [0, 10]]] + coordinates: [ + [ + [0, 10], + [50, 10], + [50, -20], + [0, 10] + ] + ] } }; - await t.test('select then delete two vertices with Draw.trash()', async () => { - // Now in `direct_select` mode ... - click(map, makeMouseEvent(0, -20)); - click(map, makeMouseEvent(25, 10, { shiftKey: true })); - Draw.trash(); - - await afterNextRender(); - - firedWith('draw.update', { - action: 'change_coordinates', - features: [polygonE] - }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.update', - 'draw.selectionchange' - ], 'no unexpected draw events'); - }); + await t.test( + 'select then delete two vertices with Draw.trash()', + async () => { + // Now in `direct_select` mode ... + click(map, makeMouseEvent(0, -20)); + click(map, makeMouseEvent(25, 10, { shiftKey: true })); + Draw.trash(); + + await afterNextRender(); + + firedWith('draw.update', { + action: 'change_coordinates', + features: [polygonE] + }); + assert.deepEqual( + flushDrawEvents(), + ['draw.update', 'draw.selectionchange'], + 'no unexpected draw events' + ); + } + ); await t.test('select the polygon', async () => { // Deselect everything @@ -752,9 +877,11 @@ test('ensure user interactions fire right events', async (t) => { features: [polygonE], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); await t.test('add the line to the selection', async () => { @@ -768,9 +895,11 @@ test('ensure user interactions fire right events', async (t) => { features: [polygonE, lineF], points: [] }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.selectionchange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.selectionchange'], + 'no unexpected draw events' + ); }); // Below are tests to ensure that API usage to modify data does not @@ -792,7 +921,10 @@ test('ensure user interactions fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[10, 10], [20, 20]] + coordinates: [ + [10, 10], + [20, 20] + ] } }); Draw.changeMode('draw_point'); @@ -805,29 +937,38 @@ test('ensure user interactions fire right events', async (t) => { assert.deepEqual(flushDrawEvents(), [], 'no unexpected draw events'); }); - await t.test('except when the API function does not directly correspond to the event', async () => { - const line = { - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: [[10, 10], [20, 20], [30, 30]] - } - }; - const lineId = Draw.add(line)[0]; - Draw.changeMode('simple_select', { - featureIds: [lineId] - }); - await afterNextRender(); - Draw.trash(); - await afterNextRender(); - firedWith('draw.delete', { - features: [line] - }); - assert.deepEqual(flushDrawEvents(), [ - 'draw.delete' - ], 'no unexpected draw events'); - }); + await t.test( + 'except when the API function does not directly correspond to the event', + async () => { + const line = { + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [ + [10, 10], + [20, 20], + [30, 30] + ] + } + }; + const lineId = Draw.add(line)[0]; + Draw.changeMode('simple_select', { + featureIds: [lineId] + }); + await afterNextRender(); + Draw.trash(); + await afterNextRender(); + firedWith('draw.delete', { + features: [line] + }); + assert.deepEqual( + flushDrawEvents(), + ['draw.delete'], + 'no unexpected draw events' + ); + } + ); await t.test('start draw_point mode then exit with Enter', async () => { Draw.deleteAll(); @@ -840,9 +981,11 @@ test('ensure user interactions fire right events', async (t) => { mode: 'simple_select' }); assert.equal(Draw.getAll().features.length, 0, 'no feature created'); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange'], + 'no unexpected draw events' + ); }); await t.test('start draw_point mode then exit with Escape', async () => { @@ -856,104 +999,127 @@ test('ensure user interactions fire right events', async (t) => { mode: 'simple_select' }); assert.equal(Draw.getAll().features.length, 0, 'no feature created'); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange' - ], 'no unexpected draw events'); - }); - - await t.test('start draw_line_string mode and drawing a line then finish with Enter', async () => { - Draw.deleteAll(); - Draw.changeMode('draw_line_string'); - click(map, makeMouseEvent(240, 240)); - click(map, makeMouseEvent(260, 260)); - container.dispatchEvent(enterEvent); - - await afterNextRender(); - - const expectedLine = { - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: [[240, 240], [260, 260]] - } - }; - - firedWith('draw.create', { - features: [expectedLine] - }); - - firedWith('draw.selectionchange', { - features: [expectedLine], - points: [] - }); - - firedWith('draw.modechange', { - mode: 'simple_select' - }); - - assert.deepEqual(flushDrawEvents(), [ - 'draw.create', - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); - }); - - await t.test('start draw_line_string mode then exit with Escape', async () => { - Draw.deleteAll(); - Draw.changeMode('draw_line_string'); - click(map, makeMouseEvent(0, 0)); - click(map, makeMouseEvent(20, 20)); - container.dispatchEvent(escapeEvent); - - await afterNextRender(); - - firedWith('draw.modechange', { - mode: 'simple_select' - }); - assert.equal(Draw.getAll().features.length, 0, 'no feature created'); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange'], + 'no unexpected draw events' + ); }); - await t.test('start draw_polygon mode and drawing a polygon then finish with Enter', async () => { - Draw.deleteAll(); - Draw.changeMode('draw_polygon'); - click(map, makeMouseEvent(240, 240)); - click(map, makeMouseEvent(260, 260)); - click(map, makeMouseEvent(300, 200)); - container.dispatchEvent(enterEvent); + await t.test( + 'start draw_line_string mode and drawing a line then finish with Enter', + async () => { + Draw.deleteAll(); + Draw.changeMode('draw_line_string'); + click(map, makeMouseEvent(240, 240)); + click(map, makeMouseEvent(260, 260)); + container.dispatchEvent(enterEvent); - await afterNextRender(); + await afterNextRender(); - const expectedPolygon = { - type: 'Feature', - properties: {}, - geometry: { - type: 'Polygon', - coordinates: [[[240, 240], [260, 260], [300, 200], [240, 240]]] - } - }; - firedWith('draw.create', { - features: [expectedPolygon] - }); - - firedWith('draw.selectionchange', { - features: [expectedPolygon], - points: [] - }); - - firedWith('draw.modechange', { - mode: 'simple_select' - }); - - assert.deepEqual(flushDrawEvents(), [ - 'draw.create', - 'draw.modechange', - 'draw.selectionchange' - ], 'no unexpected draw events'); - }); + const expectedLine = { + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [ + [240, 240], + [260, 260] + ] + } + }; + + firedWith('draw.create', { + features: [expectedLine] + }); + + firedWith('draw.selectionchange', { + features: [expectedLine], + points: [] + }); + + firedWith('draw.modechange', { + mode: 'simple_select' + }); + + assert.deepEqual( + flushDrawEvents(), + ['draw.create', 'draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); + } + ); + + await t.test( + 'start draw_line_string mode then exit with Escape', + async () => { + Draw.deleteAll(); + Draw.changeMode('draw_line_string'); + click(map, makeMouseEvent(0, 0)); + click(map, makeMouseEvent(20, 20)); + container.dispatchEvent(escapeEvent); + + await afterNextRender(); + + firedWith('draw.modechange', { + mode: 'simple_select' + }); + assert.equal(Draw.getAll().features.length, 0, 'no feature created'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange'], + 'no unexpected draw events' + ); + } + ); + + await t.test( + 'start draw_polygon mode and drawing a polygon then finish with Enter', + async () => { + Draw.deleteAll(); + Draw.changeMode('draw_polygon'); + click(map, makeMouseEvent(240, 240)); + click(map, makeMouseEvent(260, 260)); + click(map, makeMouseEvent(300, 200)); + container.dispatchEvent(enterEvent); + + await afterNextRender(); + + const expectedPolygon = { + type: 'Feature', + properties: {}, + geometry: { + type: 'Polygon', + coordinates: [ + [ + [240, 240], + [260, 260], + [300, 200], + [240, 240] + ] + ] + } + }; + firedWith('draw.create', { + features: [expectedPolygon] + }); + + firedWith('draw.selectionchange', { + features: [expectedPolygon], + points: [] + }); + + firedWith('draw.modechange', { + mode: 'simple_select' + }); + + assert.deepEqual( + flushDrawEvents(), + ['draw.create', 'draw.modechange', 'draw.selectionchange'], + 'no unexpected draw events' + ); + } + ); await t.test('start draw_polygon mode then exit with Escape', async () => { Draw.deleteAll(); @@ -968,9 +1134,11 @@ test('ensure user interactions fire right events', async (t) => { mode: 'simple_select' }); assert.equal(Draw.getAll().features.length, 0, 'no feature created'); - assert.deepEqual(flushDrawEvents(), [ - 'draw.modechange' - ], 'no unexpected draw events'); + assert.deepEqual( + flushDrawEvents(), + ['draw.modechange'], + 'no unexpected draw events' + ); }); await t.test('box selection includes no features', async () => { @@ -983,10 +1151,10 @@ test('ensure user interactions fire right events', async (t) => { }); }); -test('ensure API fire right events', async (t) => { +test('ensure API fire right events', async t => { const container = document.createElement('div'); document.body.appendChild(container); - const map = createMap({container}); + const map = createMap({ container }); const fireSpy = spy(map, 'fire'); // Explicitly set `suppressAPIEvents` to false to ensure events are fired @@ -1013,7 +1181,10 @@ test('ensure API fire right events', async (t) => { properties: {}, geometry: { type: 'LineString', - coordinates: [[10, 10], [20, 20]] + coordinates: [ + [10, 10], + [20, 20] + ] } }; @@ -1024,23 +1195,23 @@ test('ensure API fire right events', async (t) => { await t.test('Draw#add fires draw.create event', async () => { Draw.add(point); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.create'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, {features: [point]}); + assert.deepStrictEqual(fireSpy.lastCall.lastArg, { features: [point] }); Draw.add(line); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.create'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, {features: [line]}); + assert.deepStrictEqual(fireSpy.lastCall.lastArg, { features: [line] }); }); await t.test('Draw#delete fires draw.delete event', async () => { Draw.delete(point.id); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.delete'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, {features: [point]}); + assert.deepStrictEqual(fireSpy.lastCall.lastArg, { features: [point] }); }); await t.test('Draw#deleteAll fires draw.delete event', async () => { Draw.deleteAll(); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.delete'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, {features: [line]}); + assert.deepStrictEqual(fireSpy.lastCall.lastArg, { features: [line] }); }); await t.test('Draw#set fires draw.create event', async () => { @@ -1051,13 +1222,17 @@ test('ensure API fire right events', async (t) => { Draw.set(collection); - assert.strictEqual(fireSpy.callCount, 2, 'fires draw.create event for each feature'); + assert.strictEqual( + fireSpy.callCount, + 2, + 'fires draw.create event for each feature' + ); assert.strictEqual(fireSpy.firstCall.firstArg, 'draw.create'); - assert.deepStrictEqual(fireSpy.firstCall.lastArg, {features: [point]}); + assert.deepStrictEqual(fireSpy.firstCall.lastArg, { features: [point] }); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.create'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, {features: [line]}); + assert.deepStrictEqual(fireSpy.lastCall.lastArg, { features: [line] }); }); await t.test('Draw#set fires draw.delete event', async () => { @@ -1068,10 +1243,14 @@ test('ensure API fire right events', async (t) => { Draw.set(collection); - assert.strictEqual(fireSpy.callCount, 1, 'fires draw.delete event for deleted feature'); + assert.strictEqual( + fireSpy.callCount, + 1, + 'fires draw.delete event for deleted feature' + ); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.delete'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, {features: [point]}); + assert.deepStrictEqual(fireSpy.lastCall.lastArg, { features: [point] }); }); await t.test('Draw#setFeatureProperty fires draw.update event', () => { @@ -1082,25 +1261,57 @@ test('ensure API fire right events', async (t) => { assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.update'); assert.deepStrictEqual(fireSpy.lastCall.lastArg, { action: 'change_properties', - features: [{...point, properties: {price: 200}}] + features: [{ ...point, properties: { price: 200 } }] }); }); await t.test('Draw#changeMode fires draw.modechange event', async () => { Draw.changeMode('draw_point'); - assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.modechange', 'Draw.changeMode triggers draw.modechange event'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, { mode: 'draw_point' }, 'Draw.changeMode triggers draw.modechange event with correct data'); + assert.strictEqual( + fireSpy.lastCall.firstArg, + 'draw.modechange', + 'Draw.changeMode triggers draw.modechange event' + ); + assert.deepStrictEqual( + fireSpy.lastCall.lastArg, + { mode: 'draw_point' }, + 'Draw.changeMode triggers draw.modechange event with correct data' + ); Draw.changeMode('draw_line_string'); - assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.modechange', 'Draw.changeMode triggers draw.modechange event'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, { mode: 'draw_line_string' }, 'Draw.changeMode triggers draw.modechange event with correct data'); + assert.strictEqual( + fireSpy.lastCall.firstArg, + 'draw.modechange', + 'Draw.changeMode triggers draw.modechange event' + ); + assert.deepStrictEqual( + fireSpy.lastCall.lastArg, + { mode: 'draw_line_string' }, + 'Draw.changeMode triggers draw.modechange event with correct data' + ); Draw.changeMode('draw_polygon'); - assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.modechange', 'Draw.changeMode triggers draw.modechange event'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, { mode: 'draw_polygon' }, 'Draw.changeMode triggers draw.modechange event with correct data'); + assert.strictEqual( + fireSpy.lastCall.firstArg, + 'draw.modechange', + 'Draw.changeMode triggers draw.modechange event' + ); + assert.deepStrictEqual( + fireSpy.lastCall.lastArg, + { mode: 'draw_polygon' }, + 'Draw.changeMode triggers draw.modechange event with correct data' + ); Draw.changeMode('simple_select'); - assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.modechange', 'Draw.changeMode triggers draw.modechange event'); - assert.deepStrictEqual(fireSpy.lastCall.lastArg, { mode: 'simple_select' }, 'Draw.changeMode triggers draw.modechange event with correct data'); + assert.strictEqual( + fireSpy.lastCall.firstArg, + 'draw.modechange', + 'Draw.changeMode triggers draw.modechange event' + ); + assert.deepStrictEqual( + fireSpy.lastCall.lastArg, + { mode: 'simple_select' }, + 'Draw.changeMode triggers draw.modechange event with correct data' + ); }); }); diff --git a/test/is_click.test.js b/test/is_click.test.js index 2ee4ca9f..605ea80f 100644 --- a/test/is_click.test.js +++ b/test/is_click.test.js @@ -18,13 +18,24 @@ test('isClick easy', () => { time: 1 }; const b = { - point: { x: 1, y: 1}, + point: { x: 1, y: 1 }, time: 1 }; - assert.equal(isClick({}, b, testOptions), true, 'true when start is missing point and time'); - assert.equal(isClick({ time: 2000 }, b, testOptions), true, 'true when start has only time'); - assert.equal(isClick(a, b, testOptions), true, 'true when start and end match exactly'); - + assert.equal( + isClick({}, b, testOptions), + true, + 'true when start is missing point and time' + ); + assert.equal( + isClick({ time: 2000 }, b, testOptions), + true, + 'true when start has only time' + ); + assert.equal( + isClick(a, b, testOptions), + true, + 'true when start and end match exactly' + ); }); test('isClick when start/end have same time, very close coordinates', () => { @@ -33,11 +44,10 @@ test('isClick when start/end have same time, very close coordinates', () => { time: 1 }; const b = { - point: { x: 2, y: 1.5}, + point: { x: 2, y: 1.5 }, time: 1 }; assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when start/end have same coordinates, distant times', () => { @@ -46,11 +56,10 @@ test('isClick when start/end have same coordinates, distant times', () => { time: 1 }; const b = { - point: { x: 1, y: 1}, + point: { x: 1, y: 1 }, time: 6000 }; assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when start/end have very close coordinates, distant times', () => { @@ -59,14 +68,12 @@ test('isClick when start/end have very close coordinates, distant times', () => time: 1 }; const b = { - point: { x: 2, y: 1.15}, + point: { x: 2, y: 1.15 }, time: 6000 }; assert.equal(isClick(a, b, testOptions), true); - }); - test('isClick when moving just under 4, same times', () => { const a = { point: { x: 1, y: 1 }, @@ -78,7 +85,6 @@ test('isClick when moving just under 4, same times', () => { }; // Move distance ~3.959798 assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when moving just under 4, distant times', () => { @@ -92,7 +98,6 @@ test('isClick when moving just under 4, distant times', () => { }; // Move distance ~3.959798 assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when moving just above 4, same times', () => { @@ -101,12 +106,11 @@ test('isClick when moving just above 4, same times', () => { time: 1 }; const b = { - point: { x: 3.9, y: 3.9}, + point: { x: 3.9, y: 3.9 }, time: 1 }; // Move distance ~4.101219 assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when moving just above 4, very close times', () => { @@ -115,12 +119,11 @@ test('isClick when moving just above 4, very close times', () => { time: 1 }; const b = { - point: { x: 3.9, y: 3.9}, + point: { x: 3.9, y: 3.9 }, time: 499 }; // Move distance ~4.101219 assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when moving just above 4, distant times', () => { @@ -129,12 +132,11 @@ test('isClick when moving just above 4, distant times', () => { time: 1 }; const b = { - point: { x: 3.9, y: 3.9}, + point: { x: 3.9, y: 3.9 }, time: 6000 }; // Move distance ~4.101219 assert.equal(isClick(a, b, testOptions), false); - }); test('isClick when moving just above 4, barely too distant times', () => { @@ -143,12 +145,11 @@ test('isClick when moving just above 4, barely too distant times', () => { time: 1 }; const b = { - point: { x: 3.9, y: 3.9}, + point: { x: 3.9, y: 3.9 }, time: 501 }; // Move distance ~4.101219 assert.equal(isClick(a, b, testOptions), false); - }); test('isClick when moving just below 12, same times', () => { @@ -157,12 +158,11 @@ test('isClick when moving just below 12, same times', () => { time: 1 }; const b = { - point: { x: 9.2, y: 9.2}, + point: { x: 9.2, y: 9.2 }, time: 1 }; // Move distance ~11.596551 assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when moving just below 12, very close times', () => { @@ -171,12 +171,11 @@ test('isClick when moving just below 12, very close times', () => { time: 1 }; const b = { - point: { x: 9.2, y: 9.2}, + point: { x: 9.2, y: 9.2 }, time: 499 }; // Move distance ~11.596551 assert.equal(isClick(a, b, testOptions), true); - }); test('isClick when moving just below 12, distant times', () => { @@ -185,12 +184,11 @@ test('isClick when moving just below 12, distant times', () => { time: 1 }; const b = { - point: { x: 9.2, y: 9.2}, + point: { x: 9.2, y: 9.2 }, time: 6000 }; // Move distance ~11.596551 assert.equal(isClick(a, b, testOptions), false); - }); test('isClick when moving just below 12, barely too distant times', () => { @@ -199,12 +197,11 @@ test('isClick when moving just below 12, barely too distant times', () => { time: 1 }; const b = { - point: { x: 9.2, y: 9.2}, + point: { x: 9.2, y: 9.2 }, time: 501 }; // Move distance ~11.596551 assert.equal(isClick(a, b, testOptions), false); - }); test('isClick when moving just above 12, same times', () => { @@ -213,7 +210,7 @@ test('isClick when moving just above 12, same times', () => { time: 1 }; const b = { - point: { x: 9.5, y: 9.5}, + point: { x: 9.5, y: 9.5 }, time: 1 }; // Move distance ~12.020815 @@ -226,7 +223,7 @@ test('isClick when moving just above 12, distant times', () => { time: 1 }; const b = { - point: { x: 9.5, y: 9.5}, + point: { x: 9.5, y: 9.5 }, time: 6000 }; // Move distance ~12.020815 diff --git a/test/is_event_at_coordinates.test.js b/test/is_event_at_coordinates.test.js index 1ddb04b1..618ede96 100644 --- a/test/is_event_at_coordinates.test.js +++ b/test/is_event_at_coordinates.test.js @@ -3,20 +3,37 @@ import assert from 'node:assert/strict'; import isEventAtCoordinates from '../src/lib/is_event_at_coordinates.js'; test('isEventAtCoordinates', () => { - assert.ok(isEventAtCoordinates({ - lngLat: { - lng: 3, - lat: 29 - } - }, [3, 29])); - assert.equal(isEventAtCoordinates({ - lngLat: { - lng: -3, - lat: 29 - } - }, [3, 29]), false); + assert.ok( + isEventAtCoordinates( + { + lngLat: { + lng: 3, + lat: 29 + } + }, + [3, 29] + ) + ); + assert.equal( + isEventAtCoordinates( + { + lngLat: { + lng: -3, + lat: 29 + } + }, + [3, 29] + ), + false + ); - assert.equal(isEventAtCoordinates({ - nothing: true - }, [3, 29]), false); + assert.equal( + isEventAtCoordinates( + { + nothing: true + }, + [3, 29] + ), + false + ); }); diff --git a/test/is_tap.test.js b/test/is_tap.test.js index 2bb10aa4..136e3bf6 100644 --- a/test/is_tap.test.js +++ b/test/is_tap.test.js @@ -17,12 +17,24 @@ test('isTap easy', () => { time: 1 }; const b = { - point: { x: 1, y: 1}, + point: { x: 1, y: 1 }, time: 1 }; - assert.equal(isTap({}, b, testOptions), true, 'true when start is missing point and time'); - assert.equal(isTap({ time: 2000 }, b, testOptions), true, 'true when start has only time'); - assert.equal(isTap(a, b, testOptions), true, 'true when start and end match exactly'); + assert.equal( + isTap({}, b, testOptions), + true, + 'true when start is missing point and time' + ); + assert.equal( + isTap({ time: 2000 }, b, testOptions), + true, + 'true when start has only time' + ); + assert.equal( + isTap(a, b, testOptions), + true, + 'true when start and end match exactly' + ); }); test('isTap when moving barely at all, same times', () => { @@ -31,7 +43,7 @@ test('isTap when moving barely at all, same times', () => { time: 1 }; const b = { - point: { x: 2, y: 1.5}, + point: { x: 2, y: 1.5 }, time: 1 }; assert.equal(isTap(a, b, testOptions), true); @@ -69,7 +81,7 @@ test('isTap when moving barely at all, just before the time limit', () => { time: 1 }; const b = { - point: { x: 2, y: 1.5}, + point: { x: 2, y: 1.5 }, time: 250 }; assert.equal(isTap(a, b, testOptions), true); diff --git a/test/line_string.test.js b/test/line_string.test.js index 6f052e4e..eba49ce7 100644 --- a/test/line_string.test.js +++ b/test/line_string.test.js @@ -1,13 +1,13 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import Feature from '../src/feature_types/feature'; import LineString from '../src/feature_types/line_string'; import MapboxDraw from '../index'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; import createMockCtx from './utils/create_mock_feature_context'; -import {drawGeometry} from './utils/draw_geometry'; +import { drawGeometry } from './utils/draw_geometry'; import createMap from './utils/create_map'; test('LineString constructor and API', () => { @@ -17,19 +17,55 @@ test('LineString constructor and API', () => { // Instance members assert.equal(lineString.ctx, ctx, 'lineString.ctx'); - assert.equal(lineString.coordinates, rawLine.geometry.coordinates, 'lineString.coordinates'); - assert.equal(lineString.properties, rawLine.properties, 'lineString.properties'); + assert.equal( + lineString.coordinates, + rawLine.geometry.coordinates, + 'lineString.coordinates' + ); + assert.equal( + lineString.properties, + rawLine.properties, + 'lineString.properties' + ); assert.equal(lineString.id, rawLine.id, 'lineString.id'); assert.equal(lineString.type, rawLine.geometry.type, 'lineString.type'); - assert.equal(getPublicMemberKeys(lineString).length, 5, 'no unexpected instance members'); + assert.equal( + getPublicMemberKeys(lineString).length, + 5, + 'no unexpected instance members' + ); // Prototype members - assert.equal(typeof LineString.prototype.isValid, 'function', 'lineString.isValid'); - assert.equal(typeof LineString.prototype.addCoordinate, 'function', 'lineString.addCoordinate'); - assert.equal(typeof LineString.prototype.getCoordinate, 'function', 'lineString.getCoordinate'); - assert.equal(typeof LineString.prototype.removeCoordinate, 'function', 'lineString.removeCoordinate'); - assert.equal(typeof LineString.prototype.updateCoordinate, 'function', 'lineString.updateCoordinate'); - assert.equal(getPublicMemberKeys(LineString.prototype).length, 5, 'no unexpected prototype members'); + assert.equal( + typeof LineString.prototype.isValid, + 'function', + 'lineString.isValid' + ); + assert.equal( + typeof LineString.prototype.addCoordinate, + 'function', + 'lineString.addCoordinate' + ); + assert.equal( + typeof LineString.prototype.getCoordinate, + 'function', + 'lineString.getCoordinate' + ); + assert.equal( + typeof LineString.prototype.removeCoordinate, + 'function', + 'lineString.removeCoordinate' + ); + assert.equal( + typeof LineString.prototype.updateCoordinate, + 'function', + 'lineString.updateCoordinate' + ); + assert.equal( + getPublicMemberKeys(LineString.prototype).length, + 5, + 'no unexpected prototype members' + ); assert.ok(LineString.prototype instanceof Feature, 'inherits from Feature'); }); @@ -42,32 +78,62 @@ test('LineString#isValid', () => { const invalidRawLineA = createFeature('line'); invalidRawLineA.geometry.coordinates = [3]; const invalidLineStringA = new LineString(createMockCtx(), invalidRawLineA); - assert.equal(invalidLineStringA.isValid(), false, 'returns false when there is one coordinate'); + assert.equal( + invalidLineStringA.isValid(), + false, + 'returns false when there is one coordinate' + ); const invalidRawLineB = createFeature('line'); invalidRawLineB.geometry.coordinates = []; const invalidLineStringB = new LineString(createMockCtx(), invalidRawLineB); - assert.equal(invalidLineStringB.isValid(), false, 'returns false when there are no coordinates'); + assert.equal( + invalidLineStringB.isValid(), + false, + 'returns false when there are no coordinates' + ); }); test('LineString#addCoordinate', () => { const rawLine = createFeature('line'); - rawLine.geometry.coordinates = [[1, 2], [3, 4]]; + rawLine.geometry.coordinates = [ + [1, 2], + [3, 4] + ]; const lineString = new LineString(createMockCtx(), rawLine); const changedSpy = spy(lineString, 'changed'); lineString.addCoordinate(1, 5, 6); assert.equal(changedSpy.callCount, 1, 'called lineString.changed()'); - assert.deepEqual(lineString.getCoordinates(), [[1, 2], [5, 6], [3, 4]], 'new coordinate inserted in correct place'); + assert.deepEqual( + lineString.getCoordinates(), + [ + [1, 2], + [5, 6], + [3, 4] + ], + 'new coordinate inserted in correct place' + ); lineString.addCoordinate('0', 7, 8); - assert.deepEqual(lineString.getCoordinates(), [[7, 8], [1, 2], [5, 6], [3, 4]], - 'string path works'); + assert.deepEqual( + lineString.getCoordinates(), + [ + [7, 8], + [1, 2], + [5, 6], + [3, 4] + ], + 'string path works' + ); }); test('LineString#getCoordinate', () => { const rawLine = createFeature('line'); - rawLine.geometry.coordinates = [[1, 2], [3, 4]]; + rawLine.geometry.coordinates = [ + [1, 2], + [3, 4] + ]; const lineString = new LineString(createMockCtx(), rawLine); assert.deepEqual(lineString.getCoordinate(0), [1, 2], 'number path works'); @@ -76,28 +142,51 @@ test('LineString#getCoordinate', () => { test('LineString#removeCoordinate', () => { const rawLine = createFeature('line'); - rawLine.geometry.coordinates = [[1, 2], [3, 4]]; + rawLine.geometry.coordinates = [ + [1, 2], + [3, 4] + ]; const lineString = new LineString(createMockCtx(), rawLine); const changedSpy = spy(lineString, 'changed'); lineString.removeCoordinate(1); assert.equal(changedSpy.callCount, 1, 'called lineString.changed()'); - assert.deepEqual(lineString.getCoordinates(), [[1, 2]], 'coordinate removed from correct place'); + assert.deepEqual( + lineString.getCoordinates(), + [[1, 2]], + 'coordinate removed from correct place' + ); }); test('LineString#updateCoordinate', () => { const rawLine = createFeature('line'); - rawLine.geometry.coordinates = [[1, 2], [3, 4], [5, 6]]; + rawLine.geometry.coordinates = [ + [1, 2], + [3, 4], + [5, 6] + ]; const lineString = new LineString(createMockCtx(), rawLine); const changedSpy = spy(lineString, 'changed'); lineString.updateCoordinate(1, 7, 8); assert.equal(changedSpy.callCount, 1, 'called lineString.changed()'); - assert.deepEqual(lineString.getCoordinates(), [[1, 2], [7, 8], [5, 6]], 'coordinate updated at correct place'); + assert.deepEqual( + lineString.getCoordinates(), + [ + [1, 2], + [7, 8], + [5, 6] + ], + 'coordinate updated at correct place' + ); }); test('LineString integration', async () => { - const lineStringCoordinates = [[0, 0], [40, 20], [20, 40]]; + const lineStringCoordinates = [ + [0, 0], + [40, 20], + [20, 40] + ]; const map = createMap(); const Draw = new MapboxDraw(); map.addControl(Draw); @@ -108,8 +197,16 @@ test('LineString integration', async () => { const feats = Draw.getAll().features; assert.equal(1, feats.length, 'only one'); assert.equal('LineString', feats[0].geometry.type, 'of the right type'); - assert.equal(lineStringCoordinates[0].length, feats[0].geometry.coordinates[0].length, 'right number of points'); - assert.deepEqual([...lineStringCoordinates, [20, 40]], feats[0].geometry.coordinates, 'in the right spot'); + assert.equal( + lineStringCoordinates[0].length, + feats[0].geometry.coordinates[0].length, + 'right number of points' + ); + assert.deepEqual( + [...lineStringCoordinates, [20, 40]], + feats[0].geometry.coordinates, + 'in the right spot' + ); Draw.onRemove(); }); }); diff --git a/test/map_event_to_bounding_box.test.js b/test/map_event_to_bounding_box.test.js index 125e536a..cf193ec1 100644 --- a/test/map_event_to_bounding_box.test.js +++ b/test/map_event_to_bounding_box.test.js @@ -3,24 +3,48 @@ import assert from 'node:assert/strict'; import mapEventToBoundingBox from '../src/lib/map_event_to_bounding_box.js'; test('mapEventToBoundingBox', () => { - assert.deepEqual(mapEventToBoundingBox({ - point: { - x: 1, - y: 2 - } - }), [[1, 2], [1, 2]]); + assert.deepEqual( + mapEventToBoundingBox({ + point: { + x: 1, + y: 2 + } + }), + [ + [1, 2], + [1, 2] + ] + ); - assert.deepEqual(mapEventToBoundingBox({ - point: { - x: 1, - y: 2 - } - }, 1), [[0, 1], [2, 3]]); + assert.deepEqual( + mapEventToBoundingBox( + { + point: { + x: 1, + y: 2 + } + }, + 1 + ), + [ + [0, 1], + [2, 3] + ] + ); - assert.deepEqual(mapEventToBoundingBox({ - point: { - x: 10.3, - y: 95674.234 - } - }, 50.5), [[-40.2, 95623.734], [60.8, 95724.734]]); + assert.deepEqual( + mapEventToBoundingBox( + { + point: { + x: 10.3, + y: 95674.234 + } + }, + 50.5 + ), + [ + [-40.2, 95623.734], + [60.8, 95724.734] + ] + ); }); diff --git a/test/mock-browser.js b/test/mock-browser.js index c1e18660..5d9bb3f8 100644 --- a/test/mock-browser.js +++ b/test/mock-browser.js @@ -6,8 +6,8 @@ global.window = {}; // Polyfill based on https://gist.github.com/paulirish/1579671 let lastTime = 0; -global.requestAnimationFrame = function(fn) { +global.requestAnimationFrame = function (fn) { const now = Date.now(); const nextTime = Math.max(lastTime + 16, now); - setTimeout(() => fn(lastTime = nextTime), nextTime - now); + setTimeout(() => fn((lastTime = nextTime)), nextTime - now); }; diff --git a/test/mode_handler.test.js b/test/mode_handler.test.js index 19051f80..1a2ad307 100644 --- a/test/mode_handler.test.js +++ b/test/mode_handler.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import modeHandler from '../src/lib/mode_handler.js'; import createMockModeHandlerContext from './utils/create_mock_mode_handler_context.js'; import createMockMode from './utils/create_mock_mode.js'; @@ -22,10 +22,17 @@ test('returned API', () => { assert.equal(typeof mh.touchmove, 'function', 'exposes touchmove'); assert.equal(typeof mh.touchend, 'function', 'exposes touchend'); assert.equal(typeof mh.tap, 'function', 'exposes tap'); - assert.equal(typeof mh.combineFeatures, 'function', 'exposes combineFeatures'); - assert.equal(typeof mh.uncombineFeatures, 'function', 'exposes uncombineFeatures'); + assert.equal( + typeof mh.combineFeatures, + 'function', + 'exposes combineFeatures' + ); + assert.equal( + typeof mh.uncombineFeatures, + 'function', + 'exposes uncombineFeatures' + ); assert.equal(Object.keys(mh).length, 17, 'no unexpected properties'); - }); test('ModeHandler calling mode.start with context, and delegation functionality', () => { @@ -41,35 +48,82 @@ test('ModeHandler calling mode.start with context, and delegation functionality' const drawContext = createMockModeHandlerContext(); const mh = modeHandler(mode, drawContext); - assert.equal(handleStartSpy.callCount, 1, 'start was called on mode handler creation'); + assert.equal( + handleStartSpy.callCount, + 1, + 'start was called on mode handler creation' + ); assert.equal(typeof startContext.on, 'function', 'start context has on()'); - assert.equal(typeof startContext.render, 'function', 'start context has render()'); - assert.equal(Object.keys(startContext).length, 2, 'start context has no unexpected properties'); + assert.equal( + typeof startContext.render, + 'function', + 'start context has render()' + ); + assert.equal( + Object.keys(startContext).length, + 2, + 'start context has no unexpected properties' + ); startContext.render('foo'); - assert.ok(drawContext.store.featureChanged.calledWith('foo'), 'start context render calls store.featureChanged'); + assert.ok( + drawContext.store.featureChanged.calledWith('foo'), + 'start context render calls store.featureChanged' + ); assert.throws(() => { - startContext.on('bar', () => true, () => {}); + startContext.on( + 'bar', + () => true, + () => {} + ); }, 'start context on throws on unknown event type'); mh.mousedown({ one: 1 }); - assert.equal(drawContext.store.render.callCount, 0, 'render not called if no handler fires'); - assert.equal(drawContext.ui.updateMapClasses.callCount, 0, 'updateMapClasses not called if no handler fires'); + assert.equal( + drawContext.store.render.callCount, + 0, + 'render not called if no handler fires' + ); + assert.equal( + drawContext.ui.updateMapClasses.callCount, + 0, + 'updateMapClasses not called if no handler fires' + ); const mousedownSpy = spy(); startContext.on('mousedown', () => true, mousedownSpy); mh.mousedown({ two: 2 }); - assert.equal(mousedownSpy.callCount, 1, 'mousedown callback called via delegation'); - assert.deepEqual(mousedownSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); - assert.equal(drawContext.store.render.callCount, 1, 'render called if handler fires'); - assert.equal(drawContext.ui.updateMapClasses.callCount, 1, 'updateMapClasses called if handler fires'); + assert.equal( + mousedownSpy.callCount, + 1, + 'mousedown callback called via delegation' + ); + assert.deepEqual( + mousedownSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); + assert.equal( + drawContext.store.render.callCount, + 1, + 'render called if handler fires' + ); + assert.equal( + drawContext.ui.updateMapClasses.callCount, + 1, + 'updateMapClasses called if handler fires' + ); const mousedownFailSpy = spy(); mousedownSpy.resetHistory(); startContext.on('mousedown', e => !e.three, mousedownFailSpy); mh.mousedown({ three: 3 }); - assert.equal(mousedownFailSpy.callCount, 0, 'delegation only calls callbacks with selectors returning true'); + assert.equal( + mousedownFailSpy.callCount, + 0, + 'delegation only calls callbacks with selectors returning true' + ); assert.equal(mousedownSpy.callCount, 1); assert.deepEqual(mousedownSpy.getCall(0).args, [{ three: 3 }]); @@ -77,63 +131,129 @@ test('ModeHandler calling mode.start with context, and delegation functionality' startContext.on('drag', () => true, dragSpy); mh.drag({ two: 2 }); assert.equal(dragSpy.callCount, 1, 'drag callback called via delegation'); - assert.deepEqual(dragSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.deepEqual( + dragSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const clickSpy = spy(); startContext.on('click', () => true, clickSpy); mh.click({ two: 2 }); assert.equal(clickSpy.callCount, 1, 'click callback called via delegation'); - assert.deepEqual(clickSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.deepEqual( + clickSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const mousemoveSpy = spy(); startContext.on('mousemove', () => true, mousemoveSpy); mh.mousemove({ two: 2 }); - assert.equal(mousemoveSpy.callCount, 1, 'mousemove callback called via delegation'); - assert.deepEqual(mousemoveSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.equal( + mousemoveSpy.callCount, + 1, + 'mousemove callback called via delegation' + ); + assert.deepEqual( + mousemoveSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const mouseupSpy = spy(); startContext.on('mouseup', () => true, mouseupSpy); mh.mouseup({ two: 2 }); - assert.equal(mouseupSpy.callCount, 1, 'mouseup callback called via delegation'); - assert.deepEqual(mouseupSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.equal( + mouseupSpy.callCount, + 1, + 'mouseup callback called via delegation' + ); + assert.deepEqual( + mouseupSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const mouseoutSpy = spy(); startContext.on('mouseout', () => true, mouseoutSpy); mh.mouseout({ two: 2 }); - assert.equal(mouseoutSpy.callCount, 1, 'mouseout callback called via delegation'); - assert.deepEqual(mouseoutSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.equal( + mouseoutSpy.callCount, + 1, + 'mouseout callback called via delegation' + ); + assert.deepEqual( + mouseoutSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const keydownSpy = spy(); startContext.on('keydown', () => true, keydownSpy); mh.keydown({ two: 2 }); - assert.equal(keydownSpy.callCount, 1, 'keydown callback called via delegation'); - assert.deepEqual(keydownSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.equal( + keydownSpy.callCount, + 1, + 'keydown callback called via delegation' + ); + assert.deepEqual( + keydownSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const keyupSpy = spy(); startContext.on('keyup', () => true, keyupSpy); mh.keyup({ two: 2 }); assert.equal(keyupSpy.callCount, 1, 'keyup callback called via delegation'); - assert.deepEqual(keyupSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.deepEqual( + keyupSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const touchstartSpy = spy(); startContext.on('touchstart', () => true, touchstartSpy); mh.touchstart({ two: 2 }); - assert.equal(touchstartSpy.callCount, 1, 'touchstart callback called via delegation'); - assert.deepEqual(touchstartSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.equal( + touchstartSpy.callCount, + 1, + 'touchstart callback called via delegation' + ); + assert.deepEqual( + touchstartSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const touchmoveSpy = spy(); startContext.on('touchmove', () => true, touchmoveSpy); mh.touchmove({ two: 2 }); - assert.equal(touchmoveSpy.callCount, 1, 'touchmove callback called via delegation'); - assert.deepEqual(touchmoveSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); + assert.equal( + touchmoveSpy.callCount, + 1, + 'touchmove callback called via delegation' + ); + assert.deepEqual( + touchmoveSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); const touchendSpy = spy(); startContext.on('touchend', () => true, touchendSpy); mh.touchend({ two: 2 }); - assert.equal(touchendSpy.callCount, 1, 'touchend callback called via delegation'); - assert.deepEqual(touchendSpy.getCall(0).args, [{ two: 2 }], 'with correct argument'); - - + assert.equal( + touchendSpy.callCount, + 1, + 'touchend callback called via delegation' + ); + assert.deepEqual( + touchendSpy.getCall(0).args, + [{ two: 2 }], + 'with correct argument' + ); }); test('ModeHandler#stop calling mode.stop', () => { @@ -142,8 +262,6 @@ test('ModeHandler#stop calling mode.stop', () => { mh.stop(); assert.equal(mode.stop.callCount, 1, 'mode.stop called'); - - }); test('ModeHandler#stop not calling nonexistent mode.stop', () => { @@ -154,8 +272,6 @@ test('ModeHandler#stop not calling nonexistent mode.stop', () => { assert.doesNotThrow(() => { mh.stop(); }); - - }); test('Modehandler#trash', () => { @@ -166,8 +282,6 @@ test('Modehandler#trash', () => { mh.trash(); assert.equal(mode.trash.callCount, 1, 'mode.trash called'); assert.equal(drawContext.store.render.callCount, 1, 'store.render called'); - - }); test('Modehandler#trash without a mode.trash', () => { @@ -179,7 +293,9 @@ test('Modehandler#trash without a mode.trash', () => { assert.doesNotThrow(() => { mh.trash(); }); - assert.equal(drawContext.store.render.callCount, 0, 'store.render not called'); - - + assert.equal( + drawContext.store.render.callCount, + 0, + 'store.render not called' + ); }); diff --git a/test/move_features.test.js b/test/move_features.test.js index c221c15d..82f14859 100644 --- a/test/move_features.test.js +++ b/test/move_features.test.js @@ -32,58 +32,127 @@ test('moveFeatures point beyond south limit', () => { test('moveFeatures line', () => { const line = new LineString(mockFeatureContext, getGeoJSON('line')); - line.setCoordinates([[10, 15], [-10, -30], [17, 33]]); + line.setCoordinates([ + [10, 15], + [-10, -30], + [17, 33] + ]); moveFeatures([line], { lng: 7, lat: 13 }); - assert.deepEqual(line.getCoordinates(), - [[17, 28], [-3, -17], [24, 46]] - ); + assert.deepEqual(line.getCoordinates(), [ + [17, 28], + [-3, -17], + [24, 46] + ]); }); test('moveFeatures line beyond north limit', () => { const line = new LineString(mockFeatureContext, getGeoJSON('line')); - line.setCoordinates([[10, 15], [-10, -30], [17, 33]]); + line.setCoordinates([ + [10, 15], + [-10, -30], + [17, 33] + ]); moveFeatures([line], { lng: 7, lat: 60 }); - assert.deepEqual(line.getCoordinates(), - [[17, 72], [-3, 27], [24, 90]], + assert.deepEqual( + line.getCoordinates(), + [ + [17, 72], + [-3, 27], + [24, 90] + ], 'lat should only move 57' ); }); test('moveFeatures line beyond south pole', () => { const line = new LineString(mockFeatureContext, getGeoJSON('line')); - line.setCoordinates([[10, 15], [-10, -30], [17, 33]]); + line.setCoordinates([ + [10, 15], + [-10, -30], + [17, 33] + ]); moveFeatures([line], { lng: -7, lat: -100 }); - assert.deepEqual(line.getCoordinates(), - [[3, -45], [-17, -90], [10, -27]], + assert.deepEqual( + line.getCoordinates(), + [ + [3, -45], + [-17, -90], + [10, -27] + ], 'lat should only move -45' ); }); test('moveFeatures polygon', () => { const polygon = new Polygon(mockFeatureContext, getGeoJSON('polygon')); - polygon.setCoordinates([[[0, 0], [0, 10], [10, 10], [10, 0]]]); + polygon.setCoordinates([ + [ + [0, 0], + [0, 10], + [10, 10], + [10, 0] + ] + ]); moveFeatures([polygon], { lng: -23, lat: 31.33 }); - assert.deepEqual(polygon.getCoordinates(), - [[[-23, 31.33], [-23, 41.33], [-13, 41.33], [-13, 31.33], [-23, 31.33]]] - ); + assert.deepEqual(polygon.getCoordinates(), [ + [ + [-23, 31.33], + [-23, 41.33], + [-13, 41.33], + [-13, 31.33], + [-23, 31.33] + ] + ]); }); test('moveFeatures polygon beyond north limit', () => { const polygon = new Polygon(mockFeatureContext, getGeoJSON('polygon')); - polygon.setCoordinates([[[0, 0], [0, 20], [10, 10], [10, 0]]]); + polygon.setCoordinates([ + [ + [0, 0], + [0, 20], + [10, 10], + [10, 0] + ] + ]); moveFeatures([polygon], { lng: -0.5, lat: 100 }); - assert.deepEqual(polygon.getCoordinates(), - [[[-0.5, 70], [-0.5, 90], [9.5, 80], [9.5, 70], [-0.5, 70]]], + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [-0.5, 70], + [-0.5, 90], + [9.5, 80], + [9.5, 70], + [-0.5, 70] + ] + ], 'lat should only move 70' ); }); test('moveFeatures polygon beyond south pole', () => { const polygon = new Polygon(mockFeatureContext, getGeoJSON('polygon')); - polygon.setCoordinates([[[0, 0], [0, -10.5], [10, -40], [10, 0]]]); + polygon.setCoordinates([ + [ + [0, 0], + [0, -10.5], + [10, -40], + [10, 0] + ] + ]); moveFeatures([polygon], { lng: 1, lat: -80.44 }); - assert.deepEqual(polygon.getCoordinates(), - [[[1, -50], [1, -60.5], [11, -90], [11, -50], [1, -50]]], + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [1, -50], + [1, -60.5], + [11, -90], + [11, -50], + [1, -50] + ] + ], 'lat should only move -50' ); }); @@ -92,17 +161,42 @@ test('moveFeatures multiple features', () => { const point = new Point(mockFeatureContext, getGeoJSON('point')); point.setCoordinates([10, 20]); const line = new LineString(mockFeatureContext, getGeoJSON('line')); - line.setCoordinates([[10, 15], [-10, -30], [17, 33]]); + line.setCoordinates([ + [10, 15], + [-10, -30], + [17, 33] + ]); const polygon = new Polygon(mockFeatureContext, getGeoJSON('polygon')); - polygon.setCoordinates([[[0, 0], [0, 10], [10, 10], [10, 0]]]); + polygon.setCoordinates([ + [ + [0, 0], + [0, 10], + [10, 10], + [10, 0] + ] + ]); moveFeatures([point, line, polygon], { lng: 5, lat: -7 }); assert.deepEqual(point.getCoordinates(), [15, 13], 'point moved'); - assert.deepEqual(line.getCoordinates(), - [[15, 8], [-5, -37], [22, 26]], + assert.deepEqual( + line.getCoordinates(), + [ + [15, 8], + [-5, -37], + [22, 26] + ], 'line moved' ); - assert.deepEqual(polygon.getCoordinates(), - [[[5, -7], [5, 3], [15, 3], [15, -7], [5, -7]]], + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [5, -7], + [5, 3], + [15, 3], + [15, -7], + [5, -7] + ] + ], 'polygon moved' ); }); @@ -111,17 +205,42 @@ test('moveFeatures multiple features beyond north limit', () => { const point = new Point(mockFeatureContext, getGeoJSON('point')); point.setCoordinates([10, 45]); const line = new LineString(mockFeatureContext, getGeoJSON('line')); - line.setCoordinates([[10, 15], [-10, -30], [17, 33]]); + line.setCoordinates([ + [10, 15], + [-10, -30], + [17, 33] + ]); const polygon = new Polygon(mockFeatureContext, getGeoJSON('polygon')); - polygon.setCoordinates([[[0, 0], [0, 10], [10, 10], [10, 0]]]); + polygon.setCoordinates([ + [ + [0, 0], + [0, 10], + [10, 10], + [10, 0] + ] + ]); moveFeatures([point, line, polygon], { lng: 5, lat: 200 }); assert.deepEqual(point.getCoordinates(), [15, 85], 'point lat only moved 40'); - assert.deepEqual(line.getCoordinates(), - [[15, 55], [-5, 10], [22, 73]], + assert.deepEqual( + line.getCoordinates(), + [ + [15, 55], + [-5, 10], + [22, 73] + ], 'line lat only moved 40' ); - assert.deepEqual(polygon.getCoordinates(), - [[[5, 40], [5, 50], [15, 50], [15, 40], [5, 40]]], + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [5, 40], + [5, 50], + [15, 50], + [15, 40], + [5, 40] + ] + ], 'polygon lat only moved 40' ); }); @@ -130,17 +249,46 @@ test('moveFeatures multiple features beyond south limit', () => { const point = new Point(mockFeatureContext, getGeoJSON('point')); point.setCoordinates([10, 20]); const line = new LineString(mockFeatureContext, getGeoJSON('line')); - line.setCoordinates([[10, 15], [-10, -30], [17, 33]]); + line.setCoordinates([ + [10, 15], + [-10, -30], + [17, 33] + ]); const polygon = new Polygon(mockFeatureContext, getGeoJSON('polygon')); - polygon.setCoordinates([[[0, 0], [0, 10], [10, 10], [10, 0]]]); + polygon.setCoordinates([ + [ + [0, 0], + [0, 10], + [10, 10], + [10, 0] + ] + ]); moveFeatures([point, line, polygon], { lng: 5, lat: -120 }); - assert.deepEqual(point.getCoordinates(), [15, -40], 'point lat only moved -60'); - assert.deepEqual(line.getCoordinates(), - [[15, -45], [-5, -90], [22, -27]], + assert.deepEqual( + point.getCoordinates(), + [15, -40], + 'point lat only moved -60' + ); + assert.deepEqual( + line.getCoordinates(), + [ + [15, -45], + [-5, -90], + [22, -27] + ], 'line lat only moved -60' ); - assert.deepEqual(polygon.getCoordinates(), - [[[5, -60], [5, -50], [15, -50], [15, -60], [5, -60]]], + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [5, -60], + [5, -50], + [15, -50], + [15, -60], + [5, -60] + ] + ], 'polygon moved' ); }); diff --git a/test/multi_feature.test.js b/test/multi_feature.test.js index da80974a..b49dfee9 100644 --- a/test/multi_feature.test.js +++ b/test/multi_feature.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import Feature from '../src/feature_types/feature.js'; import Point from '../src/feature_types/point.js'; import Polygon from '../src/feature_types/polygon.js'; @@ -13,18 +13,52 @@ test('MultiPoint via MultiFeature', () => { assert.ok(MultiFeature.prototype instanceof Feature, 'inherits from Feature'); // Prototype members - assert.equal(typeof MultiFeature.prototype.isValid, 'function', 'polygon.isValid'); - assert.equal(typeof MultiFeature.prototype.setCoordinates, 'function', 'polygon.setCoordinates'); - assert.equal(typeof MultiFeature.prototype.getCoordinate, 'function', 'polygon.getCoordinate'); - assert.equal(typeof MultiFeature.prototype.getCoordinates, 'function', 'polygon.getCoordinates'); - assert.equal(typeof MultiFeature.prototype.updateCoordinate, 'function', 'polygon.updateCoordinate'); - assert.equal(typeof MultiFeature.prototype.addCoordinate, 'function', 'polygon.addCoordinate'); - assert.equal(typeof MultiFeature.prototype.removeCoordinate, 'function', 'polygon.removeCoordinate'); - assert.equal(typeof MultiFeature.prototype.getFeatures, 'function', 'polygon.getFeatures'); - - assert.equal(getPublicMemberKeys(MultiFeature.prototype).length, 8, 'no unexpected prototype members'); - + assert.equal( + typeof MultiFeature.prototype.isValid, + 'function', + 'polygon.isValid' + ); + assert.equal( + typeof MultiFeature.prototype.setCoordinates, + 'function', + 'polygon.setCoordinates' + ); + assert.equal( + typeof MultiFeature.prototype.getCoordinate, + 'function', + 'polygon.getCoordinate' + ); + assert.equal( + typeof MultiFeature.prototype.getCoordinates, + 'function', + 'polygon.getCoordinates' + ); + assert.equal( + typeof MultiFeature.prototype.updateCoordinate, + 'function', + 'polygon.updateCoordinate' + ); + assert.equal( + typeof MultiFeature.prototype.addCoordinate, + 'function', + 'polygon.addCoordinate' + ); + assert.equal( + typeof MultiFeature.prototype.removeCoordinate, + 'function', + 'polygon.removeCoordinate' + ); + assert.equal( + typeof MultiFeature.prototype.getFeatures, + 'function', + 'polygon.getFeatures' + ); + assert.equal( + getPublicMemberKeys(MultiFeature.prototype).length, + 8, + 'no unexpected prototype members' + ); }); test('MultiPoint', () => { @@ -34,7 +68,11 @@ test('MultiPoint', () => { properties: { foo: 'bar' }, geometry: { type: 'MultiPoint', - coordinates: [[1, 1], [2, 2], [3, 3]] + coordinates: [ + [1, 1], + [2, 2], + [3, 3] + ] } }; const ctx = createMockCtx(); @@ -47,51 +85,76 @@ test('MultiPoint', () => { // Instance members assert.equal(multiPoint.ctx, ctx, 'multiPoint.ctx'); assert.equal(multiPoint.coordinates, undefined, 'no coordinates'); - assert.deepEqual(multiPoint.properties, { foo: 'bar' }, 'multiPoint.properties'); + assert.deepEqual( + multiPoint.properties, + { foo: 'bar' }, + 'multiPoint.properties' + ); assert.equal(multiPoint.id, 'wahoo', 'multiPoint.id'); assert.equal(multiPoint.type, 'MultiPoint', 'multiPoint.type'); assert.equal(multiPoint.features.length, 3, 'multiPoint.features'); // multiPoint.changed gets counted because it's used below - assert.equal(getPublicMemberKeys(multiPoint).length, 7, 'no unexpected instance members'); + assert.equal( + getPublicMemberKeys(multiPoint).length, + 7, + 'no unexpected instance members' + ); const pointA = multiPoint.features[0]; const pointB = multiPoint.features[1]; const pointC = multiPoint.features[2]; - assert.deepEqual(pointA, new Point(ctx, { - id: pointA.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [1, 1], - type: 'Point' - } - })); - assert.deepEqual(pointB, new Point(ctx, { - id: pointB.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [2, 2], - type: 'Point' - } - })); - assert.deepEqual(pointC, new Point(ctx, { - id: pointC.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [3, 3], - type: 'Point' - } - })); + assert.deepEqual( + pointA, + new Point(ctx, { + id: pointA.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [1, 1], + type: 'Point' + } + }) + ); + assert.deepEqual( + pointB, + new Point(ctx, { + id: pointB.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [2, 2], + type: 'Point' + } + }) + ); + assert.deepEqual( + pointC, + new Point(ctx, { + id: pointC.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [3, 3], + type: 'Point' + } + }) + ); const pointAGetCoordinateSpy = spy(pointA, 'getCoordinate'); const pointBGetCoordinateSpy = spy(pointB, 'getCoordinate'); const pointCGetCoordinateSpy = spy(pointC, 'getCoordinate'); const coordinate = multiPoint.getCoordinate('2'); - assert.equal(pointAGetCoordinateSpy.callCount, 0, 'point A getCoordinate not called'); - assert.equal(pointBGetCoordinateSpy.callCount, 0, 'point B getCoordinate not called'); + assert.equal( + pointAGetCoordinateSpy.callCount, + 0, + 'point A getCoordinate not called' + ); + assert.equal( + pointBGetCoordinateSpy.callCount, + 0, + 'point B getCoordinate not called' + ); assert.equal(pointCGetCoordinateSpy.callCount, 1, 'point C getCoordinate'); assert.deepEqual(coordinate, [3, 3], 'correct coordinate'); @@ -99,23 +162,50 @@ test('MultiPoint', () => { const pointBUpdateCoordinateSpy = spy(pointB, 'updateCoordinate'); const pointCUpdateCoordinateSpy = spy(pointC, 'updateCoordinate'); multiPoint.updateCoordinate('0', 99, 100); - assert.equal(pointAUpdateCoordinateSpy.callCount, 1, 'point A updateCoordinate'); - assert.equal(pointBUpdateCoordinateSpy.callCount, 0, 'point B updateCoordinate not called'); - assert.equal(pointCUpdateCoordinateSpy.callCount, 0, 'point C updateCoordinate not called'); - assert.deepEqual(multiPoint.getCoordinate('0'), [99, 100], 'correct coordinate'); + assert.equal( + pointAUpdateCoordinateSpy.callCount, + 1, + 'point A updateCoordinate' + ); + assert.equal( + pointBUpdateCoordinateSpy.callCount, + 0, + 'point B updateCoordinate not called' + ); + assert.equal( + pointCUpdateCoordinateSpy.callCount, + 0, + 'point C updateCoordinate not called' + ); + assert.deepEqual( + multiPoint.getCoordinate('0'), + [99, 100], + 'correct coordinate' + ); - assert.deepEqual(multiPoint.getCoordinates(), [[99, 100], [2, 2], [3, 3]], - 'getCoordinates returns the complete multi-coordinates'); + assert.deepEqual( + multiPoint.getCoordinates(), + [ + [99, 100], + [2, 2], + [3, 3] + ], + 'getCoordinates returns the complete multi-coordinates' + ); - multiPoint.setCoordinates([[6, 6], [7, 7]]); + multiPoint.setCoordinates([ + [6, 6], + [7, 7] + ]); assert.equal(changedSpy.callCount, 2, 'changed called by setCoordinates'); - assert.deepEqual(multiPoint.getCoordinates(), [[6, 6], [7, 7]]); + assert.deepEqual(multiPoint.getCoordinates(), [ + [6, 6], + [7, 7] + ]); assert.equal(multiPoint.isValid(), true, 'positive validation works'); multiPoint.setCoordinates([[1], []]); assert.equal(multiPoint.isValid(), false, 'negative validation works'); - - }); // Tests below less in depth becuase we know the @@ -128,8 +218,30 @@ test('MultiPolygon via MultiFeature', () => { geometry: { type: 'MultiPolygon', coordinates: [ - [[[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]]], - [[[2, 1], [6, 2], [8, 3], [2, 4], [2, 1]], [[1, 1], [2, 2], [3, 3], [1, 1]]] + [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ] + ], + [ + [ + [2, 1], + [6, 2], + [8, 3], + [2, 4], + [2, 1] + ], + [ + [1, 1], + [2, 2], + [3, 3], + [1, 1] + ] + ] ] } }; @@ -142,26 +254,52 @@ test('MultiPolygon via MultiFeature', () => { const polygonA = multiPolygon.features[0]; const polygonB = multiPolygon.features[1]; - assert.deepEqual(polygonA, new Polygon(ctx, { - id: polygonA.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [[[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]]], - type: 'Polygon' - } - })); - assert.deepEqual(polygonB, new Polygon(ctx, { - id: polygonB.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [[[2, 1], [6, 2], [8, 3], [2, 4], [2, 1]], [[1, 1], [2, 2], [3, 3], [1, 1]]], - type: 'Polygon' - } - })); - - + assert.deepEqual( + polygonA, + new Polygon(ctx, { + id: polygonA.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ] + ], + type: 'Polygon' + } + }) + ); + assert.deepEqual( + polygonB, + new Polygon(ctx, { + id: polygonB.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [ + [ + [2, 1], + [6, 2], + [8, 3], + [2, 4], + [2, 1] + ], + [ + [1, 1], + [2, 2], + [3, 3], + [1, 1] + ] + ], + type: 'Polygon' + } + }) + ); }); test('MultiLineString via MultiFeature', () => { @@ -172,8 +310,16 @@ test('MultiLineString via MultiFeature', () => { geometry: { type: 'MultiLineString', coordinates: [ - [[1, 1], [2, 2], [3, 3]], - [[4, 4], [5, 5], [6, 6]] + [ + [1, 1], + [2, 2], + [3, 3] + ], + [ + [4, 4], + [5, 5], + [6, 6] + ] ] } }; @@ -186,26 +332,38 @@ test('MultiLineString via MultiFeature', () => { const lineStringA = multiLineString.features[0]; const lineStringB = multiLineString.features[1]; - assert.deepEqual(lineStringA, new LineString(ctx, { - id: lineStringA.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [[1, 1], [2, 2], [3, 3]], - type: 'LineString' - } - })); - assert.deepEqual(lineStringB, new LineString(ctx, { - id: lineStringB.id, - type: 'Feature', - properties: {}, - geometry: { - coordinates: [[4, 4], [5, 5], [6, 6]], - type: 'LineString' - } - })); - - + assert.deepEqual( + lineStringA, + new LineString(ctx, { + id: lineStringA.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [ + [1, 1], + [2, 2], + [3, 3] + ], + type: 'LineString' + } + }) + ); + assert.deepEqual( + lineStringB, + new LineString(ctx, { + id: lineStringB.id, + type: 'Feature', + properties: {}, + geometry: { + coordinates: [ + [4, 4], + [5, 5], + [6, 6] + ], + type: 'LineString' + } + }) + ); }); test('Invalid MultiFeature type', () => { @@ -216,8 +374,16 @@ test('Invalid MultiFeature type', () => { geometry: { type: 'thing', coordinates: [ - [[1, 1], [2, 2], [3, 3]], - [[4, 4], [5, 5], [6, 6]] + [ + [1, 1], + [2, 2], + [3, 3] + ], + [ + [4, 4], + [5, 5], + [6, 6] + ] ] } }; diff --git a/test/options.test.js b/test/options.test.js index 3ea5215c..7c976f94 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -3,15 +3,17 @@ import fs from 'fs'; import path from 'path'; import test from 'node:test'; import assert from 'node:assert/strict'; -import {fileURLToPath} from 'url'; +import { fileURLToPath } from 'url'; import MapboxDraw from '../index'; import { modes } from '../src/modes/index'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); -const styleWithSourcesFixture = JSON.parse(fs.readFileSync(path.join(__dirname, './fixtures/style_with_sources.json'))); +const styleWithSourcesFixture = JSON.parse( + fs.readFileSync(path.join(__dirname, './fixtures/style_with_sources.json')) +); -test('Options test', async (t) => { +test('Options test', async t => { t.test('no options', () => { const Draw = new MapboxDraw(); const defaultOptions = { @@ -67,7 +69,7 @@ test('Options test', async (t) => { }); t.test('hide all controls', () => { - const Draw = new MapboxDraw({displayControlsDefault: false}); + const Draw = new MapboxDraw({ displayControlsDefault: false }); const defaultOptions = { defaultMode: 'simple_select', modes, @@ -93,7 +95,10 @@ test('Options test', async (t) => { }); await t.test('hide controls but show point', () => { - const Draw = new MapboxDraw({displayControlsDefault: false, controls: {point:true}}); + const Draw = new MapboxDraw({ + displayControlsDefault: false, + controls: { point: true } + }); const defaultOptions = { defaultMode: 'simple_select', modes, @@ -120,7 +125,7 @@ test('Options test', async (t) => { }); t.test('hide only point control', () => { - const Draw = new MapboxDraw({ controls: {point:false}}); + const Draw = new MapboxDraw({ controls: { point: false } }); const defaultOptions = { defaultMode: 'simple_select', modes, @@ -174,56 +179,61 @@ test('Options test', async (t) => { }); await t.test('custom styles', () => { - const Draw = new MapboxDraw({styles: [{ - 'id': 'custom-polygon', - 'type': 'fill', - 'filter': ['all', ['==', '$type', 'Polygon']], - 'paint': { - 'fill-color': '#fff' - } - }, { - 'id': 'custom-point', - 'type': 'circle', - 'filter': ['all', ['==', '$type', 'Point']], - 'paint': { - 'circle-color': '#fff' - } - }]}); + const Draw = new MapboxDraw({ + styles: [ + { + id: 'custom-polygon', + type: 'fill', + filter: ['all', ['==', '$type', 'Polygon']], + paint: { + 'fill-color': '#fff' + } + }, + { + id: 'custom-point', + type: 'circle', + filter: ['all', ['==', '$type', 'Point']], + paint: { + 'circle-color': '#fff' + } + } + ] + }); const styles = [ { - 'id': 'custom-polygon.cold', - 'source': 'mapbox-gl-draw-cold', - 'type': 'fill', - 'filter': ['all', ['==', '$type', 'Polygon']], - 'paint': { + id: 'custom-polygon.cold', + source: 'mapbox-gl-draw-cold', + type: 'fill', + filter: ['all', ['==', '$type', 'Polygon']], + paint: { 'fill-color': '#fff' } }, { - 'id': 'custom-point.cold', - 'source': 'mapbox-gl-draw-cold', - 'type': 'circle', - 'filter': ['all', ['==', '$type', 'Point']], - 'paint': { + id: 'custom-point.cold', + source: 'mapbox-gl-draw-cold', + type: 'circle', + filter: ['all', ['==', '$type', 'Point']], + paint: { 'circle-color': '#fff' } }, { - 'id': 'custom-polygon.hot', - 'source': 'mapbox-gl-draw-hot', - 'type': 'fill', - 'filter': ['all', ['==', '$type', 'Polygon']], - 'paint': { + id: 'custom-polygon.hot', + source: 'mapbox-gl-draw-hot', + type: 'fill', + filter: ['all', ['==', '$type', 'Polygon']], + paint: { 'fill-color': '#fff' } }, { - 'id': 'custom-point.hot', - 'source': 'mapbox-gl-draw-hot', - 'type': 'circle', - 'filter': ['all', ['==', '$type', 'Point']], - 'paint': { + id: 'custom-point.hot', + source: 'mapbox-gl-draw-hot', + type: 'circle', + filter: ['all', ['==', '$type', 'Point']], + paint: { 'circle-color': '#fff' } } diff --git a/test/point.test.js b/test/point.test.js index c513a264..42b86525 100644 --- a/test/point.test.js +++ b/test/point.test.js @@ -1,13 +1,13 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import Feature from '../src/feature_types/feature'; import Point from '../src/feature_types/point'; import MapboxDraw from '../index'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; import createMockCtx from './utils/create_mock_feature_context'; -import {drawGeometry} from './utils/draw_geometry'; +import { drawGeometry } from './utils/draw_geometry'; import createMap from './utils/create_map'; test('Point constructor and API', () => { @@ -17,17 +17,37 @@ test('Point constructor and API', () => { // Instance members assert.equal(point.ctx, ctx, 'point.ctx'); - assert.equal(point.coordinates, rawPoint.geometry.coordinates, 'point.coordinates'); + assert.equal( + point.coordinates, + rawPoint.geometry.coordinates, + 'point.coordinates' + ); assert.equal(point.properties, rawPoint.properties, 'point.properties'); assert.equal(point.id, rawPoint.id, 'point.id'); assert.equal(point.type, rawPoint.geometry.type, 'point.type'); - assert.equal(getPublicMemberKeys(point).length, 5, 'no unexpected instance members'); + assert.equal( + getPublicMemberKeys(point).length, + 5, + 'no unexpected instance members' + ); // Prototype members assert.equal(typeof Point.prototype.isValid, 'function', 'point.isValid'); - assert.equal(typeof Point.prototype.getCoordinate, 'function', 'point.getCoordinate'); - assert.equal(typeof Point.prototype.updateCoordinate, 'function', 'point.updateCoordinate'); - assert.equal(getPublicMemberKeys(Point.prototype).length, 3, 'no unexpected prototype members'); + assert.equal( + typeof Point.prototype.getCoordinate, + 'function', + 'point.getCoordinate' + ); + assert.equal( + typeof Point.prototype.updateCoordinate, + 'function', + 'point.updateCoordinate' + ); + assert.equal( + getPublicMemberKeys(Point.prototype).length, + 3, + 'no unexpected prototype members' + ); assert.ok(Point.prototype instanceof Feature, 'inherits from Feature'); }); @@ -40,12 +60,20 @@ test('Point#isValid', () => { const invalidRawPointA = createFeature('point'); invalidRawPointA.geometry.coordinates = [0, '1']; const invalidPointA = new Point(createMockCtx(), invalidRawPointA); - assert.equal(invalidPointA.isValid(), false, 'returns false with non-number coordinate'); + assert.equal( + invalidPointA.isValid(), + false, + 'returns false with non-number coordinate' + ); const invalidRawPointB = createFeature('point'); invalidRawPointB.geometry.coordinates = ['1', 0]; const invalidPointB = new Point(createMockCtx(), invalidRawPointA); - assert.equal(invalidPointB.isValid(), false, 'returns false with non-number coordinate, again'); + assert.equal( + invalidPointB.isValid(), + false, + 'returns false with non-number coordinate, again' + ); }); test('Point#updateCoordinate, Point#getCoordinate', () => { @@ -58,7 +86,11 @@ test('Point#updateCoordinate, Point#getCoordinate', () => { point.updateCoordinate(3, 4, 5); assert.equal(changedSpy.callCount, 1); - assert.deepEqual(point.getCoordinate(), [4, 5], 'handles 3 arguments, ignoring the first (as path)'); + assert.deepEqual( + point.getCoordinate(), + [4, 5], + 'handles 3 arguments, ignoring the first (as path)' + ); point.updateCoordinate(6, 7); assert.deepEqual(point.getCoordinate(), [6, 7], 'handles 2 arguments'); @@ -77,7 +109,11 @@ test('Point integration test', async () => { const feats = Draw.getAll().features; assert.equal(1, feats.length, 'only one'); assert.equal('Point', feats[0].geometry.type, 'of the right type'); - assert.deepEqual([10, 10], feats[0].geometry.coordinates, 'in the right spot'); + assert.deepEqual( + [10, 10], + feats[0].geometry.coordinates, + 'in the right spot' + ); Draw.onRemove(); }); diff --git a/test/polygon.test.js b/test/polygon.test.js index 4b7344e4..64d004a5 100644 --- a/test/polygon.test.js +++ b/test/polygon.test.js @@ -1,40 +1,94 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import Feature from '../src/feature_types/feature'; import Polygon from '../src/feature_types/polygon'; import MapboxDraw from '../index'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; import createMockCtx from './utils/create_mock_feature_context'; -import {drawGeometry} from './utils/draw_geometry'; +import { drawGeometry } from './utils/draw_geometry'; import createMap from './utils/create_map'; test('Polygon constructor and API', () => { const rawPolygon = createFeature('polygon'); - rawPolygon.geometry.coordinates = [[[1, 2], [3, 4], [5, 6], [7, 8], [1, 2]]]; + rawPolygon.geometry.coordinates = [ + [ + [1, 2], + [3, 4], + [5, 6], + [7, 8], + [1, 2] + ] + ]; const ctx = createMockCtx(); const polygon = new Polygon(ctx, rawPolygon); // Instance members assert.equal(polygon.ctx, ctx, 'polygon.ctx'); - assert.deepEqual(polygon.coordinates, [[[1, 2], [3, 4], [5, 6], [7, 8]]], - 'polygon.coordinates remove the last coordinate of the ring (which matches the first)'); + assert.deepEqual( + polygon.coordinates, + [ + [ + [1, 2], + [3, 4], + [5, 6], + [7, 8] + ] + ], + 'polygon.coordinates remove the last coordinate of the ring (which matches the first)' + ); assert.equal(polygon.properties, rawPolygon.properties, 'polygon.properties'); assert.equal(polygon.id, rawPolygon.id, 'polygon.id'); assert.equal(polygon.type, rawPolygon.geometry.type, 'polygon.type'); - assert.equal(getPublicMemberKeys(polygon).length, 5, 'no unexpected instance members'); + assert.equal( + getPublicMemberKeys(polygon).length, + 5, + 'no unexpected instance members' + ); // Prototype members assert.equal(typeof Polygon.prototype.isValid, 'function', 'polygon.isValid'); - assert.equal(typeof Polygon.prototype.incomingCoords, 'function', 'polygon.incomingCoords'); - assert.equal(typeof Polygon.prototype.setCoordinates, 'function', 'polygon.setCoordinates'); - assert.equal(typeof Polygon.prototype.addCoordinate, 'function', 'polygon.addCoordinate'); - assert.equal(typeof Polygon.prototype.getCoordinate, 'function', 'polygon.getCoordinate'); - assert.equal(typeof Polygon.prototype.getCoordinates, 'function', 'polygon.getCoordinates'); - assert.equal(typeof Polygon.prototype.removeCoordinate, 'function', 'polygon.removeCoordinate'); - assert.equal(typeof Polygon.prototype.updateCoordinate, 'function', 'polygon.updateCoordinate'); - assert.equal(getPublicMemberKeys(Polygon.prototype).length, 8, 'no unexpected prototype members'); + assert.equal( + typeof Polygon.prototype.incomingCoords, + 'function', + 'polygon.incomingCoords' + ); + assert.equal( + typeof Polygon.prototype.setCoordinates, + 'function', + 'polygon.setCoordinates' + ); + assert.equal( + typeof Polygon.prototype.addCoordinate, + 'function', + 'polygon.addCoordinate' + ); + assert.equal( + typeof Polygon.prototype.getCoordinate, + 'function', + 'polygon.getCoordinate' + ); + assert.equal( + typeof Polygon.prototype.getCoordinates, + 'function', + 'polygon.getCoordinates' + ); + assert.equal( + typeof Polygon.prototype.removeCoordinate, + 'function', + 'polygon.removeCoordinate' + ); + assert.equal( + typeof Polygon.prototype.updateCoordinate, + 'function', + 'polygon.updateCoordinate' + ); + assert.equal( + getPublicMemberKeys(Polygon.prototype).length, + 8, + 'no unexpected prototype members' + ); assert.ok(Polygon.prototype instanceof Feature, 'inherits from Feature'); }); @@ -45,9 +99,23 @@ test('Polygon#isValid', () => { assert.equal(validPolygon.isValid(), true, 'returns true for valid polygons'); const invalidRawPolygonA = createFeature('polygon'); - invalidRawPolygonA.geometry.coordinates = [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10]]]; + invalidRawPolygonA.geometry.coordinates = [ + [ + [1, 2], + [3, 4], + [5, 6] + ], + [ + [7, 8], + [9, 10] + ] + ]; const invalidPolygonA = new Polygon(createMockCtx(), invalidRawPolygonA); - assert.equal(invalidPolygonA.isValid(), false, 'returns false when a ring has fewer than 3 coordinates'); + assert.equal( + invalidPolygonA.isValid(), + false, + 'returns false when a ring has fewer than 3 coordinates' + ); }); test('Polygon#incomingCoords, Polygon#getCoordinates', () => { @@ -55,12 +123,38 @@ test('Polygon#incomingCoords, Polygon#getCoordinates', () => { const polygon = new Polygon(createMockCtx(), rawPolygon); const changedSpy = spy(polygon, 'changed'); - polygon.incomingCoords([[[1, 2], [3, 4], [5, 6], [1, 2]]]); + polygon.incomingCoords([ + [ + [1, 2], + [3, 4], + [5, 6], + [1, 2] + ] + ]); assert.equal(changedSpy.callCount, 1, 'calls polygon.changed'); - assert.deepEqual(polygon.coordinates, [[[1, 2], [3, 4], [5, 6]]], - 'sets new coordinates, eliminating last (closing) one'); - assert.deepEqual(polygon.getCoordinates(), [[[1, 2], [3, 4], [5, 6], [1, 2]]], - 'getCoordinates return closed rings'); + assert.deepEqual( + polygon.coordinates, + [ + [ + [1, 2], + [3, 4], + [5, 6] + ] + ], + 'sets new coordinates, eliminating last (closing) one' + ); + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [1, 2], + [3, 4], + [5, 6], + [1, 2] + ] + ], + 'getCoordinates return closed rings' + ); }); test('Polygon#setCoordinates', () => { @@ -68,17 +162,44 @@ test('Polygon#setCoordinates', () => { const polygon = new Polygon(createMockCtx(), rawPolygon); const changedSpy = spy(polygon, 'changed'); - polygon.setCoordinates([[[1, 2], [3, 4], [5, 6]]]); + polygon.setCoordinates([ + [ + [1, 2], + [3, 4], + [5, 6] + ] + ]); assert.equal(changedSpy.callCount, 1, 'polygon.changed called'); - assert.deepEqual(polygon.coordinates, [[[1, 2], [3, 4], [5, 6]]], - 'new coordinates set'); + assert.deepEqual( + polygon.coordinates, + [ + [ + [1, 2], + [3, 4], + [5, 6] + ] + ], + 'new coordinates set' + ); }); test('Polygon#addCoordinate, Polygon#removeCoordinate', () => { const rawPolygon = createFeature('polygon'); rawPolygon.geometry.coordinates = [ - [[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]], - [[2, 1], [3, 2], [4, 3], [5, 4], [2, 1]] + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ], + [ + [2, 1], + [3, 2], + [4, 3], + [5, 4], + [2, 1] + ] ]; const polygon = new Polygon(createMockCtx(), rawPolygon); const changedSpy = spy(polygon, 'changed'); @@ -86,42 +207,119 @@ test('Polygon#addCoordinate, Polygon#removeCoordinate', () => { changedSpy.resetHistory(); polygon.addCoordinate('1.1', 99, 100); assert.equal(changedSpy.callCount, 1, 'polygon.changed was called'); - assert.deepEqual(polygon.getCoordinates(), [ - [[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]], - [[2, 1], [99, 100], [3, 2], [4, 3], [5, 4], [2, 1]] - ], 'new coordinate added at right place in right ring'); + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ], + [ + [2, 1], + [99, 100], + [3, 2], + [4, 3], + [5, 4], + [2, 1] + ] + ], + 'new coordinate added at right place in right ring' + ); changedSpy.resetHistory(); polygon.removeCoordinate('0.3'); assert.equal(changedSpy.callCount, 1, 'polygon.changed was called'); - assert.deepEqual(polygon.getCoordinates(), [ - [[1, 1], [2, 2], [3, 3], [1, 1]], - [[2, 1], [99, 100], [3, 2], [4, 3], [5, 4], [2, 1]] - ], 'coordinate removed at right place in right ring'); + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [1, 1], + [2, 2], + [3, 3], + [1, 1] + ], + [ + [2, 1], + [99, 100], + [3, 2], + [4, 3], + [5, 4], + [2, 1] + ] + ], + 'coordinate removed at right place in right ring' + ); }); test('Polygon#updateCoordinate, Polygon#getCoordinate', () => { const rawPolygon = createFeature('polygon'); rawPolygon.geometry.coordinates = [ - [[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]], - [[2, 1], [3, 2], [4, 3], [5, 4], [2, 1]] + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ], + [ + [2, 1], + [3, 2], + [4, 3], + [5, 4], + [2, 1] + ] ]; const polygon = new Polygon(createMockCtx(), rawPolygon); const changedSpy = spy(polygon, 'changed'); changedSpy.resetHistory(); - assert.deepEqual(polygon.getCoordinate('1.2'), [4, 3], 'getCoordinate returns right one'); + assert.deepEqual( + polygon.getCoordinate('1.2'), + [4, 3], + 'getCoordinate returns right one' + ); polygon.updateCoordinate('1.2', 99, 100); assert.equal(changedSpy.callCount, 1, 'polygon.changed was called'); - assert.deepEqual(polygon.getCoordinates(), [ - [[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]], - [[2, 1], [3, 2], [99, 100], [5, 4], [2, 1]] - ], 'correct coordinate was changed'); - assert.deepEqual(polygon.getCoordinate('1.2'), [99, 100], 'getCoordinate still works'); + assert.deepEqual( + polygon.getCoordinates(), + [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ], + [ + [2, 1], + [3, 2], + [99, 100], + [5, 4], + [2, 1] + ] + ], + 'correct coordinate was changed' + ); + assert.deepEqual( + polygon.getCoordinate('1.2'), + [99, 100], + 'getCoordinate still works' + ); }); test('Polygon integration', async () => { - const polygonCoordinates = [[[0, 0], [30, 15], [32, 35], [15, 30], [0, 0]]]; + const polygonCoordinates = [ + [ + [0, 0], + [30, 15], + [32, 35], + [15, 30], + [0, 0] + ] + ]; const map = createMap(); const Draw = new MapboxDraw(); map.addControl(Draw); @@ -133,7 +331,15 @@ test('Polygon integration', async () => { const feats = Draw.getAll().features; assert.equal(1, feats.length, 'only one'); assert.equal('Polygon', feats[0].geometry.type, 'of the right type'); - assert.equal(feats[0].geometry.coordinates[0].length, polygonCoordinates[0].length, 'right number of points'); - assert.deepEqual(feats[0].geometry.coordinates, polygonCoordinates, 'in the right spot'); + assert.equal( + feats[0].geometry.coordinates[0].length, + polygonCoordinates[0].length, + 'right number of points' + ); + assert.deepEqual( + feats[0].geometry.coordinates, + polygonCoordinates, + 'in the right spot' + ); Draw.onRemove(); }); diff --git a/test/simple_select.test.js b/test/simple_select.test.js index f0e0edaa..8b757cff 100644 --- a/test/simple_select.test.js +++ b/test/simple_select.test.js @@ -2,10 +2,10 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import createSyntheticEvent from 'synthetic-dom-events'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import MapboxDraw from '../index'; -import {setupAfterNextRender} from './utils/after_next_render'; +import { setupAfterNextRender } from './utils/after_next_render'; import makeMouseEvent from './utils/make_mouse_event'; import mouseClick from './utils/mouse_click'; import makeTouchEvent from './utils/make_touch_event'; @@ -14,7 +14,7 @@ import createMap from './utils/create_map'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context'; import { TAP_INTERVAL, TAP_TOLERANCE } from '../src/lib/is_tap'; -test('simple_select', async (t) => { +test('simple_select', async t => { const context = createMockDrawModeContext(); const mapContainer = document.createElement('div'); document.body.appendChild(mapContainer); @@ -31,12 +31,12 @@ test('simple_select', async (t) => { const afterNextRender = setupAfterNextRender(map); - const cleanUp = function() { + const cleanUp = function () { Draw.deleteAll(); map.fire.resetHistory(); }; - const getFireArgs = function() { + const getFireArgs = function () { const args = []; for (let i = 0; i < map.fire.callCount; i++) { args.push(map.fire.getCall(i).args); @@ -45,7 +45,7 @@ test('simple_select', async (t) => { }; t.test('simple_select - init map for tests', () => { - const done = function() { + const done = function () { map.off('load', done); }; @@ -56,7 +56,6 @@ test('simple_select', async (t) => { } }); - await t.test('simple_select - box select', async () => { Draw.add(getGeoJSON('negativePoint')); const id = Draw.add(getGeoJSON('point'))[0]; @@ -67,31 +66,69 @@ test('simple_select', async (t) => { map.dragPan.disable.resetHistory(); map.fire('mousedown', makeMouseEvent(0, 0, { shiftKey: true })); assert.equal(map.dragPan.disable.callCount, 1, 'disable dragPan'); - map.fire('mousemove', makeMouseEvent(15, 15, { - shiftKey: true, - buttons: 1 - })); + map.fire( + 'mousemove', + makeMouseEvent(15, 15, { + shiftKey: true, + buttons: 1 + }) + ); await afterNextRender(); - assert.equal(map.getContainer().className.indexOf('mouse-add') > -1, true, 'mouse-add class has been set'); + assert.equal( + map.getContainer().className.indexOf('mouse-add') > -1, + true, + 'mouse-add class has been set' + ); map.fire('mouseup', makeMouseEvent(15, 15, { shiftKey: true })); await afterNextRender(); - assert.equal(map.getContainer().className.indexOf('mouse-move') > -1, true, 'mouse-move class has been set'); + assert.equal( + map.getContainer().className.indexOf('mouse-move') > -1, + true, + 'mouse-move class has been set' + ); const fireArgs = getFireArgs(); const args = fireArgs.filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); if (args.length > 0) { - assert.equal(args[0][1].features.length, 1, 'should have one feature selected'); - assert.equal(args[0][1].features[0].id, id, 'should be the feature we expect to be selected'); + assert.equal( + args[0][1].features.length, + 1, + 'should have one feature selected' + ); + assert.equal( + args[0][1].features[0].id, + id, + 'should be the feature we expect to be selected' + ); } const actionableArgs = fireArgs.filter(arg => arg[0] === 'draw.actionable'); - assert.ok(actionableArgs.length > 0, 'should have fired an actionable event'); + assert.ok( + actionableArgs.length > 0, + 'should have fired an actionable event' + ); if (actionableArgs.length > 0) { const actionable = actionableArgs[actionableArgs.length - 1][1]; - assert.equal(actionable.actions.combineFeatures, false, 'should fire correct combine actionable'); - assert.equal(actionable.actions.uncombineFeatures, false, 'should fire correct uncombine actionable'); - assert.equal(actionable.actions.trash, true, 'should fire correct trash actionable'); + assert.equal( + actionable.actions.combineFeatures, + false, + 'should fire correct combine actionable' + ); + assert.equal( + actionable.actions.uncombineFeatures, + false, + 'should fire correct uncombine actionable' + ); + assert.equal( + actionable.actions.trash, + true, + 'should fire correct trash actionable' + ); } cleanUp(); @@ -111,10 +148,13 @@ test('simple_select', async (t) => { await afterNextRender(); map.dragPan.enable.resetHistory(); map.fire('mousedown', makeMouseEvent(0, 0, { shiftKey: true })); - map.fire('mousemove', makeMouseEvent(15, 15, { - shiftKey: true, - buttons: 1 - })); + map.fire( + 'mousemove', + makeMouseEvent(15, 15, { + shiftKey: true, + buttons: 1 + }) + ); map.fire('mouseup', makeMouseEvent(15, 15, { shiftKey: true })); await afterNextRender(); @@ -122,16 +162,35 @@ test('simple_select', async (t) => { const args = fireArgs.filter(arg => arg[0] === 'draw.selectionchange'); assert.equal(args.length, 1, 'should have one and only one select event'); if (args.length > 0) { - assert.equal(args[0][1].features.length, ids.length, 'should have all features selected'); + assert.equal( + args[0][1].features.length, + ids.length, + 'should have all features selected' + ); } const actionableArgs = fireArgs.filter(arg => arg[0] === 'draw.actionable'); - assert.ok(actionableArgs.length > 0, 'should have fired an actionable event'); + assert.ok( + actionableArgs.length > 0, + 'should have fired an actionable event' + ); if (actionableArgs.length > 0) { const actionable = actionableArgs[actionableArgs.length - 1][1]; - assert.equal(actionable.actions.combineFeatures, true, 'should fire correct combine actionable'); - assert.equal(actionable.actions.uncombineFeatures, false, 'should fire correct uncombine actionable'); - assert.equal(actionable.actions.trash, true, 'should fire correct trash actionable'); + assert.equal( + actionable.actions.combineFeatures, + true, + 'should fire correct combine actionable' + ); + assert.equal( + actionable.actions.uncombineFeatures, + false, + 'should fire correct uncombine actionable' + ); + assert.equal( + actionable.actions.trash, + true, + 'should fire correct trash actionable' + ); } cleanUp(); @@ -143,14 +202,21 @@ test('simple_select', async (t) => { await afterNextRender(); map.fire('mousedown', makeMouseEvent(0, 0, { shiftKey: true })); - map.fire('mousemove', makeMouseEvent(-15, -15, { - shiftKey: true, - buttons: 1 - })); + map.fire( + 'mousemove', + makeMouseEvent(-15, -15, { + shiftKey: true, + buttons: 1 + }) + ); map.fire('mouseup', makeMouseEvent(-15, -15, { shiftKey: true })); await afterNextRender(); - assert.equal(getFireArgs().filter(arg => arg[0] === 'draw.selectionchange').length, 0, 'there should be no draw.selectionchange event'); + assert.equal( + getFireArgs().filter(arg => arg[0] === 'draw.selectionchange').length, + 0, + 'there should be no draw.selectionchange event' + ); cleanUp(); }); @@ -166,7 +232,11 @@ test('simple_select', async (t) => { map.fire('mouseup', makeMouseEvent(15, 15, { shiftKey: true })); await afterNextRender(); - assert.equal(getFireArgs().filter(arg => arg[0] === 'draw.selectionchange').length, 0, 'there should be no draw.selectionchange event'); + assert.equal( + getFireArgs().filter(arg => arg[0] === 'draw.selectionchange').length, + 0, + 'there should be no draw.selectionchange event' + ); cleanUp(); }); @@ -181,9 +251,17 @@ test('simple_select', async (t) => { await afterNextRender(); const args = getFireArgs().filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); if (args.length > 0) { - assert.equal(args[0][1].features.length, 0, 'should have no features selected'); + assert.equal( + args[0][1].features.length, + 0, + 'should have no features selected' + ); } cleanUp(); @@ -200,13 +278,29 @@ test('simple_select', async (t) => { map.fire('mouseup', makeMouseEvent(50, 30)); await afterNextRender(); - assert.equal(map.doubleClickZoom.disable.callCount, 1, 'disable doubleClickZoom'); + assert.equal( + map.doubleClickZoom.disable.callCount, + 1, + 'disable doubleClickZoom' + ); let args = getFireArgs(); args = args.filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); if (args.length > 0) { - assert.equal(args[0][1].features.length, 1, 'should have only one feature selected'); - assert.equal(args[0][1].features[0].id, id, 'should be the feature we expect to be selected'); + assert.equal( + args[0][1].features.length, + 1, + 'should have only one feature selected' + ); + assert.equal( + args[0][1].features[0].id, + id, + 'should be the feature we expect to be selected' + ); } cleanUp(); }); @@ -224,36 +318,67 @@ test('simple_select', async (t) => { await afterNextRender(); let args = getFireArgs(); args = args.filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); if (args.length > 0) { - assert.equal(args[0][1].features.length, 1, 'should have only one feature selected'); - assert.equal(args[0][1].features[0].id, id, 'should be the feature we expect to be selected'); + assert.equal( + args[0][1].features.length, + 1, + 'should have only one feature selected' + ); + assert.equal( + args[0][1].features[0].id, + id, + 'should be the feature we expect to be selected' + ); } cleanUp(); }); - await t.test('simple_select - click on a selected feature with shift down', async () => { - const id = Draw.add(getGeoJSON('polygon'))[0]; - Draw.changeMode('simple_select', { featureIds: [id] }); - - await afterNextRender(); - map.fire.resetHistory(); - map.doubleClickZoom.disable.resetHistory(); - map.fire('mousedown', makeMouseEvent(50, 30, { shiftKey: true })); - map.fire('mouseup', makeMouseEvent(50, 30, { shiftKey: true })); - - await afterNextRender(); - assert.equal(map.doubleClickZoom.disable.callCount, 1, 'disable doubleClickZoom'); - assert.equal(map.getContainer().className.indexOf('mouse-pointer') > -1, true, 'mouse-pointer class has been set'); - let args = getFireArgs(); - args = args.filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); - if (args.length > 0) { - assert.equal(args[0][1].features.length, 0, 'should have no features selected'); + await t.test( + 'simple_select - click on a selected feature with shift down', + async () => { + const id = Draw.add(getGeoJSON('polygon'))[0]; + Draw.changeMode('simple_select', { featureIds: [id] }); + + await afterNextRender(); + map.fire.resetHistory(); + map.doubleClickZoom.disable.resetHistory(); + map.fire('mousedown', makeMouseEvent(50, 30, { shiftKey: true })); + map.fire('mouseup', makeMouseEvent(50, 30, { shiftKey: true })); + + await afterNextRender(); + assert.equal( + map.doubleClickZoom.disable.callCount, + 1, + 'disable doubleClickZoom' + ); + assert.equal( + map.getContainer().className.indexOf('mouse-pointer') > -1, + true, + 'mouse-pointer class has been set' + ); + let args = getFireArgs(); + args = args.filter(arg => arg[0] === 'draw.selectionchange'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); + if (args.length > 0) { + assert.equal( + args[0][1].features.length, + 0, + 'should have no features selected' + ); + } + + cleanUp(); } - - cleanUp(); - }); + ); await t.test('simple_select - delete selected features', async () => { const id = Draw.add(getGeoJSON('polygon'))[0]; @@ -263,159 +388,296 @@ test('simple_select', async (t) => { await afterNextRender(); let args = getFireArgs(); args = args.filter(arg => arg[0] === 'draw.delete'); - assert.equal(args.length, 1, 'should have one and only one draw.delete event'); - assert.equal(args[0][1].features.length, 1, 'should delete only one feature'); - assert.equal(args[0][1].features[0].id, id, 'should delete the feature we expect it to delete'); + assert.equal( + args.length, + 1, + 'should have one and only one draw.delete event' + ); + assert.equal( + args[0][1].features.length, + 1, + 'should delete only one feature' + ); + assert.equal( + args[0][1].features[0].id, + id, + 'should delete the feature we expect it to delete' + ); const selectedFeatures = Draw.getSelectedIds(); - assert.equal(selectedFeatures.length, 0, 'nothing should be selected anymore'); + assert.equal( + selectedFeatures.length, + 0, + 'nothing should be selected anymore' + ); cleanUp(); }); - await t.test('simple_select - click on a selected feature with shift up to enter direct_select', async () => { - Draw.deleteAll(); - const id = Draw.add(getGeoJSON('polygon'))[0]; - Draw.changeMode('simple_select', { featureIds: [id] }); - - await afterNextRender(); - map.doubleClickZoom.enable.resetHistory(); - map.fire.resetHistory(); - map.doubleClickZoom.disable.resetHistory(); - map.fire('mousedown', makeMouseEvent(50, 30, false)); - map.fire('mouseup', makeMouseEvent(50, 30, false)); - - await afterNextRender(); - assert.equal(map.doubleClickZoom.disable.callCount, 2, 'disable doubleClickZoom. Once for click, once for direct_select'); - assert.equal(map.doubleClickZoom.enable.callCount, 1, 'double click zoom has been enabled'); - assert.equal(map.getContainer().className.indexOf('mouse-move') > -1, true, 'mouse-move class has been set'); - let args = getFireArgs(); - args = args.filter(arg => arg[0] === 'draw.modechange'); - assert.equal(args.length, 1, 'should have one and only one modechange event'); - if (args.length > 0) { - assert.equal(args[0][1].mode, 'direct_select', 'should change to direct select'); + await t.test( + 'simple_select - click on a selected feature with shift up to enter direct_select', + async () => { + Draw.deleteAll(); + const id = Draw.add(getGeoJSON('polygon'))[0]; + Draw.changeMode('simple_select', { featureIds: [id] }); + + await afterNextRender(); + map.doubleClickZoom.enable.resetHistory(); + map.fire.resetHistory(); + map.doubleClickZoom.disable.resetHistory(); + map.fire('mousedown', makeMouseEvent(50, 30, false)); + map.fire('mouseup', makeMouseEvent(50, 30, false)); + + await afterNextRender(); + assert.equal( + map.doubleClickZoom.disable.callCount, + 2, + 'disable doubleClickZoom. Once for click, once for direct_select' + ); + assert.equal( + map.doubleClickZoom.enable.callCount, + 1, + 'double click zoom has been enabled' + ); + assert.equal( + map.getContainer().className.indexOf('mouse-move') > -1, + true, + 'mouse-move class has been set' + ); + let args = getFireArgs(); + args = args.filter(arg => arg[0] === 'draw.modechange'); + assert.equal( + args.length, + 1, + 'should have one and only one modechange event' + ); + if (args.length > 0) { + assert.equal( + args[0][1].mode, + 'direct_select', + 'should change to direct select' + ); + } + cleanUp(); } - cleanUp(); - }); - - await t.test('simple_select - click on a vertex to enter direct_select', async () => { - const id = Draw.add(getGeoJSON('polygon'))[0]; - Draw.changeMode('simple_select', { featureIds: [id] }); - - const clickPosition = getGeoJSON('polygon').geometry.coordinates[0][0]; - - await afterNextRender(); - map.doubleClickZoom.enable.resetHistory(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(clickPosition[0], clickPosition[1])); - map.fire('mouseup', makeMouseEvent(clickPosition[0], clickPosition[1])); - - await afterNextRender(); - assert.equal(map.doubleClickZoom.enable.callCount, 1, 'double click zoom has been enabled'); - let args = getFireArgs(); - args = args.filter(arg => arg[0] === 'draw.modechange'); - assert.equal(args.length, 1, 'should have one and only one modechange event'); - if (args.length > 0) { - assert.equal(args[0][1].mode, 'direct_select', 'should change to direct select'); + ); + + await t.test( + 'simple_select - click on a vertex to enter direct_select', + async () => { + const id = Draw.add(getGeoJSON('polygon'))[0]; + Draw.changeMode('simple_select', { featureIds: [id] }); + + const clickPosition = getGeoJSON('polygon').geometry.coordinates[0][0]; + + await afterNextRender(); + map.doubleClickZoom.enable.resetHistory(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(clickPosition[0], clickPosition[1])); + map.fire('mouseup', makeMouseEvent(clickPosition[0], clickPosition[1])); + + await afterNextRender(); + assert.equal( + map.doubleClickZoom.enable.callCount, + 1, + 'double click zoom has been enabled' + ); + let args = getFireArgs(); + args = args.filter(arg => arg[0] === 'draw.modechange'); + assert.equal( + args.length, + 1, + 'should have one and only one modechange event' + ); + if (args.length > 0) { + assert.equal( + args[0][1].mode, + 'direct_select', + 'should change to direct select' + ); + } + cleanUp(); } - cleanUp(); - }); - - await t.test('simple_select - tap on a vertex to enter direct_select', async () => { - const id = Draw.add(getGeoJSON('polygon'))[0]; - Draw.changeMode('simple_select', { featureIds: [id] }); - - const tapPosition = getGeoJSON('polygon').geometry.coordinates[0][0]; - - await afterNextRender(); - map.doubleClickZoom.enable.resetHistory(); - map.fire.resetHistory(); - map.fire('touchstart', makeTouchEvent(tapPosition[0], tapPosition[1])); - map.fire('touchend', makeTouchEvent(tapPosition[0], tapPosition[1])); - - await afterNextRender(); - let args = getFireArgs(); - args = args.filter(arg => arg[0] === 'draw.modechange'); - assert.equal(args.length, 1, 'should have one and only one modechange event'); - if (args.length > 0) { - assert.equal(args[0][1].mode, 'direct_select', 'should change to direct select'); + ); + + await t.test( + 'simple_select - tap on a vertex to enter direct_select', + async () => { + const id = Draw.add(getGeoJSON('polygon'))[0]; + Draw.changeMode('simple_select', { featureIds: [id] }); + + const tapPosition = getGeoJSON('polygon').geometry.coordinates[0][0]; + + await afterNextRender(); + map.doubleClickZoom.enable.resetHistory(); + map.fire.resetHistory(); + map.fire('touchstart', makeTouchEvent(tapPosition[0], tapPosition[1])); + map.fire('touchend', makeTouchEvent(tapPosition[0], tapPosition[1])); + + await afterNextRender(); + let args = getFireArgs(); + args = args.filter(arg => arg[0] === 'draw.modechange'); + assert.equal( + args.length, + 1, + 'should have one and only one modechange event' + ); + if (args.length > 0) { + assert.equal( + args[0][1].mode, + 'direct_select', + 'should change to direct select' + ); + } + cleanUp(); } - cleanUp(); - }); - - await t.test('simple_select - tap dragging fires an update event', async () => { - const point = getGeoJSON('point'); - const pointId = Draw.add(point)[0]; - const translatePosition = (point, d) => [point[0] + d, point[1] + d]; - - const startPosition = point.geometry.coordinates; - const endPosition = translatePosition(startPosition, 25); - - Draw.changeMode('simple_select', { - featureIds: [pointId] - }); - - await afterNextRender(); - map.fire.resetHistory(); - map.fire('touchstart', makeTouchEvent(...startPosition)); - map.fire('touchmove', makeTouchEvent(...translatePosition(startPosition, 15))); - map.fire('touchmove', makeTouchEvent(...endPosition)); - map.fire('touchend', makeTouchEvent(...endPosition)); - - const movedPoint = Draw.get(pointId); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 1, 'draw.update called once'); - assert.equal(movedPoint.geometry.coordinates[0], endPosition[0], 'point lng moved to touchend location'); - assert.equal(movedPoint.geometry.coordinates[1], endPosition[1], 'point lat moved to touchend location'); - }); - - await t.test('simple_select - click on a deselected feature with shift down while having another feature selected', async () => { - const pointId = Draw.add(getGeoJSON('point'))[0]; - const id = Draw.add(getGeoJSON('polygon'))[0]; - Draw.changeMode('simple_select', { featureIds: [pointId] }); - - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(50, 30, { shiftKey: true })); - map.fire('mouseup', makeMouseEvent(50, 30, { shiftKey: true })); - - await afterNextRender(); - assert.equal(map.getContainer().className.indexOf('mouse-move') > -1, true, 'mouse-move class has been set'); - assert.equal(Draw.getSelectedIds().indexOf(pointId) !== -1, true, 'point is still selected'); - assert.equal(Draw.getSelectedIds().indexOf(id) !== -1, true, 'polygon is now selected'); - let args = getFireArgs(); - args = args.filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); - if (args.length > 0) { - assert.equal(args[0][1].features.length, 2, 'should have two features selected'); - assert.equal(args[0][1].features[0].id, pointId, 'selection includes point'); - assert.equal(args[0][1].features[1].id, id, 'selection includes polygon'); + ); + + await t.test( + 'simple_select - tap dragging fires an update event', + async () => { + const point = getGeoJSON('point'); + const pointId = Draw.add(point)[0]; + const translatePosition = (point, d) => [point[0] + d, point[1] + d]; + + const startPosition = point.geometry.coordinates; + const endPosition = translatePosition(startPosition, 25); + + Draw.changeMode('simple_select', { + featureIds: [pointId] + }); + + await afterNextRender(); + map.fire.resetHistory(); + map.fire('touchstart', makeTouchEvent(...startPosition)); + map.fire( + 'touchmove', + makeTouchEvent(...translatePosition(startPosition, 15)) + ); + map.fire('touchmove', makeTouchEvent(...endPosition)); + map.fire('touchend', makeTouchEvent(...endPosition)); + + const movedPoint = Draw.get(pointId); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 1, 'draw.update called once'); + assert.equal( + movedPoint.geometry.coordinates[0], + endPosition[0], + 'point lng moved to touchend location' + ); + assert.equal( + movedPoint.geometry.coordinates[1], + endPosition[1], + 'point lat moved to touchend location' + ); } - cleanUp(); - }); - - await t.test('simple_select - click on a deselected feature with shift up, while having another feature selected', async () => { - const pointId = Draw.add(getGeoJSON('point'))[0]; - const id = Draw.add(getGeoJSON('polygon'))[0]; - Draw.changeMode('simple_select', { featureIds: [pointId] }); - - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(50, 30, false)); - map.fire('mouseup', makeMouseEvent(50, 30, false)); - - await afterNextRender(); - assert.equal(map.getContainer().className.indexOf('mouse-move') > -1, true, 'mouse-move class has been set'); - assert.equal(Draw.getSelectedIds().indexOf(pointId) === -1, true, 'point is no longer selected'); - assert.equal(Draw.getSelectedIds().indexOf(id) !== -1, true, 'polygon is now selected'); - let args = getFireArgs(); - args = args.filter(arg => arg[0] === 'draw.selectionchange'); - assert.equal(args.length, 1, 'should have one and only one selectionchange event'); - if (args.length > 0) { - assert.equal(args[0][1].features.length, 1, 'should have only one feature selected'); - assert.equal(args[0][1].features[0].id, id, 'should be the feature we expect to be selected'); + ); + + await t.test( + 'simple_select - click on a deselected feature with shift down while having another feature selected', + async () => { + const pointId = Draw.add(getGeoJSON('point'))[0]; + const id = Draw.add(getGeoJSON('polygon'))[0]; + Draw.changeMode('simple_select', { featureIds: [pointId] }); + + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(50, 30, { shiftKey: true })); + map.fire('mouseup', makeMouseEvent(50, 30, { shiftKey: true })); + + await afterNextRender(); + assert.equal( + map.getContainer().className.indexOf('mouse-move') > -1, + true, + 'mouse-move class has been set' + ); + assert.equal( + Draw.getSelectedIds().indexOf(pointId) !== -1, + true, + 'point is still selected' + ); + assert.equal( + Draw.getSelectedIds().indexOf(id) !== -1, + true, + 'polygon is now selected' + ); + let args = getFireArgs(); + args = args.filter(arg => arg[0] === 'draw.selectionchange'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); + if (args.length > 0) { + assert.equal( + args[0][1].features.length, + 2, + 'should have two features selected' + ); + assert.equal( + args[0][1].features[0].id, + pointId, + 'selection includes point' + ); + assert.equal( + args[0][1].features[1].id, + id, + 'selection includes polygon' + ); + } + cleanUp(); } - cleanUp(); - }); + ); + + await t.test( + 'simple_select - click on a deselected feature with shift up, while having another feature selected', + async () => { + const pointId = Draw.add(getGeoJSON('point'))[0]; + const id = Draw.add(getGeoJSON('polygon'))[0]; + Draw.changeMode('simple_select', { featureIds: [pointId] }); + + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(50, 30, false)); + map.fire('mouseup', makeMouseEvent(50, 30, false)); + + await afterNextRender(); + assert.equal( + map.getContainer().className.indexOf('mouse-move') > -1, + true, + 'mouse-move class has been set' + ); + assert.equal( + Draw.getSelectedIds().indexOf(pointId) === -1, + true, + 'point is no longer selected' + ); + assert.equal( + Draw.getSelectedIds().indexOf(id) !== -1, + true, + 'polygon is now selected' + ); + let args = getFireArgs(); + args = args.filter(arg => arg[0] === 'draw.selectionchange'); + assert.equal( + args.length, + 1, + 'should have one and only one selectionchange event' + ); + if (args.length > 0) { + assert.equal( + args[0][1].features.length, + 1, + 'should have only one feature selected' + ); + assert.equal( + args[0][1].features[0].id, + id, + 'should be the feature we expect to be selected' + ); + } + cleanUp(); + } + ); await t.test('simple_select - drag every feature type', async () => { const pointId = Draw.add(getGeoJSON('point'))[0]; @@ -425,121 +687,293 @@ test('simple_select', async (t) => { const polygonId = Draw.add(getGeoJSON('polygon'))[0]; const multiPolygonId = Draw.add(getGeoJSON('multiPolygon'))[0]; - const countPositions = function(feature) { + const countPositions = function (feature) { return feature.geometry.coordinates.join(',').split(',').length; }; const startPosition = getGeoJSON('point').geometry.coordinates; Draw.changeMode('simple_select', { - featureIds: [pointId, multiPointId, lineStringId, multiLineStringId, polygonId, multiPolygonId] + featureIds: [ + pointId, + multiPointId, + lineStringId, + multiLineStringId, + polygonId, + multiPolygonId + ] }); await afterNextRender(); map.fire.resetHistory(); map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { buttons: 1 })); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25, { buttons: 1 })); - map.fire('mouseup', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25)); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { + buttons: 1 + }) + ); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25, { + buttons: 1 + }) + ); + map.fire( + 'mouseup', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25) + ); const movedPoint = Draw.get(pointId); - assert.equal(movedPoint.geometry.coordinates[0], startPosition[0] + 25, 'point lng moved'); - assert.equal(movedPoint.geometry.coordinates[1], startPosition[1] + 25, 'point lat moved'); - assert.equal(countPositions(movedPoint), countPositions(getGeoJSON('point')), 'point has same number of postions'); + assert.equal( + movedPoint.geometry.coordinates[0], + startPosition[0] + 25, + 'point lng moved' + ); + assert.equal( + movedPoint.geometry.coordinates[1], + startPosition[1] + 25, + 'point lat moved' + ); + assert.equal( + countPositions(movedPoint), + countPositions(getGeoJSON('point')), + 'point has same number of postions' + ); const movedMultiPoint = Draw.get(multiPointId); - assert.equal(movedMultiPoint.geometry.coordinates[0][0], getGeoJSON('multiPoint').geometry.coordinates[0][0] + 25, 'multipoint lng moved'); - assert.equal(movedMultiPoint.geometry.coordinates[0][1], getGeoJSON('multiPoint').geometry.coordinates[0][1] + 25, 'multipoint lat moved'); - assert.equal(countPositions(movedMultiPoint), countPositions(getGeoJSON('multiPoint')), 'multiPoint has same number of postions'); + assert.equal( + movedMultiPoint.geometry.coordinates[0][0], + getGeoJSON('multiPoint').geometry.coordinates[0][0] + 25, + 'multipoint lng moved' + ); + assert.equal( + movedMultiPoint.geometry.coordinates[0][1], + getGeoJSON('multiPoint').geometry.coordinates[0][1] + 25, + 'multipoint lat moved' + ); + assert.equal( + countPositions(movedMultiPoint), + countPositions(getGeoJSON('multiPoint')), + 'multiPoint has same number of postions' + ); const movedLineString = Draw.get(lineStringId); - assert.equal(movedLineString.geometry.coordinates[0][0], getGeoJSON('line').geometry.coordinates[0][0] + 25, 'line lng moved'); - assert.equal(movedLineString.geometry.coordinates[0][1], getGeoJSON('line').geometry.coordinates[0][1] + 25, 'line lat moved'); - assert.equal(countPositions(movedLineString), countPositions(getGeoJSON('line')), 'line has same number of postions'); + assert.equal( + movedLineString.geometry.coordinates[0][0], + getGeoJSON('line').geometry.coordinates[0][0] + 25, + 'line lng moved' + ); + assert.equal( + movedLineString.geometry.coordinates[0][1], + getGeoJSON('line').geometry.coordinates[0][1] + 25, + 'line lat moved' + ); + assert.equal( + countPositions(movedLineString), + countPositions(getGeoJSON('line')), + 'line has same number of postions' + ); const movedMultiLineString = Draw.get(multiLineStringId); - assert.equal(movedMultiLineString.geometry.coordinates[0][0][0], getGeoJSON('multiLineString').geometry.coordinates[0][0][0] + 25, 'multiLineString lng moved'); - assert.equal(movedMultiLineString.geometry.coordinates[0][0][1], getGeoJSON('multiLineString').geometry.coordinates[0][0][1] + 25, 'multiLineString lat moved'); - assert.equal(countPositions(movedMultiLineString), countPositions(getGeoJSON('multiLineString')), 'multiLineString has same number of postions'); + assert.equal( + movedMultiLineString.geometry.coordinates[0][0][0], + getGeoJSON('multiLineString').geometry.coordinates[0][0][0] + 25, + 'multiLineString lng moved' + ); + assert.equal( + movedMultiLineString.geometry.coordinates[0][0][1], + getGeoJSON('multiLineString').geometry.coordinates[0][0][1] + 25, + 'multiLineString lat moved' + ); + assert.equal( + countPositions(movedMultiLineString), + countPositions(getGeoJSON('multiLineString')), + 'multiLineString has same number of postions' + ); const movedPolygon = Draw.get(polygonId); - assert.equal(movedPolygon.geometry.coordinates[0][0][0], getGeoJSON('polygon').geometry.coordinates[0][0][0] + 25, 'polygon lng moved'); - assert.equal(movedPolygon.geometry.coordinates[0][0][1], getGeoJSON('polygon').geometry.coordinates[0][0][1] + 25, 'polygon lat moved'); - assert.equal(countPositions(movedPolygon), countPositions(getGeoJSON('polygon')), 'polygon has same number of postions'); + assert.equal( + movedPolygon.geometry.coordinates[0][0][0], + getGeoJSON('polygon').geometry.coordinates[0][0][0] + 25, + 'polygon lng moved' + ); + assert.equal( + movedPolygon.geometry.coordinates[0][0][1], + getGeoJSON('polygon').geometry.coordinates[0][0][1] + 25, + 'polygon lat moved' + ); + assert.equal( + countPositions(movedPolygon), + countPositions(getGeoJSON('polygon')), + 'polygon has same number of postions' + ); const movedMultiPolygon = Draw.get(multiPolygonId); - assert.equal(movedMultiPolygon.geometry.coordinates[0][0][0][0], getGeoJSON('multiPolygon').geometry.coordinates[0][0][0][0] + 25, 'multiPolygon lng moved'); - assert.equal(movedMultiPolygon.geometry.coordinates[0][0][0][1], getGeoJSON('multiPolygon').geometry.coordinates[0][0][0][1] + 25, 'multiPolygon lat moved'); - assert.equal(countPositions(movedMultiPolygon), countPositions(getGeoJSON('multiPolygon')), 'multiPolygon has same number of postions'); - - cleanUp(); - }); - - await t.test('simple_select - interrupt drag move with mousemove', async () => { - const pointId = Draw.add(getGeoJSON('point'))[0]; - Draw.changeMode('simple_select', { featureIds: [pointId] }); - const startPosition = getGeoJSON('point').geometry.coordinates; - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - // Dragging - map.fire('mousemove', makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { buttons: 1 })); - // Not dragging - map.fire('mousemove', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25)); - map.fire('mouseup', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25)); - - const movedPoint = Draw.get(pointId); - assert.equal(movedPoint.geometry.coordinates[0], startPosition[0] + 15, 'point lng moved only the first amount'); - assert.equal(movedPoint.geometry.coordinates[1], startPosition[1] + 15, 'point lat moved only the first amount'); + assert.equal( + movedMultiPolygon.geometry.coordinates[0][0][0][0], + getGeoJSON('multiPolygon').geometry.coordinates[0][0][0][0] + 25, + 'multiPolygon lng moved' + ); + assert.equal( + movedMultiPolygon.geometry.coordinates[0][0][0][1], + getGeoJSON('multiPolygon').geometry.coordinates[0][0][0][1] + 25, + 'multiPolygon lat moved' + ); + assert.equal( + countPositions(movedMultiPolygon), + countPositions(getGeoJSON('multiPolygon')), + 'multiPolygon has same number of postions' + ); cleanUp(); }); - await t.test('simple_select - fire one update when dragging mouse leaves container and button is released outside', async () => { - const pointId = Draw.add(getGeoJSON('point'))[0]; - Draw.changeMode('simple_select', { featureIds: [pointId] }); - const startPosition = getGeoJSON('point').geometry.coordinates; - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { buttons: 1 })); - mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25)); - map.fire('mouseup', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25)); - - const movedPoint = Draw.get(pointId); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 1, 'draw.update called once'); - assert.equal(movedPoint.geometry.coordinates[0], startPosition[0] + 15, 'point lng moved only the first amount'); - assert.equal(movedPoint.geometry.coordinates[1], startPosition[1] + 15, 'point lat moved only the first amount'); - - cleanUp(); - }); - - await t.test('simple_select - fire two update when dragging mouse leaves container then returns and button is released inside', async () => { - const pointId = Draw.add(getGeoJSON('point'))[0]; - Draw.changeMode('simple_select', { featureIds: [pointId] }); - const startPosition = getGeoJSON('point').geometry.coordinates; - await afterNextRender(); - map.fire.resetHistory(); - map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { buttons: 1 })); - mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); - map.fire('mousemove', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25, { buttons: 1 })); - map.fire('mouseup', makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25)); - - const movedPoint = Draw.get(pointId); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 2, 'draw.update called twice'); - assert.equal(movedPoint.geometry.coordinates[0], startPosition[0] + 25, 'point lng moved to the mouseup location'); - assert.equal(movedPoint.geometry.coordinates[1], startPosition[1] + 25, 'point lat moved to the mouseup location'); - }); + await t.test( + 'simple_select - interrupt drag move with mousemove', + async () => { + const pointId = Draw.add(getGeoJSON('point'))[0]; + Draw.changeMode('simple_select', { featureIds: [pointId] }); + const startPosition = getGeoJSON('point').geometry.coordinates; + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); + // Dragging + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { + buttons: 1 + }) + ); + // Not dragging + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25) + ); + map.fire( + 'mouseup', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25) + ); + + const movedPoint = Draw.get(pointId); + assert.equal( + movedPoint.geometry.coordinates[0], + startPosition[0] + 15, + 'point lng moved only the first amount' + ); + assert.equal( + movedPoint.geometry.coordinates[1], + startPosition[1] + 15, + 'point lat moved only the first amount' + ); + + cleanUp(); + } + ); + + await t.test( + 'simple_select - fire one update when dragging mouse leaves container and button is released outside', + async () => { + const pointId = Draw.add(getGeoJSON('point'))[0]; + Draw.changeMode('simple_select', { featureIds: [pointId] }); + const startPosition = getGeoJSON('point').geometry.coordinates; + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { + buttons: 1 + }) + ); + mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25) + ); + map.fire( + 'mouseup', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25) + ); + + const movedPoint = Draw.get(pointId); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 1, 'draw.update called once'); + assert.equal( + movedPoint.geometry.coordinates[0], + startPosition[0] + 15, + 'point lng moved only the first amount' + ); + assert.equal( + movedPoint.geometry.coordinates[1], + startPosition[1] + 15, + 'point lat moved only the first amount' + ); + + cleanUp(); + } + ); + + await t.test( + 'simple_select - fire two update when dragging mouse leaves container then returns and button is released inside', + async () => { + const pointId = Draw.add(getGeoJSON('point'))[0]; + Draw.changeMode('simple_select', { featureIds: [pointId] }); + const startPosition = getGeoJSON('point').geometry.coordinates; + await afterNextRender(); + map.fire.resetHistory(); + map.fire('mousedown', makeMouseEvent(startPosition[0], startPosition[1])); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 15, startPosition[1] + 15, { + buttons: 1 + }) + ); + mapContainer.dispatchEvent(createSyntheticEvent('mouseout')); + map.fire( + 'mousemove', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25, { + buttons: 1 + }) + ); + map.fire( + 'mouseup', + makeMouseEvent(startPosition[0] + 25, startPosition[1] + 25) + ); + + const movedPoint = Draw.get(pointId); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 2, 'draw.update called twice'); + assert.equal( + movedPoint.geometry.coordinates[0], + startPosition[0] + 25, + 'point lng moved to the mouseup location' + ); + assert.equal( + movedPoint.geometry.coordinates[1], + startPosition[1] + 25, + 'point lat moved to the mouseup location' + ); + } + ); t.test('simple_select - on closing invalid line', () => { Draw.changeMode('draw_line_string'); mouseClick(map, makeMouseEvent(1, 1)); mouseClick(map, makeMouseEvent(1, 1)); - assert.equal(Draw.getMode(), 'simple_select', 'should be in simple_select mode'); - assert.equal(Draw.getSelected().features.length, 0, 'should not get any selected features'); - assert.equal(context.store._emitSelectionChange, undefined, 'should not emit selection change'); + assert.equal( + Draw.getMode(), + 'simple_select', + 'should be in simple_select mode' + ); + assert.equal( + Draw.getSelected().features.length, + 0, + 'should not get any selected features' + ); + assert.equal( + context.store._emitSelectionChange, + undefined, + 'should not emit selection change' + ); cleanUp(); }); @@ -548,34 +982,63 @@ test('simple_select', async (t) => { mouseClick(map, makeMouseEvent(1, 1)); mouseClick(map, makeMouseEvent(16, 16)); mouseClick(map, makeMouseEvent(16, 16)); - assert.equal(Draw.getMode(), 'simple_select', 'should be in simple_select mode'); - assert.equal(Draw.getSelected().features.length, 0, 'should not get any selected features'); - assert.equal(context.store._emitSelectionChange, undefined, 'should not emit selection change'); + assert.equal( + Draw.getMode(), + 'simple_select', + 'should be in simple_select mode' + ); + assert.equal( + Draw.getSelected().features.length, + 0, + 'should not get any selected features' + ); + assert.equal( + context.store._emitSelectionChange, + undefined, + 'should not emit selection change' + ); cleanUp(); }); - await t.test('simple_select - fire one update after moving point with touch', async () => { - const pointId = Draw.add(getGeoJSON('point'))[0]; - Draw.changeMode('simple_select', { featureIds: [pointId] }); - const startPosition = getGeoJSON('point').geometry.coordinates; - const endPosition = [startPosition[0] + TAP_TOLERANCE, startPosition[1] + TAP_TOLERANCE]; - await afterNextRender(); - map.fire.resetHistory(); - map.doubleClickZoom.disable.resetHistory(); - map.fire('touchstart', makeTouchEvent(startPosition[0], startPosition[1])); - - await new Promise(resolve => setTimeout(resolve, TAP_INTERVAL)); - - map.fire('touchmove', makeTouchEvent(endPosition[0], endPosition[1])); - map.fire('touchend', makeTouchEvent(endPosition[0], endPosition[1])); - - const movedPoint = Draw.get(pointId); - const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); - assert.equal(args.length, 1, 'draw.update called once'); - assert.equal(movedPoint.geometry.coordinates[0], endPosition[0], 'point lng moved to the last touchmove position'); - assert.equal(movedPoint.geometry.coordinates[1], endPosition[1], 'point lat moved the last touchmove position'); - cleanUp(); - }); + await t.test( + 'simple_select - fire one update after moving point with touch', + async () => { + const pointId = Draw.add(getGeoJSON('point'))[0]; + Draw.changeMode('simple_select', { featureIds: [pointId] }); + const startPosition = getGeoJSON('point').geometry.coordinates; + const endPosition = [ + startPosition[0] + TAP_TOLERANCE, + startPosition[1] + TAP_TOLERANCE + ]; + await afterNextRender(); + map.fire.resetHistory(); + map.doubleClickZoom.disable.resetHistory(); + map.fire( + 'touchstart', + makeTouchEvent(startPosition[0], startPosition[1]) + ); + + await new Promise(resolve => setTimeout(resolve, TAP_INTERVAL)); + + map.fire('touchmove', makeTouchEvent(endPosition[0], endPosition[1])); + map.fire('touchend', makeTouchEvent(endPosition[0], endPosition[1])); + + const movedPoint = Draw.get(pointId); + const args = getFireArgs().filter(arg => arg[0] === 'draw.update'); + assert.equal(args.length, 1, 'draw.update called once'); + assert.equal( + movedPoint.geometry.coordinates[0], + endPosition[0], + 'point lng moved to the last touchmove position' + ); + assert.equal( + movedPoint.geometry.coordinates[1], + endPosition[1], + 'point lat moved the last touchmove position' + ); + cleanUp(); + } + ); document.body.removeChild(mapContainer); }); diff --git a/test/sort_features.test.js b/test/sort_features.test.js index 9c17f901..98d17e08 100644 --- a/test/sort_features.test.js +++ b/test/sort_features.test.js @@ -12,7 +12,15 @@ test('sortFeatures', () => { id: 'medium-polygon', geometry: { type: 'Polygon', - coordinates: [[[15, 50], [15, 59], [35, 59], [35, 50], [15, 50]]] + coordinates: [ + [ + [15, 50], + [15, 59], + [35, 59], + [35, 50], + [15, 50] + ] + ] } }, { @@ -23,7 +31,15 @@ test('sortFeatures', () => { id: 'huge-polygon', geometry: { type: 'Polygon', - coordinates: [[[58, 27], [58, 68], [101, 68], [101, 27], [58, 27]]] + coordinates: [ + [ + [58, 27], + [58, 68], + [101, 68], + [101, 27], + [58, 27] + ] + ] } }, { @@ -65,14 +81,30 @@ test('sortFeatures', () => { id: 'medium-polygon', geometry: { type: 'Polygon', - coordinates: [[[15, 50], [15, 59], [35, 59], [35, 50], [15, 50]]] + coordinates: [ + [ + [15, 50], + [15, 59], + [35, 59], + [35, 50], + [15, 50] + ] + ] } }, { id: 'huge-polygon', geometry: { type: 'Polygon', - coordinates: [[[58, 27], [58, 68], [101, 68], [101, 27], [58, 27]]] + coordinates: [ + [ + [58, 27], + [58, 68], + [101, 68], + [101, 27], + [58, 27] + ] + ] } } ]); diff --git a/test/static.test.js b/test/static.test.js index 5de681fd..f9e8dc4e 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -2,15 +2,15 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import StaticMode from '@mapbox/mapbox-gl-draw-static-mode'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import MapboxDraw from '../index'; -import {setupAfterNextRender} from './utils/after_next_render'; +import { setupAfterNextRender } from './utils/after_next_render'; import makeMouseEvent from './utils/make_mouse_event'; import getGeoJSON from './utils/get_geojson'; import createMap from './utils/create_map'; -test('static', async (t) => { +test('static', async t => { const map = createMap(); const opts = { modes: { @@ -27,12 +27,12 @@ test('static', async (t) => { const afterNextRender = setupAfterNextRender(map); - const cleanUp = function() { + const cleanUp = function () { Draw.deleteAll(); map.fire.resetHistory(); }; - const getFireArgs = function() { + const getFireArgs = function () { const args = []; for (let i = 0; i < map.fire.callCount; i++) { args.push(map.fire.getCall(i).args); @@ -41,7 +41,7 @@ test('static', async (t) => { }; t.test('static - init map for tests', () => { - const done = function() { + const done = function () { map.off('load', done); }; @@ -70,7 +70,11 @@ test('static', async (t) => { }); await t.test('static - try clicking many features', async () => { - const features = [getGeoJSON('point'), getGeoJSON('line'), getGeoJSON('square')]; + const features = [ + getGeoJSON('point'), + getGeoJSON('line'), + getGeoJSON('square') + ]; Draw.add({ type: 'FeatureCollection', features diff --git a/test/store.test.js b/test/store.test.js index 836f4ea2..9066318d 100644 --- a/test/store.test.js +++ b/test/store.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import Store from '../src/store.js'; import createFeature from './utils/create_feature.js'; @@ -32,45 +32,149 @@ test('Store constructor and public API', () => { const store = new Store(ctx); // instance members - assert.deepEqual(store.sources, { - hot: [], - cold: [] - }, 'exposes store.sources'); + assert.deepEqual( + store.sources, + { + hot: [], + cold: [] + }, + 'exposes store.sources' + ); assert.equal(store.ctx, ctx, 'exposes store.ctx'); assert.equal(store.ctx.map, map, 'exposes store.ctx.map'); assert.equal(store.isDirty, false, 'exposes store.isDirty'); assert.equal(typeof store.render, 'function', 'exposes store.render'); - assert.equal(getPublicMemberKeys(store).length, 4, 'no unexpected instance members'); + assert.equal( + getPublicMemberKeys(store).length, + 4, + 'no unexpected instance members' + ); // prototype members - assert.equal(typeof Store.prototype.setDirty, 'function', 'exposes store.setDirty'); - assert.equal(typeof Store.prototype.createRenderBatch, 'function', 'exposes store.createRenderBatch'); - assert.equal(typeof Store.prototype.featureCreated, 'function', 'exposes store.featureCreated'); - assert.equal(typeof Store.prototype.featureChanged, 'function', 'exposes store.featureChanged'); - assert.equal(typeof Store.prototype.getChangedIds, 'function', 'exposes store.getChangedIds'); - assert.equal(typeof Store.prototype.clearChangedIds, 'function', 'exposes store.clearChangedIds'); - assert.equal(typeof Store.prototype.getAllIds, 'function', 'exposes store.getAllIds'); + assert.equal( + typeof Store.prototype.setDirty, + 'function', + 'exposes store.setDirty' + ); + assert.equal( + typeof Store.prototype.createRenderBatch, + 'function', + 'exposes store.createRenderBatch' + ); + assert.equal( + typeof Store.prototype.featureCreated, + 'function', + 'exposes store.featureCreated' + ); + assert.equal( + typeof Store.prototype.featureChanged, + 'function', + 'exposes store.featureChanged' + ); + assert.equal( + typeof Store.prototype.getChangedIds, + 'function', + 'exposes store.getChangedIds' + ); + assert.equal( + typeof Store.prototype.clearChangedIds, + 'function', + 'exposes store.clearChangedIds' + ); + assert.equal( + typeof Store.prototype.getAllIds, + 'function', + 'exposes store.getAllIds' + ); assert.equal(typeof Store.prototype.add, 'function', 'exposes store.add'); assert.equal(typeof Store.prototype.get, 'function', 'exposes store.get'); - assert.equal(typeof Store.prototype.getAll, 'function', 'exposes store.getAll'); - assert.equal(typeof Store.prototype.select, 'function', 'exposes store.select'); - assert.equal(typeof Store.prototype.deselect, 'function', 'exposes store.deselect'); - assert.equal(typeof Store.prototype.clearSelected, 'function', 'exposes store.clearSelected'); - assert.equal(typeof Store.prototype.getSelectedIds, 'function', 'exposes store.getSelectedIds'); - assert.equal(typeof Store.prototype.getSelected, 'function', 'exposes store.getSelected'); - assert.equal(typeof Store.prototype.isSelected, 'function', 'exposes store.isSelected'); - assert.equal(typeof Store.prototype.delete, 'function', 'exposes store.delete'); - assert.equal(typeof Store.prototype.setSelected, 'function', 'exposes store.setSelected'); - assert.equal(typeof Store.prototype.setSelectedCoordinates, 'function', 'exposes store.setSelectedCoordinates'); - assert.equal(typeof Store.prototype.getSelectedCoordinates, 'function', 'exposes store.getSelectedCoordinates'); - assert.equal(typeof Store.prototype.clearSelectedCoordinates, 'function', 'exposes store.clearSelectedCoordinates'); - assert.equal(typeof Store.prototype.setFeatureProperty, 'function', 'exposes store.setFeatureProperty'); - assert.equal(typeof Store.prototype.storeMapConfig, 'function', 'exposes store.storeMapConfig'); - assert.equal(typeof Store.prototype.restoreMapConfig, 'function', 'exposes store.restoreMapConfig'); - assert.equal(typeof Store.prototype.getInitialConfigValue, 'function', 'exposes store.getInitialConfigValue'); - - assert.equal(getPublicMemberKeys(Store.prototype).length, 25, 'no untested prototype members'); + assert.equal( + typeof Store.prototype.getAll, + 'function', + 'exposes store.getAll' + ); + assert.equal( + typeof Store.prototype.select, + 'function', + 'exposes store.select' + ); + assert.equal( + typeof Store.prototype.deselect, + 'function', + 'exposes store.deselect' + ); + assert.equal( + typeof Store.prototype.clearSelected, + 'function', + 'exposes store.clearSelected' + ); + assert.equal( + typeof Store.prototype.getSelectedIds, + 'function', + 'exposes store.getSelectedIds' + ); + assert.equal( + typeof Store.prototype.getSelected, + 'function', + 'exposes store.getSelected' + ); + assert.equal( + typeof Store.prototype.isSelected, + 'function', + 'exposes store.isSelected' + ); + assert.equal( + typeof Store.prototype.delete, + 'function', + 'exposes store.delete' + ); + assert.equal( + typeof Store.prototype.setSelected, + 'function', + 'exposes store.setSelected' + ); + assert.equal( + typeof Store.prototype.setSelectedCoordinates, + 'function', + 'exposes store.setSelectedCoordinates' + ); + assert.equal( + typeof Store.prototype.getSelectedCoordinates, + 'function', + 'exposes store.getSelectedCoordinates' + ); + assert.equal( + typeof Store.prototype.clearSelectedCoordinates, + 'function', + 'exposes store.clearSelectedCoordinates' + ); + assert.equal( + typeof Store.prototype.setFeatureProperty, + 'function', + 'exposes store.setFeatureProperty' + ); + assert.equal( + typeof Store.prototype.storeMapConfig, + 'function', + 'exposes store.storeMapConfig' + ); + assert.equal( + typeof Store.prototype.restoreMapConfig, + 'function', + 'exposes store.restoreMapConfig' + ); + assert.equal( + typeof Store.prototype.getInitialConfigValue, + 'function', + 'exposes store.getInitialConfigValue' + ); + + assert.equal( + getPublicMemberKeys(Store.prototype).length, + 25, + 'no untested prototype members' + ); }); test('Store#setDirty', () => { @@ -83,7 +187,7 @@ test('Store#setDirty', () => { test('Store#createRenderBatch', () => { const store = createStore(); let numRenders = 0; - store.render = function() { + store.render = function () { numRenders++; }; store.render(); @@ -92,13 +196,17 @@ test('Store#createRenderBatch', () => { store.render(); store.render(); store.render(); - assert.equal(numRenders, 1, 'when batching render doesn\'t get incremented'); + assert.equal(numRenders, 1, "when batching render doesn't get incremented"); renderBatch(); assert.equal(numRenders, 2, 'when releasing batch, render only happens once'); renderBatch = store.createRenderBatch(); renderBatch(); - assert.equal(numRenders, 2, 'when releasing batch, render doesn\'t happen if render wasn\'t called'); + assert.equal( + numRenders, + 2, + "when releasing batch, render doesn't happen if render wasn't called" + ); }); test('Store#featureChanged, Store#getChangedIds, Store#clearChangedIds', () => { @@ -133,7 +241,7 @@ test('Store#add, Store#get, Store#getAll', () => { assert.deepEqual(store.getAll(), [point, line]); }); -test('selection methods', async (t) => { +test('selection methods', async t => { const store = createStore(); const f1 = createFeature('point'); store.add(f1); @@ -148,16 +256,32 @@ test('selection methods', async (t) => { t.test('select one feature', () => { store.select(f1.id); - assert.deepEqual(store.getSelectedIds(), [f1.id], 'f1 returns in selected ids array'); - assert.deepEqual(store.getSelected(), [f1.toGeoJSON()], 'f1 returns in selected array'); + assert.deepEqual( + store.getSelectedIds(), + [f1.id], + 'f1 returns in selected ids array' + ); + assert.deepEqual( + store.getSelected(), + [f1.toGeoJSON()], + 'f1 returns in selected array' + ); assert.equal(store.isSelected(f1.id), true, 'isSelected affirms f1'); assert.equal(store.isSelected(f2.id), false, 'isSelected rejects f2'); }); await t.test('select a second feature', () => { store.select(f2.id); - assert.deepEqual(store.getSelectedIds(), [f1.id, f2.id], 'f1 and f2 return in selected ids array'); - assert.deepEqual(store.getSelected(), [f1, f2], 'f1 and f2 return in selected array'); + assert.deepEqual( + store.getSelectedIds(), + [f1.id, f2.id], + 'f1 and f2 return in selected ids array' + ); + assert.deepEqual( + store.getSelected(), + [f1, f2], + 'f1 and f2 return in selected array' + ); assert.equal(store.isSelected(f1.id), true, 'isSelected affirms f1'); assert.equal(store.isSelected(f2.id), true, 'isSelected affirms f2'); }); @@ -168,13 +292,21 @@ test('selection methods', async (t) => { await t.test('deselect a feature', () => { store.deselect(f1.id); - assert.deepEqual(store.getSelectedIds(), [f2.id], 'deselection of f1 clears it from selected array'); + assert.deepEqual( + store.getSelectedIds(), + [f2.id], + 'deselection of f1 clears it from selected array' + ); }); await t.test('serially select more features', () => { store.select(f3.id); store.select(f4.id); - assert.deepEqual(store.getSelectedIds(), [f2.id, f3.id, f4.id], 'serial selection of f3 and f4 reflected in selected array'); + assert.deepEqual( + store.getSelectedIds(), + [f2.id, f3.id, f4.id], + 'serial selection of f3 and f4 reflected in selected array' + ); }); await t.test('clear selection', () => { @@ -222,16 +354,16 @@ test('Store#setSelected', () => { const line = createFeature('line'); const polygon = createFeature('polygon'); - store.setSelected(point.id, {silent: true}); + store.setSelected(point.id, { silent: true }); assert.deepEqual(store.getSelectedIds(), [point.id]); - store.setSelected([line.id, polygon.id], {silent: true}); + store.setSelected([line.id, polygon.id], { silent: true }); assert.deepEqual(store.getSelectedIds(), [line.id, polygon.id]); - store.setSelected(line.id, {silent: true}); + store.setSelected(line.id, { silent: true }); assert.deepEqual(store.getSelectedIds(), [line.id]); - store.setSelected(undefined, {silent: true}); + store.setSelected(undefined, { silent: true }); assert.deepEqual(store.getSelectedIds(), []); }); @@ -243,7 +375,11 @@ test('Store#setFeatureProperty', () => { store.clearChangedIds(); store.setFeatureProperty(point.id, 'size', 200); assert.deepEqual(store.getChangedIds(), [point.id]); - assert.equal(store.get(point.id).properties.size, 200, 'sets the property on the feature'); + assert.equal( + store.get(point.id).properties.size, + 200, + 'sets the property on the feature' + ); }); test('Store#storeAndRestoreMapConfig', () => { @@ -251,14 +387,26 @@ test('Store#storeAndRestoreMapConfig', () => { // Disable doubleClickZoom map.doubleClickZoom.disable(); // Check it's disabled - assert.equal(map.doubleClickZoom.isEnabled(), false, 'Disables doubleClickZoom on the map'); + assert.equal( + map.doubleClickZoom.isEnabled(), + false, + 'Disables doubleClickZoom on the map' + ); const ctx = { map }; const store = new Store(ctx); store.storeMapConfig(); // Check we can get the initial state of it - assert.equal(store.getInitialConfigValue('doubleClickZoom'), false, 'Retrieves the initial value for the doubleClickZoom'); + assert.equal( + store.getInitialConfigValue('doubleClickZoom'), + false, + 'Retrieves the initial value for the doubleClickZoom' + ); // Enable it again, byt then use restore to reset the initial state map.doubleClickZoom.enable(); store.restoreMapConfig(); - assert.equal(map.doubleClickZoom.isEnabled(), false, 'Restores doubleClickZoom on the map'); + assert.equal( + map.doubleClickZoom.isEnabled(), + false, + 'Restores doubleClickZoom on the map' + ); }); diff --git a/test/string_set.test.js b/test/string_set.test.js index 1ebb711a..830a612d 100644 --- a/test/string_set.test.js +++ b/test/string_set.test.js @@ -5,17 +5,41 @@ import StringSet from '../src/lib/string_set.js'; test('StringSet constructor and API', () => { const set = new StringSet(); assert.deepEqual(set.values(), [], 'empty by default'); - assert.equal(Object.keys(set).filter(k => k[0] !== '_').length, 0, 'no unexpected properties'); + assert.equal( + Object.keys(set).filter(k => k[0] !== '_').length, + 0, + 'no unexpected properties' + ); // Methods assert.equal(typeof StringSet.prototype.add, 'function', 'exposes set.add'); - assert.equal(typeof StringSet.prototype.delete, 'function', 'exposes set.delete'); + assert.equal( + typeof StringSet.prototype.delete, + 'function', + 'exposes set.delete' + ); assert.equal(typeof StringSet.prototype.has, 'function', 'exposes set.has'); - assert.equal(typeof StringSet.prototype.values, 'function', 'exposes set.values'); - assert.equal(typeof StringSet.prototype.clear, 'function', 'exposes set.clear'); - assert.equal(Object.keys(StringSet.prototype).filter(k => k[0] !== '_').length, 5, 'no unexpected methods'); + assert.equal( + typeof StringSet.prototype.values, + 'function', + 'exposes set.values' + ); + assert.equal( + typeof StringSet.prototype.clear, + 'function', + 'exposes set.clear' + ); + assert.equal( + Object.keys(StringSet.prototype).filter(k => k[0] !== '_').length, + 5, + 'no unexpected methods' + ); const populatedSet = new StringSet(['a', 4, 'b']); - assert.deepEqual(populatedSet.values(), ['a', 4, 'b'], 'populated by constructor arg'); + assert.deepEqual( + populatedSet.values(), + ['a', 4, 'b'], + 'populated by constructor arg' + ); }); test('StringSet#add', () => { @@ -60,7 +84,11 @@ test('StringSet#values', () => { const subject = ['a', 'b']; const set = new StringSet(subject); assert.deepEqual(set.values(), ['a', 'b']); - assert.notEqual(set.values(), subject, 'array is copied, so source array is not mutable'); + assert.notEqual( + set.values(), + subject, + 'array is copied, so source array is not mutable' + ); }); test('StringSet#clear', () => { diff --git a/test/ui.test.js b/test/ui.test.js index 49fb57ca..2906f9ee 100644 --- a/test/ui.test.js +++ b/test/ui.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import {spy} from 'sinon'; +import { spy } from 'sinon'; import ui from '../src/ui.js'; @@ -36,14 +36,20 @@ function createMockContext({ position, controls } = {}) { } function getButtons(div) { - return Array.prototype.slice.call(div.getElementsByClassName('mapbox-gl-draw_ctrl-draw-btn')); + return Array.prototype.slice.call( + div.getElementsByClassName('mapbox-gl-draw_ctrl-draw-btn') + ); } -test('ui container classes', async (t) => { +test('ui container classes', async t => { const { context, cleanup } = createMockContext(); const testUi = ui(context); - assert.equal(context.container.className, '', 'confirm that class starts empty'); + assert.equal( + context.container.className, + '', + 'confirm that class starts empty' + ); // Each sub-test relies on state from the prior sub-tests @@ -54,9 +60,18 @@ test('ui container classes', async (t) => { mouse: 'move' }); testUi.updateMapClasses(); - assert.ok(context.container.classList.contains('mode-direct_select'), 'mode class set'); - assert.ok(context.container.classList.contains('feature-vertex'), 'feature class set'); - assert.ok(context.container.classList.contains('mouse-move'), 'mouse class set'); + assert.ok( + context.container.classList.contains('mode-direct_select'), + 'mode class set' + ); + assert.ok( + context.container.classList.contains('feature-vertex'), + 'feature class set' + ); + assert.ok( + context.container.classList.contains('mouse-move'), + 'mouse class set' + ); }); await t.test('update only feature class', () => { @@ -64,9 +79,18 @@ test('ui container classes', async (t) => { feature: 'midpoint' }); testUi.updateMapClasses(); - assert.ok(context.container.classList.contains('mode-direct_select'), 'mode class remains'); - assert.ok(context.container.classList.contains('feature-midpoint'), 'feature class updated'); - assert.ok(context.container.classList.contains('mouse-move'), 'mouse class remains'); + assert.ok( + context.container.classList.contains('mode-direct_select'), + 'mode class remains' + ); + assert.ok( + context.container.classList.contains('feature-midpoint'), + 'feature class updated' + ); + assert.ok( + context.container.classList.contains('mouse-move'), + 'mouse class remains' + ); }); await t.test('update mode and mouse classes', () => { @@ -75,9 +99,18 @@ test('ui container classes', async (t) => { mouse: 'bar' }); testUi.updateMapClasses(); - assert.ok(context.container.classList.contains('mode-foo'), 'mode class updated'); - assert.ok(context.container.classList.contains('feature-midpoint'), 'feature class remains'); - assert.ok(context.container.classList.contains('mouse-bar'), 'mouse class updated'); + assert.ok( + context.container.classList.contains('mode-foo'), + 'mode class updated' + ); + assert.ok( + context.container.classList.contains('feature-midpoint'), + 'feature class remains' + ); + assert.ok( + context.container.classList.contains('mouse-bar'), + 'mouse class updated' + ); }); await t.test('remove only feature class', () => { @@ -85,9 +118,18 @@ test('ui container classes', async (t) => { feature: null }); testUi.updateMapClasses(); - assert.ok(context.container.classList.contains('mode-foo'), 'mode class remains'); - assert.ok(context.container.className.indexOf('feature-') === -1, 'feature class removed'); - assert.ok(context.container.classList.contains('mouse-bar'), 'mouse class remains'); + assert.ok( + context.container.classList.contains('mode-foo'), + 'mode class remains' + ); + assert.ok( + context.container.className.indexOf('feature-') === -1, + 'feature class removed' + ); + assert.ok( + context.container.classList.contains('mouse-bar'), + 'mouse class remains' + ); }); await t.test('remove all classes', () => { @@ -97,9 +139,18 @@ test('ui container classes', async (t) => { mouse: null }); testUi.updateMapClasses(); - assert.ok(context.container.className.indexOf('mode-') === -1, 'mode class removed'); - assert.ok(context.container.className.indexOf('feature-') === -1, 'feature class still gone'); - assert.ok(context.container.className.indexOf('mouse-') === -1, 'mouse class removed'); + assert.ok( + context.container.className.indexOf('mode-') === -1, + 'mode class removed' + ); + assert.ok( + context.container.className.indexOf('feature-') === -1, + 'feature class still gone' + ); + assert.ok( + context.container.className.indexOf('mouse-') === -1, + 'mouse class removed' + ); }); cleanup(); @@ -128,8 +179,14 @@ test('ui buttons with one options.controls', () => { const div = testUi.addButtons(); const buttons = getButtons(div); assert.equal(buttons.length, 1, 'one button added'); - assert.ok(buttons[0].classList.contains('mapbox-gl-draw_line'), 'has line class'); - assert.ok(buttons[0].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), 'has control class'); + assert.ok( + buttons[0].classList.contains('mapbox-gl-draw_line'), + 'has line class' + ); + assert.ok( + buttons[0].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), + 'has control class' + ); cleanup(); }); @@ -144,8 +201,11 @@ test('ui buttons control group container inserted above attribution control, in const controlContainer = getControlContainer(); const testUi = ui(context); - assert.equal(controlContainer.getElementsByClassName('mapboxgl-ctrl-group').length, 0, - 'confirm control group does not exist at first'); + assert.equal( + controlContainer.getElementsByClassName('mapboxgl-ctrl-group').length, + 0, + 'confirm control group does not exist at first' + ); const controlGroup = testUi.addButtons(); assert.ok(controlGroup, 'control group exists'); @@ -153,7 +213,7 @@ test('ui buttons control group container inserted above attribution control, in cleanup(); }); -test('ui buttons with all options.controls, no attribution control', async (t) => { +test('ui buttons with all options.controls, no attribution control', async t => { /* eslint-disable */ const { context, cleanup } = createMockContext({ controls: { @@ -171,18 +231,58 @@ test('ui buttons with all options.controls, no attribution control', async (t) = assert.equal(buttons.length, 4, 'one button added'); - assert.ok(buttons[0].classList.contains('mapbox-gl-draw_point'), 'first button has point class'); - assert.ok(buttons[0].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), 'first button has control class'); - assert.equal(buttons[0].parentNode, controlGroup, 'first button is in controlGroup'); - assert.ok(buttons[1].classList.contains('mapbox-gl-draw_line'), 'second button has line class'); - assert.ok(buttons[1].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), 'second button has control class'); - assert.equal(buttons[2].parentNode, controlGroup, 'second button is in controlGroup'); - assert.ok(buttons[2].classList.contains('mapbox-gl-draw_polygon'), 'third button has polygon class'); - assert.ok(buttons[2].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), 'third button has control class'); - assert.equal(buttons[1].parentNode, controlGroup, 'third button is in controlGroup'); - assert.ok(buttons[3].classList.contains('mapbox-gl-draw_trash'), 'fourth button has trash class'); - assert.ok(buttons[3].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), 'fourth button has control class'); - assert.equal(buttons[3].parentNode, controlGroup, 'fourth button is in controlGroup'); + assert.ok( + buttons[0].classList.contains('mapbox-gl-draw_point'), + 'first button has point class' + ); + assert.ok( + buttons[0].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), + 'first button has control class' + ); + assert.equal( + buttons[0].parentNode, + controlGroup, + 'first button is in controlGroup' + ); + assert.ok( + buttons[1].classList.contains('mapbox-gl-draw_line'), + 'second button has line class' + ); + assert.ok( + buttons[1].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), + 'second button has control class' + ); + assert.equal( + buttons[2].parentNode, + controlGroup, + 'second button is in controlGroup' + ); + assert.ok( + buttons[2].classList.contains('mapbox-gl-draw_polygon'), + 'third button has polygon class' + ); + assert.ok( + buttons[2].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), + 'third button has control class' + ); + assert.equal( + buttons[1].parentNode, + controlGroup, + 'third button is in controlGroup' + ); + assert.ok( + buttons[3].classList.contains('mapbox-gl-draw_trash'), + 'fourth button has trash class' + ); + assert.ok( + buttons[3].classList.contains('mapbox-gl-draw_ctrl-draw-btn'), + 'fourth button has control class' + ); + assert.equal( + buttons[3].parentNode, + controlGroup, + 'fourth button is in controlGroup' + ); const pointButton = buttons[0]; const lineButton = buttons[1]; @@ -193,55 +293,152 @@ test('ui buttons with all options.controls, no attribution control', async (t) = lineButton.click(); assert.ok(lineButton.classList.contains('active'), 'line button is active'); - assert.equal(polygonButton.classList.contains('active'), false, 'polygon button is inactive'); - assert.equal(pointButton.classList.contains('active'), false, 'point button is inactive'); - assert.equal(trashButton.classList.contains('active'), false, 'trash button is inactive'); + assert.equal( + polygonButton.classList.contains('active'), + false, + 'polygon button is inactive' + ); + assert.equal( + pointButton.classList.contains('active'), + false, + 'point button is inactive' + ); + assert.equal( + trashButton.classList.contains('active'), + false, + 'trash button is inactive' + ); assert.equal(context.events.changeMode.callCount, 1, 'changeMode called'); - assert.deepEqual(context.events.changeMode.getCall(0).args, ['draw_line_string'], 'with correct arguments'); + assert.deepEqual( + context.events.changeMode.getCall(0).args, + ['draw_line_string'], + 'with correct arguments' + ); context.events.changeMode.resetHistory(); }); await t.test('click polygon button', () => { polygonButton.click(); - assert.equal(lineButton.classList.contains('active'), false, 'line button is inactive'); - assert.ok(polygonButton.classList.contains('active'), 'polygon button is active'); - assert.equal(pointButton.classList.contains('active'), false, 'point button is inactive'); - assert.equal(trashButton.classList.contains('active'), false, 'trash button is inactive'); + assert.equal( + lineButton.classList.contains('active'), + false, + 'line button is inactive' + ); + assert.ok( + polygonButton.classList.contains('active'), + 'polygon button is active' + ); + assert.equal( + pointButton.classList.contains('active'), + false, + 'point button is inactive' + ); + assert.equal( + trashButton.classList.contains('active'), + false, + 'trash button is inactive' + ); assert.equal(context.events.changeMode.callCount, 1, 'changeMode called'); - assert.deepEqual(context.events.changeMode.getCall(0).args, ['draw_polygon'], 'with correct arguments'); + assert.deepEqual( + context.events.changeMode.getCall(0).args, + ['draw_polygon'], + 'with correct arguments' + ); context.events.changeMode.resetHistory(); }); - await t.test('programmatically activate point button, then programmatically deactivate', () => { - testUi.setActiveButton('point'); - - assert.equal(lineButton.classList.contains('active'), false, 'line button is inactive'); - assert.equal(polygonButton.classList.contains('active'), false, 'polygon button is inactive'); - assert.ok(pointButton.classList.contains('active'), 'point button is active'); - assert.equal(trashButton.classList.contains('active'), false, 'trash button is inactive'); - assert.equal(context.events.changeMode.callCount, 0, 'changeMode not called'); - - testUi.setActiveButton(); - - assert.equal(lineButton.classList.contains('active'), false, 'line button is inactive'); - assert.equal(polygonButton.classList.contains('active'), false, 'polygon button is inactive'); - assert.equal(pointButton.classList.contains('active'), false, 'point button is inactive'); - assert.equal(trashButton.classList.contains('active'), false, 'trash button is inactive'); - assert.equal(context.events.changeMode.callCount, 0, 'changeMode not called'); - }); + await t.test( + 'programmatically activate point button, then programmatically deactivate', + () => { + testUi.setActiveButton('point'); + + assert.equal( + lineButton.classList.contains('active'), + false, + 'line button is inactive' + ); + assert.equal( + polygonButton.classList.contains('active'), + false, + 'polygon button is inactive' + ); + assert.ok( + pointButton.classList.contains('active'), + 'point button is active' + ); + assert.equal( + trashButton.classList.contains('active'), + false, + 'trash button is inactive' + ); + assert.equal( + context.events.changeMode.callCount, + 0, + 'changeMode not called' + ); + + testUi.setActiveButton(); + + assert.equal( + lineButton.classList.contains('active'), + false, + 'line button is inactive' + ); + assert.equal( + polygonButton.classList.contains('active'), + false, + 'polygon button is inactive' + ); + assert.equal( + pointButton.classList.contains('active'), + false, + 'point button is inactive' + ); + assert.equal( + trashButton.classList.contains('active'), + false, + 'trash button is inactive' + ); + assert.equal( + context.events.changeMode.callCount, + 0, + 'changeMode not called' + ); + } + ); await t.test('click trash button', () => { trashButton.click(); - assert.equal(lineButton.classList.contains('active'), false, 'line button is inactive'); - assert.equal(polygonButton.classList.contains('active'), false, 'polygon button is inactive'); - assert.equal(pointButton.classList.contains('active'), false, 'point button is inactive'); - assert.equal(trashButton.classList.contains('active'), false, 'trash button is inactive'); - - assert.equal(context.events.changeMode.callCount, 0, 'changeMode not called'); + assert.equal( + lineButton.classList.contains('active'), + false, + 'line button is inactive' + ); + assert.equal( + polygonButton.classList.contains('active'), + false, + 'polygon button is inactive' + ); + assert.equal( + pointButton.classList.contains('active'), + false, + 'point button is inactive' + ); + assert.equal( + trashButton.classList.contains('active'), + false, + 'trash button is inactive' + ); + + assert.equal( + context.events.changeMode.callCount, + 0, + 'changeMode not called' + ); }); cleanup(); diff --git a/test/utils/create_feature.js b/test/utils/create_feature.js index 6c5f5e5e..59864671 100644 --- a/test/utils/create_feature.js +++ b/test/utils/create_feature.js @@ -1,4 +1,4 @@ -import {generateID} from '../../src/lib/id.js'; +import { generateID } from '../../src/lib/id.js'; import getGeoJSON from './get_geojson.js'; const usedIds = new Set(); @@ -13,11 +13,16 @@ export function generateUniqueID() { } export default function createFeature(featureType) { - const feature = Object.assign({ - id: generateUniqueID(), - properties: {} - }, getGeoJSON(featureType)); + const feature = Object.assign( + { + id: generateUniqueID(), + properties: {} + }, + getGeoJSON(featureType) + ); feature.toGeoJSON = () => feature; - feature.setProperty = (property, name) => { feature.properties[property] = name; }; + feature.setProperty = (property, name) => { + feature.properties[property] = name; + }; return feature; } diff --git a/test/utils/create_map.js b/test/utils/create_map.js index 14fd10bb..1c6f9c8e 100644 --- a/test/utils/create_map.js +++ b/test/utils/create_map.js @@ -1,4 +1,4 @@ -import {bboxClip} from '@turf/bbox-clip'; +import { bboxClip } from '@turf/bbox-clip'; import Evented from '../../bench/lib/evented'; import { interactions } from '../../src/constants'; @@ -14,9 +14,9 @@ class MockMap extends Evented { addSource: (id, source) => { this.style._layers[id] = source; }, - removeSource: (id) => { + removeSource: id => { delete this.style._layers[id]; - }, + } }; this.options = { container: document.createElement('div'), @@ -26,9 +26,15 @@ class MockMap extends Evented { for (const interaction of interactions) { this[interaction] = { enabled: true, - disable() { this.enabled = false; }, - enable() { this.enabled = true; }, - isEnabled() { return this.enabled; }, + disable() { + this.enabled = false; + }, + enable() { + this.enabled = true; + }, + isEnabled() { + return this.enabled; + } }; } @@ -86,8 +92,8 @@ class MockMap extends Evented { for (const feature of source.data.features) { if (feature.geometry.type === 'Point') { const [x, y] = feature.geometry.coordinates; - if (x >= minX && x <= maxX && y >= minY && y <= maxY) features.push(feature); - + if (x >= minX && x <= maxX && y >= minY && y <= maxY) + features.push(feature); } else if (feature.geometry.type === 'MultiPoint') { for (const [x, y] of feature.geometry.coordinates) { if (x >= minX && x <= maxX && y >= minY && y <= maxY) { @@ -95,7 +101,6 @@ class MockMap extends Evented { break; } } - } else { const clipped = bboxClip(feature, bbox); if (clipped.geometry.coordinates.length) features.push(feature); diff --git a/test/utils/create_mock_draw_mode_context.js b/test/utils/create_mock_draw_mode_context.js index d2657eee..73f6b95b 100644 --- a/test/utils/create_mock_draw_mode_context.js +++ b/test/utils/create_mock_draw_mode_context.js @@ -1,4 +1,4 @@ -import {spy} from 'sinon'; +import { spy } from 'sinon'; export default function createMockDrawModeContext() { const _store = {}; diff --git a/test/utils/create_mock_feature_context.js b/test/utils/create_mock_feature_context.js index 54e1f75d..0fab06b7 100644 --- a/test/utils/create_mock_feature_context.js +++ b/test/utils/create_mock_feature_context.js @@ -1,4 +1,4 @@ -import {spy} from 'sinon'; +import { spy } from 'sinon'; /** * Returns an mock ctx object with just those properties a Feature @@ -6,7 +6,9 @@ import {spy} from 'sinon'; * * @return {Object} */ -export default function createMockFeatureContext(opts = { userProperties: false}) { +export default function createMockFeatureContext( + opts = { userProperties: false } +) { return { options: { userProperties: opts.userProperties diff --git a/test/utils/create_mock_lifecycle_context.js b/test/utils/create_mock_lifecycle_context.js index 4063b36b..0aae8ac5 100644 --- a/test/utils/create_mock_lifecycle_context.js +++ b/test/utils/create_mock_lifecycle_context.js @@ -1,4 +1,4 @@ -import {spy} from 'sinon'; +import { spy } from 'sinon'; export default function createMockLifecycleContext() { return { diff --git a/test/utils/create_mock_mode.js b/test/utils/create_mock_mode.js index 05075e05..afb11e37 100644 --- a/test/utils/create_mock_mode.js +++ b/test/utils/create_mock_mode.js @@ -1,4 +1,4 @@ -import {spy} from 'sinon'; +import { spy } from 'sinon'; export default function createMockModeHandlerContext() { return { diff --git a/test/utils/create_mock_mode_handler_context.js b/test/utils/create_mock_mode_handler_context.js index c78183f2..a18aeda0 100644 --- a/test/utils/create_mock_mode_handler_context.js +++ b/test/utils/create_mock_mode_handler_context.js @@ -1,4 +1,4 @@ -import {spy} from 'sinon'; +import { spy } from 'sinon'; export default function createMockModeHandlerContext() { return { diff --git a/test/utils/draw_geometry.js b/test/utils/draw_geometry.js index dc429f01..a83fd23a 100644 --- a/test/utils/draw_geometry.js +++ b/test/utils/draw_geometry.js @@ -1,5 +1,5 @@ import click from './mouse_click.js'; -import {setupAfterNextRender} from './after_next_render.js'; +import { setupAfterNextRender } from './after_next_render.js'; import makeMouseEvent from './make_mouse_event.js'; /** diff --git a/test/utils/get_geojson.js b/test/utils/get_geojson.js index 1190231d..5ef17a85 100644 --- a/test/utils/get_geojson.js +++ b/test/utils/get_geojson.js @@ -1,10 +1,20 @@ const features = { multiPolygon: { type: 'Feature', - properties: {'a':'b', 'c':'d'}, + properties: { a: 'b', c: 'd' }, geometry: { type: 'MultiPolygon', - coordinates: [[[[1, 1], [2, 2], [2, 6], [4, 3], [1, 1]]]] + coordinates: [ + [ + [ + [1, 1], + [2, 2], + [2, 6], + [4, 3], + [1, 1] + ] + ] + ] } }, @@ -15,10 +25,20 @@ const features = { type: 'MultiPolygon', coordinates: [ [ - [[1, 1], [2, 2], [4, 3], [1, 1]] + [ + [1, 1], + [2, 2], + [4, 3], + [1, 1] + ] ], [ - [[30, 20], [50, 40], [70, 30], [30, 20]] + [ + [30, 20], + [50, 40], + [70, 30], + [30, 20] + ] ] ] } @@ -29,7 +49,11 @@ const features = { properties: {}, geometry: { type: 'LineString', - coordinates: [[0, 0], [1, 1], [2, 2]] + coordinates: [ + [0, 0], + [1, 1], + [2, 2] + ] } }, @@ -38,7 +62,11 @@ const features = { properties: {}, geometry: { type: 'LineString', - coordinates: [[3, 3], [5, 5], [7, 7]] + coordinates: [ + [3, 3], + [5, 5], + [7, 7] + ] } }, @@ -47,7 +75,18 @@ const features = { properties: {}, geometry: { type: 'MultiLineString', - coordinates: [[[20, 20], [21, 21], [22, 22]], [[30, 30], [31, 31], [32, 32]]] + coordinates: [ + [ + [20, 20], + [21, 21], + [22, 22] + ], + [ + [30, 30], + [31, 31], + [32, 32] + ] + ] } }, @@ -56,7 +95,10 @@ const features = { properties: {}, geometry: { type: 'MultiPoint', - coordinates: [[-5, -5], [-10, -10]] + coordinates: [ + [-5, -5], + [-10, -10] + ] } }, @@ -89,19 +131,35 @@ const features = { polygon: { type: 'Feature', - properties: {'a':'b', 'c':'d'}, + properties: { a: 'b', c: 'd' }, geometry: { type: 'Polygon', - coordinates: [[[30, 20], [50, 40], [70, 30], [50, 20], [30, 20]]] + coordinates: [ + [ + [30, 20], + [50, 40], + [70, 30], + [50, 20], + [30, 20] + ] + ] } }, polygon2: { type: 'Feature', - properties: {'a2':'b2', 'c2':'d2'}, + properties: { a2: 'b2', c2: 'd2' }, geometry: { type: 'Polygon', - coordinates: [[[40, 30], [60, 50], [90, 90], [100, 80], [40, 30]]] + coordinates: [ + [ + [40, 30], + [60, 50], + [90, 90], + [100, 80], + [40, 30] + ] + ] } }, @@ -110,7 +168,15 @@ const features = { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]]] + coordinates: [ + [ + [1, 1], + [1, 2], + [2, 2], + [2, 1], + [1, 1] + ] + ] } }, @@ -125,10 +191,20 @@ const features = { properties: {}, geometry: { type: 'GeometryCollection', - geometries: [{ - type: 'Polygon', - coordinates: [[[30, 20], [50, 40], [70, 30], [50, 20], [30, 20]]] - }] + geometries: [ + { + type: 'Polygon', + coordinates: [ + [ + [30, 20], + [50, 40], + [70, 30], + [50, 20], + [30, 20] + ] + ] + } + ] } }, @@ -140,13 +216,21 @@ const features = { properties: {}, geometry: { type: 'Polygon', - coordinates: [[[1, 1], [2, 2], [3, 3], [4, 4], [1, 1]]] + coordinates: [ + [ + [1, 1], + [2, 2], + [3, 3], + [4, 4], + [1, 1] + ] + ] } } ] } }; -export default function getGeoJSON (type) { +export default function getGeoJSON(type) { return JSON.parse(JSON.stringify(features[type])); } diff --git a/test/utils/key_events.js b/test/utils/key_events.js index 7dca7fb6..df35df32 100644 --- a/test/utils/key_events.js +++ b/test/utils/key_events.js @@ -2,7 +2,7 @@ import createSyntheticEvent from 'synthetic-dom-events'; import * as Constants from '../../src/constants'; const classList = [Constants.classes.CANVAS]; -classList.contains = function(cls) { +classList.contains = function (cls) { return classList.indexOf(cls) >= 0; }; diff --git a/test/utils/make_mouse_event.js b/test/utils/make_mouse_event.js index c7fe104b..829b6236 100644 --- a/test/utils/make_mouse_event.js +++ b/test/utils/make_mouse_event.js @@ -1,13 +1,16 @@ -export default function(lng = 0, lat = 0, eventProperties = {}) { +export default function (lng = 0, lat = 0, eventProperties = {}) { const e = { - originalEvent: Object.assign({ - stopPropagation() {}, - button: 0, - clientX: lng, - clientY: lat - }, eventProperties), - point: {x: lng, y:lat}, - lngLat: {lng, lat} + originalEvent: Object.assign( + { + stopPropagation() {}, + button: 0, + clientX: lng, + clientY: lat + }, + eventProperties + ), + point: { x: lng, y: lat }, + lngLat: { lng, lat } }; return e; diff --git a/test/utils/make_touch_event.js b/test/utils/make_touch_event.js index 78e120bf..e11e80e8 100644 --- a/test/utils/make_touch_event.js +++ b/test/utils/make_touch_event.js @@ -1,14 +1,17 @@ -export default function(lng = 0, lat = 0, eventProperties = {}) { +export default function (lng = 0, lat = 0, eventProperties = {}) { const e = { - originalEvent: Object.assign({ - stopPropagation() {}, - preventDefault() {}, - button: 0, - clientX: lng, - clientY: lat - }, eventProperties), - point: {x: lng, y:lat}, - lngLat: {lng, lat} + originalEvent: Object.assign( + { + stopPropagation() {}, + preventDefault() {}, + button: 0, + clientX: lng, + clientY: lat + }, + eventProperties + ), + point: { x: lng, y: lat }, + lngLat: { lng, lat } }; return e; diff --git a/vite.config.js b/vite.config.js index 9a000cd0..f1a0ae34 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,6 +4,6 @@ import tsconfigPaths from 'vite-plugin-tsconfig-paths'; export default defineConfig({ plugins: [tsconfigPaths()], build: { - target: 'esnext', // Ensure compatibility with modern JavaScript + target: 'esnext' // Ensure compatibility with modern JavaScript } }); From 6c95cc9775050218001fa0f21c87596ebc1e0b71 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 15:19:11 +0200 Subject: [PATCH 07/59] Fix bad reference to getFeaturesAt --- package.json | 4 ++-- src/api.ts | 2 +- src/events.ts | 2 +- src/lib/features_at.ts | 28 +++++++++++------------ src/lib/get_features_at_and_set_cursor.ts | 3 ++- src/lib/index.ts | 2 +- src/lib/theme.ts | 2 -- src/modes/mode_interface_accessors.ts | 2 +- test/features_at.test.js | 2 +- 9 files changed, 22 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 165a511d..62adec59 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", - "lint": "eslint index.ts src test bench", + "lint": "eslint index.ts src bench test", "pretest": "npm run lint", "test": "node --test --import ./test/mock-browser.js", "coverage": "node --test --import ./test/mock-browser.js --experimental-test-coverage", @@ -91,7 +91,7 @@ "dist/mapbox-gl-draw*" ], "lint-staged": { - "**/*.ts": [ + "**/*.{js,ts}": [ "eslint", "prettier --write" ] diff --git a/src/api.ts b/src/api.ts index d7fd8bd2..88434676 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,7 +1,7 @@ import isEqual from 'fast-deep-equal'; import normalize from '@mapbox/geojson-normalize'; import { generateID } from './lib/id'; -import { featuresAt } from './lib/features_at'; +import * as featuresAt from './lib/features_at'; import stringSetsAreEqual from './lib/string_sets_are_equal'; import * as Constants from './constants'; import StringSet from './lib/string_set'; diff --git a/src/events.ts b/src/events.ts index 58eb3207..ae462d67 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,6 +1,6 @@ import setupModeHandler from './lib/mode_handler'; import { getFeatureAtAndSetCursors } from './lib/get_features_at_and_set_cursor'; -import { featuresAt } from './lib/features_at'; +import * as featuresAt from './lib/features_at'; import isClick from './lib/is_click'; import isTap from './lib/is_tap'; import * as Constants from './constants'; diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index c160d138..a9d7e6ef 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -14,21 +14,7 @@ const META_TYPES = [ Constants.meta.VERTEX ]; -// Requires either event or bbox -export default { - click: featuresAtClick, - touch: featuresAtTouch -}; - -function featuresAtClick(event: Event, bbox: BBox, ctx: DrawCTX) { - return featuresAt(event, bbox, ctx, ctx.options.clickBuffer); -} - -function featuresAtTouch(event: Event, bbox: BBox, ctx: DrawCTX) { - return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); -} - -export const featuresAt = ( +const featuresAt = ( event: Event, bbox: BBox, ctx: DrawCTX, @@ -60,3 +46,15 @@ export const featuresAt = ( return sortFeatures(uniqueFeatures); }; + +function featuresAtClick(event: Event, bbox: BBox, ctx: DrawCTX) { + return featuresAt(event, bbox, ctx, ctx.options.clickBuffer); +} + +function featuresAtTouch(event: Event, bbox: BBox, ctx: DrawCTX) { + return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); +} + +// Requires either event or bbox +export const click = featuresAtClick; +export const touch = featuresAtTouch; diff --git a/src/lib/get_features_at_and_set_cursor.ts b/src/lib/get_features_at_and_set_cursor.ts index 812ac143..d7e74fb2 100644 --- a/src/lib/get_features_at_and_set_cursor.ts +++ b/src/lib/get_features_at_and_set_cursor.ts @@ -1,8 +1,9 @@ -import { featuresAt } from './features_at'; +import * as featuresAt from './features_at'; import * as Constants from '../constants'; import type { DrawCTX } from '../types/types'; export const getFeatureAtAndSetCursors = (event: Event, ctx: DrawCTX) => { + console.log('HELLO', featuresAt); const features = featuresAt.click(event, null, ctx); const classes = { mouse: Constants.cursors.NONE }; diff --git a/src/lib/index.ts b/src/lib/index.ts index 263bbdaa..3eb28543 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -5,7 +5,7 @@ import createSupplementaryPoints from './create_supplementary_points'; import createVertex from './create_vertex'; import doubleClickZoom from './double_click_zoom'; import euclideanDistance from './euclidean_distance'; -import { featuresAt } from './features_at'; +import * as featuresAt from './features_at'; import { getFeatureAtAndSetCursors } from './get_features_at_and_set_cursor'; import isClick from './is_click'; import isEventAtCoordinates from './is_event_at_coordinates'; diff --git a/src/lib/theme.ts b/src/lib/theme.ts index bd05f970..c45a9465 100644 --- a/src/lib/theme.ts +++ b/src/lib/theme.ts @@ -1,5 +1,3 @@ -/* eslint comma-dangle: ["error", "always-multiline"] */ - const blue = '#3bb2d0'; const orange = '#fbb03b'; const white = '#fff'; diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index 4bfe0983..c90f3f89 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -1,5 +1,5 @@ import * as Constants from '../constants'; -import { featuresAt } from '../lib/features_at'; +import * as featuresAt from '../lib/features_at'; import Point from '../feature_types/point'; import LineString from '../feature_types/line_string'; import Polygon from '../feature_types/polygon'; diff --git a/test/features_at.test.js b/test/features_at.test.js index b7ced10c..8a68095a 100644 --- a/test/features_at.test.js +++ b/test/features_at.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import { featuresAt } from '../src/lib/features_at'; +import * as featuresAt from '../src/lib/features_at'; import styles from '../src/lib/theme'; import * as Constants from '../src/constants'; import setupOptions from '../src/options'; From 209890326894c58da84b045c2784e6baca88b291 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 15:41:30 +0200 Subject: [PATCH 08/59] More TypeScript setup --- package.json | 2 +- src/lib/get_features_at_and_set_cursor.ts | 1 - tsconfig.json | 10 ++++++++-- tsconfig.tsbuildinfo | 1 - 4 files changed, 9 insertions(+), 5 deletions(-) delete mode 100644 tsconfig.tsbuildinfo diff --git a/package.json b/package.json index 62adec59..4ac63f8a 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "start-server": "vite --config vite.config.js", "start-bench": "run-p build-token watch watch-bench \"start-server --base . .\"", "start": "run-p build-token start-server", - "format": "prettier --write '**/*.{js,ts,tsx,css}'", + "format": "prettier --write '**/*.{js,ts,css}'", "prepare": "husky" }, "devDependencies": { diff --git a/src/lib/get_features_at_and_set_cursor.ts b/src/lib/get_features_at_and_set_cursor.ts index d7e74fb2..7869228f 100644 --- a/src/lib/get_features_at_and_set_cursor.ts +++ b/src/lib/get_features_at_and_set_cursor.ts @@ -3,7 +3,6 @@ import * as Constants from '../constants'; import type { DrawCTX } from '../types/types'; export const getFeatureAtAndSetCursors = (event: Event, ctx: DrawCTX) => { - console.log('HELLO', featuresAt); const features = featuresAt.click(event, null, ctx); const classes = { mouse: Constants.cursors.NONE }; diff --git a/tsconfig.json b/tsconfig.json index 398bf53d..724b3969 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,8 +3,14 @@ "module": "ESNext", "target": "ESNext", "moduleResolution": "Node", + "skipLibCheck": true, "strict": true, "esModuleInterop": true, - "declaration": true - } + "noEmit": true + }, + "include": [ + "./src/**/*", + "./test/**/*", + "./bench/**/*" + ] } diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo deleted file mode 100644 index 804e25df..00000000 --- a/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./src/constants.ts","./src/types/fast-deep-equal.d.ts","./src/types/geojson-area.d.ts","./src/types/geojson-flatten.d.ts","./src/types/point-geometry.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/globals.global.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/keyv/src/index.d.ts","./node_modules/@types/http-cache-semantics/index.d.ts","./node_modules/@types/responselike/index.d.ts","./node_modules/@types/cacheable-request/index.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/geojson/index.d.ts","./node_modules/@types/geojson-vt/index.d.ts","./node_modules/@types/json5/index.d.ts","./node_modules/@types/keyv/index.d.ts","./node_modules/@types/mapbox__point-geometry/index.d.ts","./node_modules/@types/pbf/index.d.ts","./node_modules/@mapbox/point-geometry/index.d.ts","./node_modules/@types/mapbox__vector-tile/index.d.ts","./node_modules/@types/minimist/index.d.ts","./node_modules/@types/normalize-package-data/index.d.ts","./node_modules/@types/resolve/index.d.ts","./node_modules/@types/supercluster/index.d.ts"],"fileIdsList":[[98],[68,71,97,98,105,106,107,108],[98,111],[68,98,105],[52,98,111,116],[53,98],[56,98],[57,62,98],[58,68,69,76,86,97,98],[58,59,68,76,98],[60,98],[61,62,69,77,98],[62,86,94,98],[63,65,68,76,98],[64,98],[65,66,98],[67,68,98],[68,98],[68,69,70,86,97,98],[68,69,70,86,89,98],[98,102],[71,76,86,97,98],[68,69,71,72,76,86,94,97,98],[71,73,86,94,97,98],[53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104],[68,74,98],[75,97,98],[65,68,76,86,98],[77,98],[78,98],[56,79,98],[80,96,98,102],[81,98],[82,98],[68,83,84,98],[83,85,98,100],[68,86,87,88,89,98],[86,88,98],[86,87,98],[89,98],[90,98],[68,92,93,98],[92,93,98],[62,76,86,94,98],[95,98],[76,96,98],[57,71,82,97,98],[62,98],[86,98,99],[98,100],[98,101],[57,62,68,70,79,86,97,98,100,102],[86,98,103],[71,86,98,105]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"092c2bfe125ce69dbb1223c85d68d4d2397d7d8411867b5cc03cec902c233763","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},"1b60eb59d9f48d6eee9d0402b286824b926bee768ec2f01755e926193a29f7f0","d2b46f22255daef82ebf0aa0d2028ea163739ff6b21dbaf31cf748864bebe1f4","f6e324ff4a8b9d7755aebb679dadcc5dbab5ae72b8c4436f7a541188e2c5a890","8cd02a0c1fa163d043a6a5444c412db2b6cf88228739580ed80b922949acec00","d0e5c906b91d9dd11dd5d9a61f82cd5b9a4f36d6b7514cc9481f3e6ead4a6946",{"version":"9122ed7070e054b73ebab37c2373a196def2d90e7d1a9a7fcd9d46b0e51fae78","impliedFormat":1},{"version":"a69c09dbea52352f479d3e7ac949fde3d17b195abe90b045d619f747b38d6d1a","impliedFormat":1},{"version":"77f0b5c6a193a699c9f7d7fb0578e64e562d271afa740783665d2a827104a873","affectsGlobalScope":true,"impliedFormat":1},{"version":"21a167fec8f933752fb8157f06d28fab6817af3ad9b0bdb1908a10762391eab9","impliedFormat":1},{"version":"002d6d5f044365b3fbfba0ba9be3bb57cac09b81547c8df4b0795755d2081d90","affectsGlobalScope":true,"impliedFormat":1},{"version":"0c0cee62cb619aed81133b904f644515ba3064487002a7da83fd8aa07b1b4abd","impliedFormat":1},{"version":"5a94487653355b56018122d92392beb2e5f4a6c63ba5cef83bbe1c99775ef713","impliedFormat":1},{"version":"d5135ad93b33adcce80b18f8065087934cdc1730d63db58562edcf017e1aad9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"82408ed3e959ddc60d3e9904481b5a8dc16469928257af22a3f7d1a3bc7fd8c4","impliedFormat":1},{"version":"c4cfc9a6e2ebb8bc8c0e2392dfc4056993ced3b35069ebf132ac18ca7a562881","impliedFormat":1},{"version":"bb9c4ffa5e6290c6980b63c815cdd1625876dadb2efaf77edbe82984be93e55e","impliedFormat":1},{"version":"75ecef44f126e2ae018b4abbd85b6e8a2e2ba1638ebec56cc64274643ce3567b","impliedFormat":1},{"version":"f30bb836526d930a74593f7b0f5c1c46d10856415a8f69e5e2fc3db80371e362","impliedFormat":1},{"version":"14b5aa23c5d0ae1907bc696ac7b6915d88f7d85799cc0dc2dcf98fbce2c5a67c","impliedFormat":1},{"version":"5c439dafdc09abe4d6c260a96b822fa0ba5be7203c71a63ab1f1423cd9e838ea","impliedFormat":1},{"version":"bae4ea23beb8397755b935cb84d3cdc6cdb0b1b4a329b90de9fc6c8774d71994","affectsGlobalScope":true,"impliedFormat":1},{"version":"cec36af22f514322f870e81d30675c78df82ae8bf4863f5fd4e4424c040c678d","impliedFormat":1},{"version":"df36874d9e56aff601e921c4b3971d37cf66d14f6455935ce821e6cad13b1823","impliedFormat":1},{"version":"68915895d4a136df5cf5f90aaa41d8e1e47ec047e7781a150b5d0cf273dbb7a9","impliedFormat":1},{"version":"acfbb5aaef964e1d441f961a1846197f03241dba3c63b1e4d1903684888ef465","impliedFormat":1},{"version":"09416dd69576b03a3f485adf329a02f043e4a481e060ef5b208194e488d31fd9","impliedFormat":1},{"version":"2c828a5405191d006115ab34e191b8474bc6c86ffdc401d1a9864b1b6e088a58","impliedFormat":1},{"version":"e8b18c6385ff784228a6f369694fcf1a6b475355ba89090a88de13587a9391d5","affectsGlobalScope":true,"impliedFormat":1},{"version":"76527127c8b749bee5977408861ce3ee56ec19ddcea8704c628f98ca610283e6","impliedFormat":1},{"version":"a907bf91df26df2400858ef75f749498fb5cf00062bf90a737ac3949cc07978d","impliedFormat":1},{"version":"cb92bc2e42b261e4299025756f1beb826b3d9666a3f0d46f8a7254ca512f57e4","impliedFormat":1},{"version":"cb4f3f03480e1727eae46400606cecaa97f550186ff8fa909ebc00db4180531b","impliedFormat":1},{"version":"b3624aed92dab6da8484280d3cb3e2f4130ec3f4ef3f8201c95144ae9e898bb6","affectsGlobalScope":true,"impliedFormat":1},{"version":"5153a2fd150e46ce57bb3f8db1318d33f6ad3261ed70ceeff92281c0608c74a3","impliedFormat":1},{"version":"d1a78a3c5708807e8de3e399f91df4797c62e44b02195eefc2209b2e713e54ee","impliedFormat":1},{"version":"36b03690b628eab08703d63f04eaa89c5df202e5f1edf3989f13ad389cd2c091","impliedFormat":1},{"version":"0effadd232a20498b11308058e334d3339cc5bf8c4c858393e38d9d4c0013dcf","impliedFormat":1},{"version":"25846d43937c672bab7e8195f3d881f93495df712ee901860effc109918938cc","impliedFormat":1},{"version":"556bf5c36deb62cffa1bf697c1789fe008ec82db0273025001db66732714e9d9","impliedFormat":1},{"version":"1b952304137851e45bc009785de89ada562d9376177c97e37702e39e60c2f1ff","impliedFormat":1},{"version":"806ef4cac3b3d9fa4a48d849c8e084d7c72fcd7b16d76e06049a9ed742ff79c0","affectsGlobalScope":true,"impliedFormat":1},{"version":"44b8b584a338b190a59f4f6929d072431950c7bd92ec2694821c11bce180c8a5","impliedFormat":1},{"version":"23b89798789dffbd437c0c423f5d02d11f9736aea73d6abf16db4f812ff36eda","impliedFormat":1},{"version":"0830071706fa0e477fb5e95f0955cc1062b5948b146b7d4e03a126f12ad6085f","impliedFormat":1},{"version":"970a90f76d4d219ad60819d61f5994514087ba94c985647a3474a5a3d12714ed","affectsGlobalScope":true,"impliedFormat":1},{"version":"664d8f2d59164f2e08c543981453893bc7e003e4dfd29651ce09db13e9457980","impliedFormat":1},{"version":"4c8525f256873c7ba3135338c647eaf0ca7115a1a2805ae2d0056629461186ce","impliedFormat":1},{"version":"3c13ef48634e7b5012fcf7e8fce7496352c2d779a7201389ca96a2a81ee4314d","impliedFormat":1},{"version":"5d0a25ec910fa36595f85a67ac992d7a53dd4064a1ba6aea1c9f14ab73a023f2","impliedFormat":1},{"version":"bfe39beb986d2a2e512c091cbe924f1c415bc65de54de0e2f6a0dc6f84c183d9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2d526e6f21d8cc66ac11ada32874e95ae88d870c6c9d3d9d4e03b1d1f9ad7b8e","impliedFormat":1},{"version":"06d7c42d256f0ce6afe1b2b6cfbc97ab391f29dadb00dd0ae8e8f23f5bc916c3","impliedFormat":1},{"version":"ec4bd1b200670fb567920db572d6701ed42a9641d09c4ff6869768c8f81b404c","impliedFormat":1},{"version":"e59a892d87e72733e2a9ca21611b9beb52977be2696c7ba4b216cbbb9a48f5aa","impliedFormat":1},{"version":"d2ec52f565f0570e90b659811347bd689f8c6039b11eaaccd0f243759d46da6e","impliedFormat":1},{"version":"8a300fa9b698845a1f9c41ecbe2c5966634582a8e2020d51abcace9b55aa959e","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a12806a1bde5e9f137bb79728d87a4ceaedf04e95efc9967d3288a3c252d9a7b","impliedFormat":1},{"version":"42baf4ca38c38deaf411ea73f37bc39ff56c6e5c761a968b64ac1b25c92b5cd8","impliedFormat":1},{"version":"d7dbe0ad36bdca8a6ecf143422a48e72cc8927bab7b23a1a2485c2f78a7022c6","impliedFormat":1},{"version":"8718fa41d7cf4aa91de4e8f164c90f88e0bf343aa92a1b9b725a9c675c64e16b","impliedFormat":1},{"version":"f992cd6cc0bcbaa4e6c810468c90f2d8595f8c6c3cf050c806397d3de8585562","impliedFormat":1},{"version":"785b9d575b49124ce01b46f5b9402157c7611e6532effa562ac6aebec0074dfc","impliedFormat":1},{"version":"d30e67059f5c545c5f8f0cc328a36d2e03b8c4a091b4301bc1d6afb2b1491a3a","impliedFormat":1},{"version":"37550007de426cbbb418582008deae1a508935eaebbd4d41e22805ad3b485ad4","impliedFormat":1},{"version":"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","impliedFormat":1},{"version":"fec943fdb3275eb6e006b35e04a8e2e99e9adf3f4b969ddf15315ac7575a93e4","impliedFormat":1},{"version":"ae4cda96b058f20db053c1f57e51257d1cffff9c0880326d2b8129ade5363402","impliedFormat":1},{"version":"12115a2a03125cb3f600e80e7f43ef57f71a2951bb6e60695fb00ac8e12b27f3","impliedFormat":1},{"version":"59ffd1f821bf240bbd89c9a10fa2fdaec9716bc292e847864efb7ccecd976d5c","impliedFormat":99},{"version":"02f7c65c690af708e9da6b09698c86d34b6b39a05acd8288a079859d920aea9f","impliedFormat":1},{"version":"fbca5ffaebf282ec3cdac47b0d1d4a138a8b0bb32105251a38acb235087d3318","impliedFormat":1},{"version":"22293bd6fa12747929f8dfca3ec1684a3fe08638aa18023dd286ab337e88a592","impliedFormat":1},{"version":"8baa5d0febc68db886c40bf341e5c90dc215a90cd64552e47e8184be6b7e3358","impliedFormat":1},{"version":"e3913b35c221b4468658743d6496b83323c895f8e5b566c48d8844c01bf24738","impliedFormat":1}],"root":[[48,52]],"options":{"esModuleInterop":true,"jsx":4,"strict":true},"referencedMap":[[117,1],[109,2],[110,1],[112,3],[111,1],[107,1],[113,1],[114,4],[115,1],[118,5],[119,1],[53,6],[54,6],[56,7],[57,8],[58,9],[59,10],[60,11],[61,12],[62,13],[63,14],[64,15],[65,16],[66,16],[67,17],[68,18],[69,19],[70,20],[55,21],[104,1],[71,22],[72,23],[73,24],[105,25],[74,26],[75,27],[76,28],[77,29],[78,30],[79,31],[80,32],[81,33],[82,34],[83,35],[84,35],[85,36],[86,37],[88,38],[87,39],[89,40],[90,41],[91,1],[92,42],[93,43],[94,44],[95,45],[96,46],[97,47],[98,48],[99,49],[100,50],[101,51],[102,52],[103,53],[120,1],[116,1],[121,1],[108,54],[122,3],[106,18],[46,1],[47,1],[8,1],[10,1],[9,1],[2,1],[11,1],[12,1],[13,1],[14,1],[15,1],[16,1],[17,1],[18,1],[3,1],[19,1],[20,1],[4,1],[21,1],[25,1],[22,1],[23,1],[24,1],[26,1],[27,1],[28,1],[5,1],[29,1],[30,1],[31,1],[32,1],[6,1],[36,1],[33,1],[34,1],[35,1],[37,1],[7,1],[38,1],[43,1],[44,1],[39,1],[40,1],[41,1],[42,1],[1,1],[45,1],[48,1],[49,1],[50,1],[51,1],[52,1]],"semanticDiagnosticsPerFile":[[55,[{"start":2311,"length":11,"messageText":"Subsequent variable declarations must have the same type. Variable 'AbortSignal' must be of type '{ new (): AbortSignal; prototype: AbortSignal; abort(reason?: any): AbortSignal; any(signals: AbortSignal[]): AbortSignal; timeout(milliseconds: number): AbortSignal; }', but here has type '{ new (): AbortSignal; prototype: AbortSignal; }'.","category":1,"code":2403,"relatedInformation":[{"file":"./node_modules/typescript/lib/lib.dom.d.ts","start":69084,"length":11,"messageText":"'AbortSignal' was also declared here.","category":3,"code":6203}]}]],[75,[{"start":3888,"length":7,"messageText":"Overload signatures must all be optional or required.","category":1,"code":2386}]],[118,[{"start":456,"length":5,"messageText":"Cannot use namespace 'Point' as a type.","category":1,"code":2709}]]],"version":"5.8.2"} \ No newline at end of file From dd83eeda7575d31e59830f6cd9f5d818d5902678 Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 17:03:20 +0200 Subject: [PATCH 09/59] Convet more to TypeScript --- package.json | 2 +- src/events.ts | 2 +- src/feature_types/line_string.ts | 12 +++++++----- src/lib/create_supplementary_points.ts | 2 +- src/lib/create_vertex.ts | 19 ++++--------------- src/lib/double_click_zoom.ts | 8 +++++--- src/lib/euclidean_distance.ts | 4 +++- src/lib/index.ts | 10 +++++----- src/lib/is_click.ts | 23 ++++++++++++----------- src/lib/is_event_at_coordinates.ts | 9 ++++++--- src/lib/is_tap.ts | 19 ++++++++++--------- src/lib/mouse_event_point.ts | 11 ++--------- src/lib/to_dense_array.ts | 8 +------- src/modes/direct_select.ts | 2 +- src/modes/draw_line_string.ts | 6 +++--- src/modes/draw_polygon.ts | 6 +++--- src/modes/simple_select.ts | 2 +- src/types/types.ts | 25 +++++++++++++++++++++++++ src/ui.ts | 6 ++++-- test/create_vertex.test.js | 2 +- test/is_event_at_coordinates.test.js | 2 +- test/is_tap.test.js | 2 +- 22 files changed, 98 insertions(+), 84 deletions(-) diff --git a/package.json b/package.json index 4ac63f8a..59ed25d8 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", - "lint": "eslint index.ts src bench test", + "lint": "eslint index.ts bench test", "pretest": "npm run lint", "test": "node --test --import ./test/mock-browser.js", "coverage": "node --test --import ./test/mock-browser.js --experimental-test-coverage", diff --git a/src/events.ts b/src/events.ts index ae462d67..36deaa13 100644 --- a/src/events.ts +++ b/src/events.ts @@ -2,7 +2,7 @@ import setupModeHandler from './lib/mode_handler'; import { getFeatureAtAndSetCursors } from './lib/get_features_at_and_set_cursor'; import * as featuresAt from './lib/features_at'; import isClick from './lib/is_click'; -import isTap from './lib/is_tap'; +import { isTap } from './lib/is_tap'; import * as Constants from './constants'; import objectToMode from './modes/object_to_mode'; diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index b768f551..a977a7da 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -1,6 +1,8 @@ import Feature from './feature.js'; +import type { FeatureCollection } from 'geojson'; +import type { DrawCTX } from '../types/types'; -const LineString = function (ctx, geojson) { +const LineString = function (ctx: DrawCTX, geojson: FeatureCollection) { Feature.call(this, ctx, geojson); }; @@ -10,23 +12,23 @@ LineString.prototype.isValid = function () { return this.coordinates.length > 1; }; -LineString.prototype.addCoordinate = function (path, lng, lat) { +LineString.prototype.addCoordinate = function (path: string, lng: number, lat: number) { this.changed(); const id = parseInt(path, 10); this.coordinates.splice(id, 0, [lng, lat]); }; -LineString.prototype.getCoordinate = function (path) { +LineString.prototype.getCoordinate = function (path: string) { const id = parseInt(path, 10); return JSON.parse(JSON.stringify(this.coordinates[id])); }; -LineString.prototype.removeCoordinate = function (path) { +LineString.prototype.removeCoordinate = function (path: string) { this.changed(); this.coordinates.splice(parseInt(path, 10), 1); }; -LineString.prototype.updateCoordinate = function (path, lng, lat) { +LineString.prototype.updateCoordinate = function (path: string, lng: number, lat: number) { const id = parseInt(path, 10); this.coordinates[id] = [lng, lat]; this.changed(); diff --git a/src/lib/create_supplementary_points.ts b/src/lib/create_supplementary_points.ts index a8a4033e..f065af62 100644 --- a/src/lib/create_supplementary_points.ts +++ b/src/lib/create_supplementary_points.ts @@ -1,4 +1,4 @@ -import createVertex from './create_vertex'; +import { createVertex } from './create_vertex'; import createMidpoint from './create_midpoint'; import * as Constants from '../constants'; diff --git a/src/lib/create_vertex.ts b/src/lib/create_vertex.ts index 2d9d90bb..627784f9 100644 --- a/src/lib/create_vertex.ts +++ b/src/lib/create_vertex.ts @@ -1,20 +1,9 @@ import * as Constants from '../constants'; +import type { Feature } from 'geojson'; -/** - * Returns GeoJSON for a Point representing the - * vertex of another feature. - * - * @param {string} parentId - * @param {Array} coordinates - * @param {string} path - Dot-separated numbers indicating exactly - * where the point exists within its parent feature's coordinates. - * @param {boolean} selected - * @return {GeoJSON} Point - */ - -export default function (parentId, coordinates, path, selected) { +export const createVertex = (parentId: string, coordinates: [number, number], path: string, selected: boolean): Feature => { return { - type: Constants.geojsonTypes.FEATURE, + type: Constants.geojsonTypes.FEATURE as 'Feature', properties: { meta: Constants.meta.VERTEX, parent: parentId, @@ -24,7 +13,7 @@ export default function (parentId, coordinates, path, selected) { : Constants.activeStates.INACTIVE }, geometry: { - type: Constants.geojsonTypes.POINT, + type: Constants.geojsonTypes.POINT as 'Point', coordinates } }; diff --git a/src/lib/double_click_zoom.ts b/src/lib/double_click_zoom.ts index f753a09b..2f167ea4 100644 --- a/src/lib/double_click_zoom.ts +++ b/src/lib/double_click_zoom.ts @@ -1,5 +1,7 @@ -export default { - enable(ctx) { +import type { DrawCTX } from '../types/types'; + +export const doubleClickZoom = { + enable: (ctx: DrawCTX) => { setTimeout(() => { // First check we've got a map and some context. if ( @@ -15,7 +17,7 @@ export default { ctx.map.doubleClickZoom.enable(); }, 0); }, - disable(ctx) { + disable: (ctx: DrawCTX) => { setTimeout(() => { if (!ctx.map || !ctx.map.doubleClickZoom) return; // Always disable here, as it's necessary in some cases. diff --git a/src/lib/euclidean_distance.ts b/src/lib/euclidean_distance.ts index 4c0032cb..70880d51 100644 --- a/src/lib/euclidean_distance.ts +++ b/src/lib/euclidean_distance.ts @@ -1,4 +1,6 @@ -export default function (a, b) { +import type { XY } from '../types/types'; + +export const euclideanDistance = (a: XY, b: XY) => { const x = a.x - b.x; const y = a.y - b.y; return Math.sqrt(x * x + y * y); diff --git a/src/lib/index.ts b/src/lib/index.ts index 3eb28543..8da46c77 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -2,14 +2,14 @@ import * as CommonSelectors from './common_selectors'; import constrainFeatureMovement from './constrain_feature_movement'; import createMidPoint from './create_midpoint'; import createSupplementaryPoints from './create_supplementary_points'; -import createVertex from './create_vertex'; -import doubleClickZoom from './double_click_zoom'; -import euclideanDistance from './euclidean_distance'; +import { createVertex } from './create_vertex'; +import { doubleClickZoom } from './double_click_zoom'; +import { euclideanDistance } from './euclidean_distance'; import * as featuresAt from './features_at'; import { getFeatureAtAndSetCursors } from './get_features_at_and_set_cursor'; import isClick from './is_click'; -import isEventAtCoordinates from './is_event_at_coordinates'; -import isTap from './is_tap'; +import { isEventAtCoordinates } from './is_event_at_coordinates'; +import { isTap } from './is_tap'; import mapEventToBoundingBox from './map_event_to_bounding_box'; import ModeHandler from './mode_handler'; import moveFeatures from './move_features'; diff --git a/src/lib/is_click.ts b/src/lib/is_click.ts index 6f65fa53..15fca01e 100644 --- a/src/lib/is_click.ts +++ b/src/lib/is_click.ts @@ -1,16 +1,17 @@ -import euclideanDistance from './euclidean_distance.js'; +import { euclideanDistance } from './euclidean_distance.js'; +import type { Entry } from '../types/types'; -const FINE_TOLERANCE = 4; -const GROSS_TOLERANCE = 12; -const INTERVAL = 500; - -export default function isClick(start, end, options = {}) { - const fineTolerance = - options.fineTolerance != null ? options.fineTolerance : FINE_TOLERANCE; - const grossTolerance = - options.grossTolerance != null ? options.grossTolerance : GROSS_TOLERANCE; - const interval = options.interval != null ? options.interval : INTERVAL; +interface Options { + fineTolerance: number; + grossTolerance: number; + interval: number; +} +export default function isClick(start: Entry, end: Entry, { + fineTolerance = 4, + grossTolerance = 12, + interval = 500 +}: Options) { start.point = start.point || end.point; start.time = start.time || end.time; const moveDistance = euclideanDistance(start.point, end.point); diff --git a/src/lib/is_event_at_coordinates.ts b/src/lib/is_event_at_coordinates.ts index e810f3b8..8df832cf 100644 --- a/src/lib/is_event_at_coordinates.ts +++ b/src/lib/is_event_at_coordinates.ts @@ -1,8 +1,11 @@ -function isEventAtCoordinates(event, coordinates) { +export const isEventAtCoordinates = (event: { + lngLat: { + lng: number, + lat: number + } +}, coordinates: [number, number]) => { if (!event.lngLat) return false; return ( event.lngLat.lng === coordinates[0] && event.lngLat.lat === coordinates[1] ); } - -export default isEventAtCoordinates; diff --git a/src/lib/is_tap.ts b/src/lib/is_tap.ts index 979f3d21..558db0fb 100644 --- a/src/lib/is_tap.ts +++ b/src/lib/is_tap.ts @@ -1,16 +1,17 @@ -import euclideanDistance from './euclidean_distance.js'; +import { euclideanDistance } from './euclidean_distance.js'; +import type { Entry } from '../types/types'; -export const TAP_TOLERANCE = 25; -export const TAP_INTERVAL = 250; - -export default function isTap(start, end, options = {}) { - const tolerance = - options.tolerance != null ? options.tolerance : TAP_TOLERANCE; - const interval = options.interval != null ? options.interval : TAP_INTERVAL; +interface Options { + tolerance: number; + interval: number; +} +export const isTap = (start: Entry, end: Entry, { + tolerance = 25, + interval = 250 +}: Options) => { start.point = start.point || end.point; start.time = start.time || end.time; const moveDistance = euclideanDistance(start.point, end.point); - return moveDistance < tolerance && end.time - start.time < interval; } diff --git a/src/lib/mouse_event_point.ts b/src/lib/mouse_event_point.ts index a6b70f4a..4e8b8127 100644 --- a/src/lib/mouse_event_point.ts +++ b/src/lib/mouse_event_point.ts @@ -1,14 +1,7 @@ import Point from '@mapbox/point-geometry'; +import type { PointLike } from 'mapbox-gl'; -/** - * Returns a Point representing a mouse event's position - * relative to a containing element. - * - * @param {MouseEvent} mouseEvent - * @param {Node} container - * @returns {Point} - */ -function mouseEventPoint(mouseEvent, container) { +function mouseEventPoint(mouseEvent: MouseEvent, container: HTMLElement): PointLike { const rect = container.getBoundingClientRect(); return new Point( mouseEvent.clientX - rect.left - (container.clientLeft || 0), diff --git a/src/lib/to_dense_array.ts b/src/lib/to_dense_array.ts index 6553745f..1c886a66 100644 --- a/src/lib/to_dense_array.ts +++ b/src/lib/to_dense_array.ts @@ -1,10 +1,4 @@ -/** - * Derive a dense array (no `undefined`s) from a single value or array. - * - * @param {any} x - * @return {Array} - */ -function toDenseArray(x) { +const toDenseArray = (x: unknown): Array => { return [].concat(x).filter(y => y !== undefined); } diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 1b68b0e4..dc1748c9 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -7,7 +7,7 @@ import { } from '../lib/common_selectors'; import createSupplementaryPoints from '../lib/create_supplementary_points'; import constrainFeatureMovement from '../lib/constrain_feature_movement'; -import doubleClickZoom from '../lib/double_click_zoom'; +import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; diff --git a/src/modes/draw_line_string.ts b/src/modes/draw_line_string.ts index ba8e914e..8ba84fd1 100644 --- a/src/modes/draw_line_string.ts +++ b/src/modes/draw_line_string.ts @@ -1,8 +1,8 @@ import * as CommonSelectors from '../lib/common_selectors'; -import isEventAtCoordinates from '../lib/is_event_at_coordinates'; -import doubleClickZoom from '../lib/double_click_zoom'; +import { isEventAtCoordinates } from '../lib/is_event_at_coordinates'; +import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; -import createVertex from '../lib/create_vertex'; +import { createVertex } from '../lib/create_vertex'; const DrawLineString = {}; diff --git a/src/modes/draw_polygon.ts b/src/modes/draw_polygon.ts index 586352e1..37808ab9 100644 --- a/src/modes/draw_polygon.ts +++ b/src/modes/draw_polygon.ts @@ -1,8 +1,8 @@ import * as CommonSelectors from '../lib/common_selectors'; -import doubleClickZoom from '../lib/double_click_zoom'; +import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; -import isEventAtCoordinates from '../lib/is_event_at_coordinates'; -import createVertex from '../lib/create_vertex'; +import { isEventAtCoordinates } from '../lib/is_event_at_coordinates'; +import { createVertex } from '../lib/create_vertex'; const DrawPolygon = {}; diff --git a/src/modes/simple_select.ts b/src/modes/simple_select.ts index 347bc565..ede18a34 100644 --- a/src/modes/simple_select.ts +++ b/src/modes/simple_select.ts @@ -2,7 +2,7 @@ import * as CommonSelectors from '../lib/common_selectors'; import mouseEventPoint from '../lib/mouse_event_point'; import createSupplementaryPoints from '../lib/create_supplementary_points'; import StringSet from '../lib/string_set'; -import doubleClickZoom from '../lib/double_click_zoom'; +import { doubleClickZoom } from '../lib/double_click_zoom'; import moveFeatures from '../lib/move_features'; import * as Constants from '../constants'; diff --git a/src/types/types.ts b/src/types/types.ts index f5856064..eeea6628 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -18,6 +18,13 @@ import type { MapTouchEvent as MapboxMapTouchEvent } from 'mapbox-gl'; +export type XY = { x: number, y: number }; + +export interface Entry { + point: XY; + time: number; +} + export interface MapMouseEvent extends MapboxMapMouseEvent { featureTarget: DrawFeature; } @@ -127,8 +134,15 @@ interface DrawActionableState { uncombineFeatures: boolean; } +interface _DrawCTS extends DrawCTX { + store: { + getInitialConfigValue: (config: string) => boolean; + } +} + export interface DrawCTX { map: Map; + container: HTMLElement, drawConfig: DrawOptions; setSelected(features?: string | string[]): void; setSelectedCoordinates( @@ -156,6 +170,17 @@ export interface DrawCTX { newFeature(geojson: GeoJSON): DrawFeature; isInstanceOf(type: string, feature: object): boolean; doRender(id: string): void; + ui: DrawUI; + _ctx: _DrawCTS; +} + +export interface DrawUI { + queueMapClasses: (options: { mode: null, feature: null, mouse: null }) => void; + setActiveButton: (id: string) => void; + updateMapClasses: () => void; + clearMapClasses: () => void; + addButtons: () => void; + removeButtons: () => void; } export interface DrawCustomMode< diff --git a/src/ui.ts b/src/ui.ts index 2815d2b7..0e12a2f1 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,8 +1,10 @@ import * as Constants from './constants'; +import type { DrawCTX } from './types/types'; + const classTypes = ['mode', 'feature', 'mouse']; -export default function (ctx) { +export default function (ctx: DrawCTX) { const buttonElements = {}; let activeButton = null; @@ -53,7 +55,7 @@ export default function (ctx) { currentMapClasses = Object.assign(currentMapClasses, nextMapClasses); } - function createControlButton(id, options = {}) { + function createControlButton(id: string, options = {}) { const button = document.createElement('button'); button.className = `${Constants.classes.CONTROL_BUTTON} ${options.className}`; button.setAttribute('title', options.title); diff --git a/test/create_vertex.test.js b/test/create_vertex.test.js index ff5cd2ae..9b839ead 100644 --- a/test/create_vertex.test.js +++ b/test/create_vertex.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import createVertex from '../src/lib/create_vertex.js'; +import { createVertex } from '../src/lib/create_vertex.js'; test('createVertex', () => { assert.deepEqual(createVertex('foo', [1, 2], '3.4.5', true), { diff --git a/test/is_event_at_coordinates.test.js b/test/is_event_at_coordinates.test.js index 618ede96..0abefbaf 100644 --- a/test/is_event_at_coordinates.test.js +++ b/test/is_event_at_coordinates.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import isEventAtCoordinates from '../src/lib/is_event_at_coordinates.js'; +import { isEventAtCoordinates } from '../src/lib/is_event_at_coordinates.js'; test('isEventAtCoordinates', () => { assert.ok( diff --git a/test/is_tap.test.js b/test/is_tap.test.js index 136e3bf6..0764d2cc 100644 --- a/test/is_tap.test.js +++ b/test/is_tap.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import isTap from '../src/lib/is_tap.js'; +import { isTap } from '../src/lib/is_tap.js'; // By adding these values as options and stating them in the test, // we can know the calculation works from the tests, but tweak From 8cdbaf09f5f67e170d6eb6d9c14b0480254ec03c Mon Sep 17 00:00:00 2001 From: tristen Date: Tue, 4 Mar 2025 22:29:42 +0200 Subject: [PATCH 10/59] Tackle smaller libs --- src/api.ts | 6 ++++-- src/events.ts | 3 ++- src/lib/create_midpoint.ts | 11 ++++++----- src/lib/create_supplementary_points.ts | 2 +- src/lib/index.ts | 4 ++-- src/lib/string_sets_are_equal.ts | 2 +- src/options.ts | 6 +++--- src/render.ts | 2 +- src/setup.ts | 3 ++- src/store.ts | 3 ++- 10 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/api.ts b/src/api.ts index 88434676..e25f7832 100644 --- a/src/api.ts +++ b/src/api.ts @@ -2,7 +2,7 @@ import isEqual from 'fast-deep-equal'; import normalize from '@mapbox/geojson-normalize'; import { generateID } from './lib/id'; import * as featuresAt from './lib/features_at'; -import stringSetsAreEqual from './lib/string_sets_are_equal'; +import { stringSetsAreEqual } from './lib/string_sets_are_equal'; import * as Constants from './constants'; import StringSet from './lib/string_set'; @@ -11,6 +11,8 @@ import LineString from './feature_types/line_string'; import Point from './feature_types/point'; import MultiFeature from './feature_types/multi_feature'; +import type { DrawCTX, Draw } from './types/types'; + const featureTypes = { Polygon, LineString, @@ -20,7 +22,7 @@ const featureTypes = { MultiPoint: MultiFeature }; -export default function (ctx, api) { +export default function (ctx: DrawCTX, api: Draw) { api.modes = Constants.modes; // API doesn't emit events by default diff --git a/src/events.ts b/src/events.ts index 36deaa13..34240bc9 100644 --- a/src/events.ts +++ b/src/events.ts @@ -5,8 +5,9 @@ import isClick from './lib/is_click'; import { isTap } from './lib/is_tap'; import * as Constants from './constants'; import objectToMode from './modes/object_to_mode'; +import type { DrawCTX } from './types/types'; -export default function (ctx) { +export default function (ctx: DrawCTX) { const modes = Object.keys(ctx.options.modes).reduce((m, k) => { m[k] = objectToMode(ctx.options.modes[k]); return m; diff --git a/src/lib/create_midpoint.ts b/src/lib/create_midpoint.ts index db62f989..f744505a 100644 --- a/src/lib/create_midpoint.ts +++ b/src/lib/create_midpoint.ts @@ -1,8 +1,9 @@ import * as Constants from '../constants'; +import type { Feature, Point } from 'geojson'; -export default function (parent, startVertex, endVertex) { - const startCoord = startVertex.geometry.coordinates; - const endCoord = endVertex.geometry.coordinates; +export const createMidpoint = (parent: string, startVertex: Feature, endVertex: Feature): Feature => { + const startCoord = (startVertex.geometry as Point).coordinates; + const endCoord = (endVertex.geometry as Point).coordinates; // If a coordinate exceeds the projection, we can't calculate a midpoint, // so run away @@ -21,7 +22,7 @@ export default function (parent, startVertex, endVertex) { }; return { - type: Constants.geojsonTypes.FEATURE, + type: Constants.geojsonTypes.FEATURE as 'Feature', properties: { meta: Constants.meta.MIDPOINT, parent, @@ -30,7 +31,7 @@ export default function (parent, startVertex, endVertex) { coord_path: endVertex.properties.coord_path }, geometry: { - type: Constants.geojsonTypes.POINT, + type: Constants.geojsonTypes.POINT as 'Point', coordinates: [mid.lng, mid.lat] } }; diff --git a/src/lib/create_supplementary_points.ts b/src/lib/create_supplementary_points.ts index f065af62..2d409df5 100644 --- a/src/lib/create_supplementary_points.ts +++ b/src/lib/create_supplementary_points.ts @@ -1,5 +1,5 @@ import { createVertex } from './create_vertex'; -import createMidpoint from './create_midpoint'; +import { createMidpoint } from './create_midpoint'; import * as Constants from '../constants'; function createSupplementaryPoints(geojson, options = {}, basePath = null) { diff --git a/src/lib/index.ts b/src/lib/index.ts index 8da46c77..c8403c23 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,6 +1,6 @@ import * as CommonSelectors from './common_selectors'; import constrainFeatureMovement from './constrain_feature_movement'; -import createMidPoint from './create_midpoint'; +import { createMidPoint } from './create_midpoint'; import createSupplementaryPoints from './create_supplementary_points'; import { createVertex } from './create_vertex'; import { doubleClickZoom } from './double_click_zoom'; @@ -15,7 +15,7 @@ import ModeHandler from './mode_handler'; import moveFeatures from './move_features'; import sortFeatures from './sort_features'; import StringSet from './string_set'; -import stringSetsAreEqual from './string_sets_are_equal'; +import { stringSetsAreEqual } from './string_sets_are_equal'; import theme from './theme'; import toDenseArray from './to_dense_array'; diff --git a/src/lib/string_sets_are_equal.ts b/src/lib/string_sets_are_equal.ts index 3b92ade6..6d10b037 100644 --- a/src/lib/string_sets_are_equal.ts +++ b/src/lib/string_sets_are_equal.ts @@ -1,4 +1,4 @@ -export default function (a, b) { +export const stringSetsAreEqual = (a: Array, b: Array) => { if (a.length !== b.length) return false; return ( JSON.stringify(a.map(id => id).sort()) === diff --git a/src/options.ts b/src/options.ts index 956af34b..4d201cbd 100644 --- a/src/options.ts +++ b/src/options.ts @@ -47,16 +47,16 @@ function addSources(styles, sourceBucket) { } export default function (options = {}) { - let withDefaults = Object.assign({}, options); + let withDefaults = { ...options} if (!options.controls) { withDefaults.controls = {}; } if (options.displayControlsDefault === false) { - withDefaults.controls = Object.assign({}, hideControls, options.controls); + withDefaults.controls = { ...hideControls, ...options.controls }; } else { - withDefaults.controls = Object.assign({}, showControls, options.controls); + withDefaults.controls = { ...showControls, ...options.controls }; } withDefaults = Object.assign({}, defaultOptions, withDefaults); diff --git a/src/render.ts b/src/render.ts index f83f818a..fe775089 100644 --- a/src/render.ts +++ b/src/render.ts @@ -43,7 +43,7 @@ export default function render() { newHotIds.forEach(id => renderFeature(id, 'hot')); newColdIds.forEach(id => renderFeature(id, 'cold')); - function renderFeature(id, source) { + function renderFeature(id: string, source: string) { const feature = store.get(id); const featureInternal = feature.internal(mode); store.ctx.events.currentModeRender(featureInternal, geojson => { diff --git a/src/setup.ts b/src/setup.ts index 8a5f9909..31abe261 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -2,8 +2,9 @@ import events from './events'; import Store from './store'; import ui from './ui'; import * as Constants from './constants'; +import type { DrawCTX } from './types/types'; -export default function (ctx) { +export default function (ctx: DrawCTX) { let controlContainer = null; let mapLoadedInterval = null; diff --git a/src/store.ts b/src/store.ts index 34058a02..60df2ca5 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,8 +2,9 @@ import toDenseArray from './lib/to_dense_array'; import StringSet from './lib/string_set'; import render from './render'; import * as Constants from './constants'; +import type { DrawCTX } from './types/types'; -export default function Store(ctx) { +export default function Store(ctx: DrawCTX) { this._features = {}; this._featureIds = new StringSet(); this._selectedFeatureIds = new StringSet(); From 0a746b8e1b92c5340643f8dc3d2253d1f7d24466 Mon Sep 17 00:00:00 2001 From: tristen Date: Wed, 5 Mar 2025 14:59:45 +0200 Subject: [PATCH 11/59] Move feature_types to classes --- src/events.ts | 2 +- src/feature_types/feature.ts | 109 +++++++++++--------- src/feature_types/line_string.ts | 73 ++++++------- src/feature_types/multi_feature.ts | 136 ++++++++++++++----------- src/feature_types/point.ts | 46 +++++---- src/feature_types/polygon.ts | 110 ++++++++++---------- src/lib/create_midpoint.ts | 2 +- src/lib/create_supplementary_points.ts | 4 +- src/lib/index.ts | 2 +- src/lib/is_click.ts | 32 ++++-- src/lib/is_event_at_coordinates.ts | 15 ++- src/lib/to_dense_array.ts | 4 +- src/modes/object_to_mode.ts | 8 +- src/store.ts | 2 +- src/types/types.ts | 24 ++++- test/draw_line_string.test.js | 2 +- test/draw_point.test.js | 2 +- test/draw_polygon.test.js | 2 +- tsconfig.json | 1 - 19 files changed, 321 insertions(+), 255 deletions(-) diff --git a/src/events.ts b/src/events.ts index 34240bc9..0223609e 100644 --- a/src/events.ts +++ b/src/events.ts @@ -4,7 +4,7 @@ import * as featuresAt from './lib/features_at'; import isClick from './lib/is_click'; import { isTap } from './lib/is_tap'; import * as Constants from './constants'; -import objectToMode from './modes/object_to_mode'; +import { objectToMode } from './modes/object_to_mode'; import type { DrawCTX } from './types/types'; export default function (ctx: DrawCTX) { diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index 8b63c782..5da855a5 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -1,38 +1,46 @@ import { generateID } from '../lib/id'; import * as Constants from '../constants'; +import type { Geometry } from 'geojson'; +import type { StrictFeature, DrawCTX } from '../types/types'; -const Feature = function (ctx, geojson) { - this.ctx = ctx; - this.properties = geojson.properties || {}; - this.coordinates = geojson.geometry.coordinates; - this.id = geojson.id || generateID(); - this.type = geojson.geometry.type; -}; +class Feature { + protected ctx: DrawCTX; + properties: Record; + coordinates: any; + id: string; + type: Geometry['type']; -Feature.prototype.changed = function () { - this.ctx.store.featureChanged(this.id); -}; + constructor(ctx: DrawCTX, geojson: StrictFeature) { + this.ctx = ctx; + this.properties = geojson.properties || {}; + this.coordinates = geojson.geometry.coordinates; + this.id = (geojson as any).id || generateID(); + this.type = geojson.geometry.type; + } -Feature.prototype.incomingCoords = function (coords) { - this.setCoordinates(coords); -}; + changed(): void { + this.ctx.store.featureChanged(this.id); + } -Feature.prototype.setCoordinates = function (coords) { - this.coordinates = coords; - this.changed(); -}; + incomingCoords(coords: any): void { + this.setCoordinates(coords); + } + + setCoordinates(coords: any): void { + this.coordinates = coords; + this.changed(); + } -Feature.prototype.getCoordinates = function () { - return JSON.parse(JSON.stringify(this.coordinates)); -}; + getCoordinates(): any { + return JSON.parse(JSON.stringify(this.coordinates)); + } -Feature.prototype.setProperty = function (property, value) { - this.properties[property] = value; -}; + setProperty(property: string, value: any): void { + this.properties[property] = value; + } -Feature.prototype.toGeoJSON = function () { - return JSON.parse( - JSON.stringify({ + toGeoJSON(): any { + return { id: this.id, type: Constants.geojsonTypes.FEATURE, properties: this.properties, @@ -40,33 +48,34 @@ Feature.prototype.toGeoJSON = function () { coordinates: this.getCoordinates(), type: this.type } - }) - ); -}; + }; + } -Feature.prototype.internal = function (mode) { - const properties = { - id: this.id, - meta: Constants.meta.FEATURE, - 'meta:type': this.type, - active: Constants.activeStates.INACTIVE, - mode - }; + internal(mode: string): any { + const properties: Record = { + id: this.id, + meta: Constants.meta.FEATURE, + 'meta:type': this.type, + active: Constants.activeStates.INACTIVE, + mode + }; - if (this.ctx.options.userProperties) { - for (const name in this.properties) { - properties[`user_${name}`] = this.properties[name]; + if (this.ctx.options.userProperties) { + for (const name in this.properties) { + properties[`user_${name}`] = this.properties[name]; + } } - } - return { - type: Constants.geojsonTypes.FEATURE, - properties, - geometry: { - coordinates: this.getCoordinates(), - type: this.type - } - }; -}; + return { + type: Constants.geojsonTypes.FEATURE, + properties, + geometry: { + coordinates: this.getCoordinates(), + type: this.type + } + }; + } +} export default Feature; + diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index a977a7da..3d097ef6 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -1,37 +1,42 @@ import Feature from './feature.js'; -import type { FeatureCollection } from 'geojson'; -import type { DrawCTX } from '../types/types'; - -const LineString = function (ctx: DrawCTX, geojson: FeatureCollection) { - Feature.call(this, ctx, geojson); -}; - -LineString.prototype = Object.create(Feature.prototype); - -LineString.prototype.isValid = function () { - return this.coordinates.length > 1; -}; - -LineString.prototype.addCoordinate = function (path: string, lng: number, lat: number) { - this.changed(); - const id = parseInt(path, 10); - this.coordinates.splice(id, 0, [lng, lat]); -}; - -LineString.prototype.getCoordinate = function (path: string) { - const id = parseInt(path, 10); - return JSON.parse(JSON.stringify(this.coordinates[id])); -}; - -LineString.prototype.removeCoordinate = function (path: string) { - this.changed(); - this.coordinates.splice(parseInt(path, 10), 1); -}; - -LineString.prototype.updateCoordinate = function (path: string, lng: number, lat: number) { - const id = parseInt(path, 10); - this.coordinates[id] = [lng, lat]; - this.changed(); -}; +import type { StrictFeature, DrawCTX } from '../types/types'; + +type Coordinate = [number, number]; + +class LineString extends Feature { + constructor(ctx: DrawCTX, geojson: StrictFeature) { + super(ctx, geojson); + } + + isValid(): boolean { + return this.coordinates.length > 1; + } + + addCoordinate(path: string, lng: number, lat: number): void { + this.changed(); + const id = parseInt(path, 10); + this.coordinates.splice(id, 0, [lng, lat]); + } + + getCoordinate(path: string): Coordinate | undefined { + const id = parseInt(path, 10); + return this.coordinates[id] ? [...this.coordinates[id] as Coordinate] : undefined; + } + + removeCoordinate(path: string): void { + this.changed(); + this.coordinates.splice(parseInt(path, 10), 1); + } + + updateCoordinate(path: string, lng: number, lat: number): void { + const id = parseInt(path, 10); + if (this.coordinates[id]) { + this.coordinates[id] = [lng, lat]; + this.changed(); + } + } + + changed(): void {} +} export default LineString; diff --git a/src/feature_types/multi_feature.ts b/src/feature_types/multi_feature.ts index d762cf85..6fb15d35 100644 --- a/src/feature_types/multi_feature.ts +++ b/src/feature_types/multi_feature.ts @@ -12,29 +12,43 @@ const models = { MultiPolygon }; -const takeAction = (features, action, path, lng, lat) => { +type FeatureType = MultiPoint | MultiLineString | MultiPolygon; + +const takeAction = ( + features: FeatureType[], + action: 'getCoordinate' | 'updateCoordinate' | 'addCoordinate' | 'removeCoordinate', + path: string, + lng?: number, + lat?: number +): any => { const parts = path.split('.'); const idx = parseInt(parts[0], 10); const tail = !parts[1] ? null : parts.slice(1).join('.'); return features[idx][action](tail, lng, lat); }; -const MultiFeature = function (ctx, geojson) { - Feature.call(this, ctx, geojson); +class MultiFeature extends Feature { + model: FeatureType; + features: FeatureType[]; - delete this.coordinates; - this.model = models[geojson.geometry.type]; - if (this.model === undefined) - throw new TypeError(`${geojson.geometry.type} is not a valid type`); - this.features = this._coordinatesToFeatures(geojson.geometry.coordinates); -}; + constructor(ctx: any, geojson: any) { + super(ctx, geojson); + + delete this.coordinates; + + // Determine the model based on geojson type + this.model = models[geojson.geometry.type]; + if (this.model === undefined) { + throw new TypeError(`${geojson.geometry.type} is not a valid type`); + } -MultiFeature.prototype = Object.create(Feature.prototype); + // Initialize features + this.features = this._coordinatesToFeatures(geojson.geometry.coordinates); + } -MultiFeature.prototype._coordinatesToFeatures = function (coordinates) { - const Model = this.model.bind(this); - return coordinates.map( - coords => + private _coordinatesToFeatures(coordinates: any[]): FeatureType[] { + const Model = this.model.bind(this); + return coordinates.map((coords) => new Model(this.ctx, { id: generateID(), type: Constants.geojsonTypes.FEATURE, @@ -44,51 +58,53 @@ MultiFeature.prototype._coordinatesToFeatures = function (coordinates) { type: this.type.replace('Multi', '') } }) - ); -}; - -MultiFeature.prototype.isValid = function () { - return this.features.every(f => f.isValid()); -}; - -MultiFeature.prototype.setCoordinates = function (coords) { - this.features = this._coordinatesToFeatures(coords); - this.changed(); -}; - -MultiFeature.prototype.getCoordinate = function (path) { - return takeAction(this.features, 'getCoordinate', path); -}; - -MultiFeature.prototype.getCoordinates = function () { - return JSON.parse( - JSON.stringify( - this.features.map(f => { - if (f.type === Constants.geojsonTypes.POLYGON) - return f.getCoordinates(); - return f.coordinates; - }) - ) - ); -}; - -MultiFeature.prototype.updateCoordinate = function (path, lng, lat) { - takeAction(this.features, 'updateCoordinate', path, lng, lat); - this.changed(); -}; - -MultiFeature.prototype.addCoordinate = function (path, lng, lat) { - takeAction(this.features, 'addCoordinate', path, lng, lat); - this.changed(); -}; - -MultiFeature.prototype.removeCoordinate = function (path) { - takeAction(this.features, 'removeCoordinate', path); - this.changed(); -}; - -MultiFeature.prototype.getFeatures = function () { - return this.features; -}; + ); + } + + isValid(): boolean { + return this.features.every(f => f.isValid()); + } + + setCoordinates(coords: any[]): void { + this.features = this._coordinatesToFeatures(coords); + this.changed(); + } + + getCoordinate(path: string): any { + return takeAction(this.features, 'getCoordinate', path); + } + + getCoordinates(): any[] { + return JSON.parse( + JSON.stringify( + this.features.map((f) => { + if (f.type === Constants.geojsonTypes.POLYGON) { + return f.getCoordinates(); + } + return f.coordinates; + }) + ) + ); + } + + updateCoordinate(path: string, lng: number, lat: number): void { + takeAction(this.features, 'updateCoordinate', path, lng, lat); + this.changed(); + } + + addCoordinate(path: string, lng: number, lat: number): void { + takeAction(this.features, 'addCoordinate', path, lng, lat); + this.changed(); + } + + removeCoordinate(path: string): void { + takeAction(this.features, 'removeCoordinate', path); + this.changed(); + } + + getFeatures(): FeatureType[] { + return this.features; + } +} export default MultiFeature; diff --git a/src/feature_types/point.ts b/src/feature_types/point.ts index d6217431..8576e101 100644 --- a/src/feature_types/point.ts +++ b/src/feature_types/point.ts @@ -1,29 +1,35 @@ import Feature from './feature.js'; +import type { DrawCTX, StrictFeature } from '../types/types'; -const Point = function (ctx, geojson) { - Feature.call(this, ctx, geojson); -}; +type Coordinate = [number, number]; -Point.prototype = Object.create(Feature.prototype); +class Point extends Feature { + coordinates: Coordinate; -Point.prototype.isValid = function () { - return ( - typeof this.coordinates[0] === 'number' && - typeof this.coordinates[1] === 'number' - ); -}; + constructor(ctx: DrawCTX, geojson: StrictFeature) { + super(ctx, geojson); + this.coordinates = geojson.geometry.coordinates as Coordinate; + } + + isValid(): boolean { + return ( + typeof this.coordinates[0] === 'number' && + typeof this.coordinates[1] === 'number' + ); + } -Point.prototype.updateCoordinate = function (pathOrLng, lngOrLat, lat) { - if (arguments.length === 3) { - this.coordinates = [lngOrLat, lat]; - } else { - this.coordinates = [pathOrLng, lngOrLat]; + updateCoordinate(pathOrLng: number, lngOrLat: number, lat?: number): void { + if (lat !== undefined) { + this.coordinates = [lngOrLat, lat]; + } else { + this.coordinates = [pathOrLng, lngOrLat]; + } + this.changed(); } - this.changed(); -}; -Point.prototype.getCoordinate = function () { - return this.getCoordinates(); -}; + getCoordinate(): Coordinate { + return this.getCoordinates() as Coordinate; + } +} export default Point; diff --git a/src/feature_types/polygon.ts b/src/feature_types/polygon.ts index fb125080..b64f2f2d 100644 --- a/src/feature_types/polygon.ts +++ b/src/feature_types/polygon.ts @@ -1,71 +1,75 @@ import Feature from './feature.js'; +import type { DrawCTX, Coords, StrictFeature } from '../types/types'; -const Polygon = function (ctx, geojson) { - Feature.call(this, ctx, geojson); - this.coordinates = this.coordinates.map(ring => ring.slice(0, -1)); -}; +type Coordinate = [number, number]; -Polygon.prototype = Object.create(Feature.prototype); +class Polygon extends Feature { + constructor(ctx: DrawCTX, geojson: StrictFeature) { + super(ctx, geojson); -Polygon.prototype.isValid = function () { - if (this.coordinates.length === 0) return false; - return this.coordinates.every(ring => ring.length > 2); -}; - -// Expects valid geoJSON polygon geometry: first and last positions must be equivalent. -Polygon.prototype.incomingCoords = function (coords) { - this.coordinates = coords.map(ring => ring.slice(0, -1)); - this.changed(); -}; + // Ensure coordinates are properly typed and adjust them. + this.coordinates = this.coordinates.map((ring: Coords) => ring.slice(0, -1)); + } -// Does NOT expect valid geoJSON polygon geometry: first and last positions should not be equivalent. -Polygon.prototype.setCoordinates = function (coords) { - this.coordinates = coords; - this.changed(); -}; + isValid(): boolean { + if (this.coordinates.length === 0) return false; + return this.coordinates.every((ring: Coords) => ring.length > 2); + } -Polygon.prototype.addCoordinate = function (path, lng, lat) { - this.changed(); - const ids = path.split('.').map(x => parseInt(x, 10)); + // Expects valid geoJSON polygon geometry: first and last positions must be equivalent. + incomingCoords(coords: Coords): void { + this.coordinates = coords.map(ring => ring.slice(0, -1)); + this.changed(); + } - const ring = this.coordinates[ids[0]]; + // Does NOT expect valid geoJSON polygon geometry: first and last positions should not be equivalent. + setCoordinates(coords: Coords): void { + this.coordinates = coords; + this.changed(); + } - ring.splice(ids[1], 0, [lng, lat]); -}; + addCoordinate(path: string, lng: number, lat: number): void { + this.changed(); + const ids = path.split('.').map((x: string) => parseInt(x, 10)); + const ring = this.coordinates[ids[0]]; + ring.splice(ids[1], 0, [lng, lat]); + } -Polygon.prototype.removeCoordinate = function (path) { - this.changed(); - const ids = path.split('.').map(x => parseInt(x, 10)); - const ring = this.coordinates[ids[0]]; - if (ring) { - ring.splice(ids[1], 1); - if (ring.length < 3) { - this.coordinates.splice(ids[0], 1); + removeCoordinate(path: string): void { + this.changed(); + const ids = path.split('.').map((x: string) => parseInt(x, 10)); + const ring = this.coordinates[ids[0]]; + if (ring) { + ring.splice(ids[1], 1); + if (ring.length < 3) { + this.coordinates.splice(ids[0], 1); + } } } -}; -Polygon.prototype.getCoordinate = function (path) { - const ids = path.split('.').map(x => parseInt(x, 10)); - const ring = this.coordinates[ids[0]]; - return JSON.parse(JSON.stringify(ring[ids[1]])); -}; + getCoordinate(path: string): Coords { + const ids = path.split('.').map((x: string) => parseInt(x, 10)); + const ring = this.coordinates[ids[0]]; + return JSON.parse(JSON.stringify(ring[ids[1]])); + } -Polygon.prototype.getCoordinates = function () { - return this.coordinates.map(coords => coords.concat([coords[0]])); -}; + getCoordinates(): Coords[] { + return this.coordinates.map((coords: Coords) => coords.concat([coords[0]])); + } -Polygon.prototype.updateCoordinate = function (path, lng, lat) { - this.changed(); - const parts = path.split('.'); - const ringId = parseInt(parts[0], 10); - const coordId = parseInt(parts[1], 10); + updateCoordinate(path: string, lng: number, lat: number): void { + this.changed(); + const parts = path.split('.'); + const ringId = parseInt(parts[0], 10); + const coordId = parseInt(parts[1], 10); - if (this.coordinates[ringId] === undefined) { - this.coordinates[ringId] = []; - } + if (this.coordinates[ringId] === undefined) { + this.coordinates[ringId] = []; + } - this.coordinates[ringId][coordId] = [lng, lat]; -}; + this.coordinates[ringId][coordId] = [lng, lat]; + } +} export default Polygon; + diff --git a/src/lib/create_midpoint.ts b/src/lib/create_midpoint.ts index f744505a..420f8305 100644 --- a/src/lib/create_midpoint.ts +++ b/src/lib/create_midpoint.ts @@ -1,7 +1,7 @@ import * as Constants from '../constants'; import type { Feature, Point } from 'geojson'; -export const createMidpoint = (parent: string, startVertex: Feature, endVertex: Feature): Feature => { +export const createMidPoint = (parent: string, startVertex: Feature, endVertex: Feature): Feature => { const startCoord = (startVertex.geometry as Point).coordinates; const endCoord = (endVertex.geometry as Point).coordinates; diff --git a/src/lib/create_supplementary_points.ts b/src/lib/create_supplementary_points.ts index 2d409df5..9448f71f 100644 --- a/src/lib/create_supplementary_points.ts +++ b/src/lib/create_supplementary_points.ts @@ -1,5 +1,5 @@ import { createVertex } from './create_vertex'; -import { createMidpoint } from './create_midpoint'; +import { createMidPoint } from './create_midpoint'; import * as Constants from '../constants'; function createSupplementaryPoints(geojson, options = {}, basePath = null) { @@ -47,7 +47,7 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { // vertex before this one. If so, add a midpoint // between that vertex and this one. if (options.midpoints && lastVertex) { - const midpoint = createMidpoint(featureId, lastVertex, vertex); + const midpoint = createMidPoint(featureId, lastVertex, vertex); if (midpoint) { supplementaryPoints.push(midpoint); } diff --git a/src/lib/index.ts b/src/lib/index.ts index c8403c23..9d0aac7c 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -17,7 +17,7 @@ import sortFeatures from './sort_features'; import StringSet from './string_set'; import { stringSetsAreEqual } from './string_sets_are_equal'; import theme from './theme'; -import toDenseArray from './to_dense_array'; +import { toDenseArray } from './to_dense_array'; export { CommonSelectors, diff --git a/src/lib/is_click.ts b/src/lib/is_click.ts index 15fca01e..fb0fb4fc 100644 --- a/src/lib/is_click.ts +++ b/src/lib/is_click.ts @@ -7,17 +7,31 @@ interface Options { interval: number; } -export default function isClick(start: Entry, end: Entry, { - fineTolerance = 4, - grossTolerance = 12, - interval = 500 -}: Options) { - start.point = start.point || end.point; - start.time = start.time || end.time; - const moveDistance = euclideanDistance(start.point, end.point); +export default function isClick( + start: Entry, + end: Entry, + options: Partial = {} +) { + const { + fineTolerance = 4, + grossTolerance = 12, + interval = 500 + } = options; + + const adjustedStart = { + point: start.point || end.point, + time: start.time || end.time + }; + + if (adjustedStart.time === undefined || end.time === undefined) { + return false; + } + + const moveDistance = euclideanDistance(adjustedStart.point, end.point); return ( moveDistance < fineTolerance || - (moveDistance < grossTolerance && end.time - start.time < interval) + (moveDistance < grossTolerance && end.time - adjustedStart.time < interval) ); } + diff --git a/src/lib/is_event_at_coordinates.ts b/src/lib/is_event_at_coordinates.ts index 8df832cf..d434c3ac 100644 --- a/src/lib/is_event_at_coordinates.ts +++ b/src/lib/is_event_at_coordinates.ts @@ -1,11 +1,10 @@ -export const isEventAtCoordinates = (event: { - lngLat: { - lng: number, - lat: number - } -}, coordinates: [number, number]) => { - if (!event.lngLat) return false; +export const isEventAtCoordinates = ( + event: { lngLat: { lng: number; lat: number } }, + coordinates: [number, number], + tolerance = 1e-6 // Default precision tolerance +): boolean => { return ( - event.lngLat.lng === coordinates[0] && event.lngLat.lat === coordinates[1] + Math.abs(event.lngLat.lng - coordinates[0]) < tolerance && + Math.abs(event.lngLat.lat - coordinates[1]) < tolerance ); } diff --git a/src/lib/to_dense_array.ts b/src/lib/to_dense_array.ts index 1c886a66..fd477d51 100644 --- a/src/lib/to_dense_array.ts +++ b/src/lib/to_dense_array.ts @@ -1,5 +1,3 @@ -const toDenseArray = (x: unknown): Array => { +export const toDenseArray = (x: unknown): Array => { return [].concat(x).filter(y => y !== undefined); } - -export default toDenseArray; diff --git a/src/modes/object_to_mode.ts b/src/modes/object_to_mode.ts index 73d0f70e..a8ab9bcb 100644 --- a/src/modes/object_to_mode.ts +++ b/src/modes/object_to_mode.ts @@ -1,4 +1,6 @@ import ModeInterface from './mode_interface.js'; +import type { DrawCTX } from '../types/types'; +import type { FeatureCollection } from 'geojson'; const eventMapper = { drag: 'onDrag', @@ -17,10 +19,10 @@ const eventMapper = { const eventKeys = Object.keys(eventMapper); -export default function (modeObject) { +export const objectToMode = (modeObject) => { const modeObjectKeys = Object.keys(modeObject); - return function (ctx, startOpts = {}) { + return function (ctx: DrawCTX, startOpts = {}) { let state = {}; const mode = modeObjectKeys.reduce((m, k) => { @@ -62,7 +64,7 @@ export default function (modeObject) { uncombineFeatures() { mode.onUncombineFeatures(state); }, - render(geojson, push) { + render(geojson: FeatureCollection, push) { mode.toDisplayFeatures(state, geojson, push); } }; diff --git a/src/store.ts b/src/store.ts index 60df2ca5..e09736b4 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,4 +1,4 @@ -import toDenseArray from './lib/to_dense_array'; +import { toDenseArray } from './lib/to_dense_array'; import StringSet from './lib/string_set'; import render from './render'; import * as Constants from './constants'; diff --git a/src/types/types.ts b/src/types/types.ts index eeea6628..5e113f37 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -18,8 +18,22 @@ import type { MapTouchEvent as MapboxMapTouchEvent } from 'mapbox-gl'; +// Extend Feature to require geometry and properties +export interface StrictFeature extends Omit { + geometry: Geometry & { coordinates: unknown }; + properties: Record; +} + +// Extend FeatureCollection to use StrictFeature +export interface StrictFeatureCollection extends Omit { + features: StrictFeature[]; +} + +// Example usage export type XY = { x: number, y: number }; +export type Coords = Array<[number, number]>; + export interface Entry { point: XY; time: number; @@ -258,16 +272,16 @@ export declare class Draw implements IControl { modes: Modes; getDefaultPosition: () => ControlPosition; constructor(options?: DrawOptions); - add(geojson: Feature | FeatureCollection | Geometry): string[]; + add(geojson: Feature | StrictFeatureCollection | Geometry): string[]; get(featureId: string): Feature | undefined; getFeatureIdsAt(point: { x: number; y: number }): string[]; getSelectedIds(): string[]; - getSelected(): FeatureCollection; - getSelectedPoints(): FeatureCollection; - getAll(): FeatureCollection; + getSelected(): StrictFeatureCollection; + getSelectedPoints(): StrictFeatureCollection; + getAll(): StrictFeatureCollection; delete(ids: string | string[]): this; deleteAll(): this; - set(featureCollection: FeatureCollection): string[]; + set(featureCollection: StrictFeatureCollection): string[]; trash(): this; combineFeatures(): this; uncombineFeatures(): this; diff --git a/test/draw_line_string.test.js b/test/draw_line_string.test.js index 77fa3111..f8057ff3 100644 --- a/test/draw_line_string.test.js +++ b/test/draw_line_string.test.js @@ -10,7 +10,7 @@ import drawLineStringModeObject from '../src/modes/draw_line_string.js'; import LineString from '../src/feature_types/line_string.js'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; -import objectToMode from '../src/modes/object_to_mode.js'; +import { objectToMode } from '../src/modes/object_to_mode.js'; import { setupAfterNextRender } from './utils/after_next_render.js'; const drawLineStringMode = objectToMode(drawLineStringModeObject); diff --git a/test/draw_point.test.js b/test/draw_point.test.js index 1c551b04..2d88a5b0 100644 --- a/test/draw_point.test.js +++ b/test/draw_point.test.js @@ -11,7 +11,7 @@ import Point from '../src/feature_types/point.js'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; import { escapeEvent, enterEvent } from './utils/key_events.js'; -import objectToMode from '../src/modes/object_to_mode.js'; +import { objectToMode } from '../src/modes/object_to_mode.js'; const drawPointMode = objectToMode(drawPointModeObject); test('draw_point mode initialization', () => { diff --git a/test/draw_polygon.test.js b/test/draw_polygon.test.js index 40f6e2f4..e72c42d4 100644 --- a/test/draw_polygon.test.js +++ b/test/draw_polygon.test.js @@ -11,7 +11,7 @@ import Polygon from '../src/feature_types/polygon.js'; import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; import { setupAfterNextRender } from './utils/after_next_render.js'; -import objectToMode from '../src/modes/object_to_mode.js'; +import { objectToMode } from '../src/modes/object_to_mode.js'; const drawPolygonMode = objectToMode(drawPolygonModeObject); import { diff --git a/tsconfig.json b/tsconfig.json index 724b3969..b121e998 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,6 @@ "target": "ESNext", "moduleResolution": "Node", "skipLibCheck": true, - "strict": true, "esModuleInterop": true, "noEmit": true }, From f7cc7018dc5413014ae7b3ae0e35af4aac62b5cb Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 6 Mar 2025 10:07:17 +0200 Subject: [PATCH 12/59] Start over again with @types/mapbox-gl-draw --- index.ts | 3 + src/feature_types/feature.ts | 6 +- src/feature_types/line_string.ts | 4 +- src/feature_types/point.ts | 4 +- src/feature_types/polygon.ts | 6 +- src/modes/direct_select.ts | 4 +- src/types/types.ts | 524 ++++++++++++++++++++++--------- 7 files changed, 396 insertions(+), 155 deletions(-) diff --git a/index.ts b/index.ts index 4740c73a..e4d95767 100644 --- a/index.ts +++ b/index.ts @@ -27,6 +27,9 @@ const setupDraw = (options: DrawOptions, api: Draw) => { }; function MapboxDraw(options: DrawOptions) { + + console.log('THIS??', this); + setupDraw(options, this); } diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index 5da855a5..823d1f9f 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -1,16 +1,16 @@ import { generateID } from '../lib/id'; import * as Constants from '../constants'; import type { Geometry } from 'geojson'; -import type { StrictFeature, DrawCTX } from '../types/types'; +import type { StrictFeature, Draw } from '../types/types'; class Feature { - protected ctx: DrawCTX; + protected ctx: Draw; properties: Record; coordinates: any; id: string; type: Geometry['type']; - constructor(ctx: DrawCTX, geojson: StrictFeature) { + constructor(ctx: Draw, geojson: StrictFeature) { this.ctx = ctx; this.properties = geojson.properties || {}; this.coordinates = geojson.geometry.coordinates; diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index 3d097ef6..948946a3 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -1,10 +1,10 @@ import Feature from './feature.js'; -import type { StrictFeature, DrawCTX } from '../types/types'; +import type { StrictFeature, Draw } from '../types/types'; type Coordinate = [number, number]; class LineString extends Feature { - constructor(ctx: DrawCTX, geojson: StrictFeature) { + constructor(ctx: Draw, geojson: StrictFeature) { super(ctx, geojson); } diff --git a/src/feature_types/point.ts b/src/feature_types/point.ts index 8576e101..e9d5fae6 100644 --- a/src/feature_types/point.ts +++ b/src/feature_types/point.ts @@ -1,12 +1,12 @@ import Feature from './feature.js'; -import type { DrawCTX, StrictFeature } from '../types/types'; +import type { Draw, StrictFeature } from '../types/types'; type Coordinate = [number, number]; class Point extends Feature { coordinates: Coordinate; - constructor(ctx: DrawCTX, geojson: StrictFeature) { + constructor(ctx: Draw, geojson: StrictFeature) { super(ctx, geojson); this.coordinates = geojson.geometry.coordinates as Coordinate; } diff --git a/src/feature_types/polygon.ts b/src/feature_types/polygon.ts index b64f2f2d..07fdcabf 100644 --- a/src/feature_types/polygon.ts +++ b/src/feature_types/polygon.ts @@ -1,10 +1,8 @@ import Feature from './feature.js'; -import type { DrawCTX, Coords, StrictFeature } from '../types/types'; - -type Coordinate = [number, number]; +import type { Draw, Coords, StrictFeature } from '../types/types'; class Polygon extends Feature { - constructor(ctx: DrawCTX, geojson: StrictFeature) { + constructor(ctx: Draw, geojson: StrictFeature) { super(ctx, geojson); // Ensure coordinates are properly typed and adjust them. diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index dc1748c9..523eea8f 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,13 +11,13 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { DrawCTX, DrawCustomMode } from '../types/types'; +import type { DrawCTX, DrawCTXCustomMode } from '../types/types'; import type { MapMouseEvent } from 'mapbox-gl'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); -interface DirectSelectMode extends DrawCustomMode { +interface DirectSelectMode extends DrawCTXCustomMode { fireUpdate(): void; clickInactive(): void; fireActionable(state: DrawCTX): void; diff --git a/src/types/types.ts b/src/types/types.ts index 5e113f37..573daf25 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,4 +1,3 @@ -import { modes, meta, types } from '../constants'; import { BBox, Feature, @@ -9,11 +8,29 @@ import { Point, Position } from 'geojson'; + +import { + classes, + sources, + cursors, + types, + geojsonTypes, + modes, + events, + updateActions, + meta, + activeStates, + interactions +} from '../constants'; + import type { + CircleLayerSpecification, ControlPosition, + FillLayerSpecification, IControl, + LineLayerSpecification, Map, - Layer, + MapEvent, MapMouseEvent as MapboxMapMouseEvent, MapTouchEvent as MapboxMapTouchEvent } from 'mapbox-gl'; @@ -39,40 +56,12 @@ export interface Entry { time: number; } -export interface MapMouseEvent extends MapboxMapMouseEvent { - featureTarget: DrawFeature; -} - -export interface MapTouchEvent extends MapboxMapTouchEvent { - featureTarget: DrawFeature; -} - -export interface DrawOptions { - keybindings: boolean; - touchEnabled: boolean; - boxSelect: boolean; - clickBuffer: number; - touchBuffer: number; - controls: Controls; - displayControlsDefault: boolean; - styles: Array; -} - -export interface Controls { - point: boolean; - line_string: boolean; - polygon: boolean; - trash: boolean; - combine_features: boolean; - uncombine_features: boolean; -} - -type Modes = typeof modes; - -export interface DrawLayer extends Layer { - meta: typeof meta; - mode: Modes; - active: boolean; +interface Modes { + draw_line_string: DrawCustomMode; + draw_polygon: DrawCustomMode; + draw_point: DrawCustomMode; + simple_select: DrawCustomMode; + direct_select: DrawCustomMode; } interface DrawPoint extends DrawFeatureBase { @@ -111,57 +100,179 @@ interface DrawFeatureBase { toGeoJSON(): GeoJSON; } -interface DrawMultiFeature< - Type extends 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' -> extends Omit< +export interface DrawUI { + queueMapClasses: (options: { mode: null, feature: null, mouse: null }) => void; + setActiveButton: (id: string) => void; + updateMapClasses: () => void; + clearMapClasses: () => void; + addButtons: () => void; + removeButtons: () => void; +} + +type DrawMode = DrawModes[keyof DrawModes]; + +interface DrawEvents { + "draw.create": DrawCreateEvent; + "draw.delete": DrawDeleteEvent; + "draw.update": DrawUpdateEvent; + "draw.selectionchange": DrawSelectionChangeEvent; + "draw.render": DrawRenderEvent; + "draw.combine": DrawCombineEvent; + "draw.uncombine": DrawUncombineEvent; + "draw.modechange": DrawModeChangeEvent; + "draw.actionable": DrawActionableEvent; +} + +type DrawEventType = keyof DrawEvents; + +type DrawModes = typeof modes[keyof typeof modes]; + +interface DrawControls { + point?: boolean | undefined; + line_string?: boolean | undefined; + polygon?: boolean | undefined; + trash?: boolean | undefined; + combine_features?: boolean | undefined; + uncombine_features?: boolean | undefined; +} + +interface DrawActionableState { + trash: boolean; + combineFeatures: boolean; + uncombineFeatures: boolean; +} + +interface DrawFeatureBase { + readonly properties: Readonly; + readonly coordinates: Coordinates; + readonly id: NonNullable; + readonly type: GeoJsonTypes; + + changed(): void; + isValid(): boolean; + incomingCoords: this["setCoordinates"]; + setCoordinates(coords: Coordinates): void; + getCoordinates(): Coordinates; + getCoordinate(path: string): Position; + updateCoordinate(path: string, lng: number, lat: number): void; + setProperty(property: string, value: any): void; + toGeoJSON(): GeoJSON; +} + +interface DrawMultiFeature extends + Omit< DrawFeatureBase< - | (Type extends 'MultiPoint' ? Array : never) - | (Type extends 'MultiLineString' - ? Array - : never) - | (Type extends 'MultiPolygon' - ? Array - : never) + | (Type extends "MultiPoint" ? Array : never) + | (Type extends "MultiLineString" ? Array : never) + | (Type extends "MultiPolygon" ? Array : never) >, - 'coordinates' - > { + "coordinates" + > +{ readonly type: Type; readonly features: Array< - | (Type extends 'MultiPoint' ? DrawPoint : never) - | (Type extends 'MultiLineString' ? DrawLineString : never) - | (Type extends 'MultiPolygon' ? DrawPolygon : never) + | (Type extends "MultiPoint" ? DrawPoint : never) + | (Type extends "MultiLineString" ? DrawLineString : never) + | (Type extends "MultiPolygon" ? DrawPolygon : never) >; - getFeatures(): this['features']; + getFeatures(): this["features"]; +} + +interface DrawPoint extends DrawFeatureBase { + readonly type: "Point"; + getCoordinate(): Position; + updateCoordinate(lng: number, lat: number): void; + updateCoordinate(path: string, lng: number, lat: number): void; +} + +interface DrawLineString extends DrawFeatureBase { + readonly type: "LineString"; + addCoordinate(path: string | number, lng: number, lat: number): void; + removeCoordinate(path: string | number): void; +} + +interface DrawPolygon extends DrawFeatureBase { + readonly type: "Polygon"; + addCoordinate(path: string, lng: number, lat: number): void; + removeCoordinate(path: string): void; } type DrawFeature = | DrawPoint | DrawLineString | DrawPolygon - | DrawMultiFeature<'MultiPoint'> - | DrawMultiFeature<'MultiLineString'> - | DrawMultiFeature<'MultiPolygon'>; + | DrawMultiFeature<"MultiPoint"> + | DrawMultiFeature<"MultiLineString"> + | DrawMultiFeature<"MultiPolygon">; -interface DrawActionableState { - trash: boolean; - combineFeatures: boolean; - uncombineFeatures: boolean; +interface MapMouseEvent extends MapboxMapMouseEvent { + featureTarget: DrawFeature; } -interface _DrawCTS extends DrawCTX { - store: { - getInitialConfigValue: (config: string) => boolean; - } +interface MapTouchEvent extends MapboxMapTouchEvent { + featureTarget: DrawFeature; +} + +interface DrawEvent { + target: Map; + type: DrawEventType; +} + +interface DrawCreateEvent extends DrawEvent { + // Array of GeoJSON objects representing the features that were created + features: Feature[]; + type: "draw.create"; +} + +interface DrawDeleteEvent extends DrawEvent { + // Array of GeoJSON objects representing the features that were deleted + features: Feature[]; + type: 'draw.delete'; +} + +interface DrawCombineEvent extends DrawEvent { + deletedFeatures: Feature[]; // Array of deleted features (those incorporated into new multifeatures) + createdFeatures: Feature[]; // Array of created multifeatures + type: 'draw.combine'; +} + +interface DrawUncombineEvent extends DrawEvent { + deletedFeatures: Feature[]; // Array of deleted multifeatures (split into features) + createdFeatures: Feature[]; // Array of created features + type: 'draw.uncombine'; +} + +interface DrawUpdateEvent extends DrawEvent { + features: Feature[]; // Array of features that were updated + action: string; // Name of the action that triggered the update + type: 'draw.update'; +} + +interface DrawSelectionChangeEvent extends DrawEvent { + features: Feature[]; // Array of features that are selected after the change + points: Array>; + type: 'draw.selectionchange'; +} + +interface DrawModeChangeEvent extends DrawEvent { + mode: DrawMode; // The next mode, i.e. the mode that Draw is changing to + type: 'draw.modechange'; +} + +interface DrawRenderEvent extends DrawEvent { + type: 'draw.render'; +} + +interface DrawActionableEvent extends DrawEvent { + actions: DrawActionableState; + type: 'draw.actionable'; } export interface DrawCTX { map: Map; - container: HTMLElement, drawConfig: DrawOptions; setSelected(features?: string | string[]): void; - setSelectedCoordinates( - coords: Array<{ coord_path: string; feature_id: string }> - ): void; + setSelectedCoordinates(coords: Array<{ coord_path: string; feature_id: string }>): void; getSelected(): DrawFeature[]; getSelectedIds(): string[]; isSelected(id: string): boolean; @@ -173,86 +284,28 @@ export interface DrawCTX { clearSelectedFeatures(): void; clearSelectedCoordinates(): void; setActionableState(actionableState: DrawActionableState): void; - changeMode(mode: Modes, opts?: object, eventOpts?: object): void; + changeMode(mode: DrawMode, opts?: object, eventOpts?: object): void; updateUIClasses(opts: object): void; activateUIButton(name?: string): void; - featuresAt( - event: Event, - bbox: BBox, - bufferType: 'click' | 'tap' - ): DrawFeature[]; + featuresAt(event: Event, bbox: BBox, bufferType: "click" | "tap"): DrawFeature[]; newFeature(geojson: GeoJSON): DrawFeature; isInstanceOf(type: string, feature: object): boolean; doRender(id: string): void; - ui: DrawUI; - _ctx: _DrawCTS; } -export interface DrawUI { - queueMapClasses: (options: { mode: null, feature: null, mouse: null }) => void; - setActiveButton: (id: string) => void; - updateMapClasses: () => void; - clearMapClasses: () => void; - addButtons: () => void; - removeButtons: () => void; -} - -export interface DrawCustomMode< - CustomModeState = unknown, - CustomModeOptions = unknown -> { +interface DrawCustomMode { onSetup?(this: DrawCTX & this, options: CustomModeOptions): CustomModeState; onDrag?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onClick?( - this: DrawCTX & this, - state: CustomModeState, - e: MapMouseEvent - ): void; - onMouseMove?( - this: DrawCTX & this, - state: CustomModeState, - e: MapMouseEvent - ): void; - onMouseDown?( - this: DrawCTX & this, - state: CustomModeState, - e: MapMouseEvent - ): void; - onMouseUp?( - this: DrawCTX & this, - state: CustomModeState, - e: MapMouseEvent - ): void; - onMouseOut?( - this: DrawCTX & this, - state: CustomModeState, - e: MapMouseEvent - ): void; - onKeyUp?( - this: DrawCTX & this, - state: CustomModeState, - e: KeyboardEvent - ): void; - onKeyDown?( - this: DrawCTX & this, - state: CustomModeState, - e: KeyboardEvent - ): void; - onTouchStart?( - this: DrawCTX & this, - state: CustomModeState, - e: MapTouchEvent - ): void; - onTouchMove?( - this: DrawCTX & this, - state: CustomModeState, - e: MapTouchEvent - ): void; - onTouchEnd?( - this: DrawCTX & this, - state: CustomModeState, - e: MapTouchEvent - ): void; + onClick?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseMove?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseDown?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseUp?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onMouseOut?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; + onKeyUp?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; + onKeyDown?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; + onTouchStart?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onTouchMove?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onTouchEnd?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; onTap?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; onStop?(this: DrawCTX & this, state: CustomModeState): void; onTrash?(this: DrawCTX & this, state: CustomModeState): void; @@ -262,14 +315,201 @@ export interface DrawCustomMode< this: DrawCTX & this, state: CustomModeState, geojson: GeoJSON, - display: (geojson: GeoJSON) => void + display: (geojson: GeoJSON) => void, ): void; } +interface Modes { + draw_line_string: DrawCustomMode; + draw_polygon: DrawCustomMode; + draw_point: DrawCustomMode; + simple_select: DrawCustomMode; + direct_select: DrawCustomMode; +} + +// Convert these to use imports from constants +interface Constants { + readonly classes: typeof classes[keyof typeof classes]; + readonly sources: typeof sources[keyof typeof sources]; + readonly cursors: typeof cursors[keyof typeof cursors]; + readonly types: typeof types[keyof typeof types]; + readonly geojsonTypes: typeof geojsonTypes[keyof typeof geojsonTypes]; + readonly events: typeof events[keyof typeof events]; + readonly updateActions: typeof updateActions[keyof typeof updateActions]; + readonly meta: typeof meta[keyof typeof meta]; + readonly activeStates: typeof activeStates[keyof typeof activeStates]; + readonly interactions: typeof interactions[keyof typeof interactions]; + readonly LAT_MIN: -90; + readonly LAT_RENDERED_MIN: -85; + readonly LAT_MAX: 90; + readonly LAT_RENDERED_MAX: 85; + readonly LNG_MIN: -270; + readonly LNG_MAX: 270; +} + +interface StringSet { + add(x: string | number): StringSet; + delete(x: string | number): StringSet; + has(x: string | number): boolean; + values(): string | number[]; + clear(): StringSet; +} + +interface Lib { + CommonSelectors: { + isOfMetaType: ( + type: Constants["meta"][keyof Constants["meta"]], + ) => (e: MapMouseEvent | MapTouchEvent) => boolean; + isShiftMousedown: (e: MapEvent) => boolean; + isActiveFeature: (e: MapMouseEvent | MapTouchEvent) => boolean; + isInactiveFeature: (e: MapMouseEvent | MapTouchEvent) => boolean; + noTarget: (e: MapMouseEvent | MapTouchEvent) => boolean; + isFeature: (e: MapMouseEvent | MapTouchEvent) => boolean; + isVertex: (e: MapMouseEvent | MapTouchEvent) => boolean; + isShiftDown: (e: MapEvent) => boolean; + isEscapeKey: (e: KeyboardEvent) => boolean; + isEnterKey: (e: KeyboardEvent) => boolean; + isTrue: () => boolean; + }; + + constrainFeatureMovement( + geojsonFeatures: DrawFeature[], + delta: { lng: number; lat: number }, + ): { lng: number; lat: number }; + + createMidPoint(parent: string, startVertex: Feature, endVertex: Feature): Feature | null; + + createSupplementaryPoints( + geojson: Feature, + options?: { midpoints?: boolean; selectedPaths?: string[] }, + basePath?: string, + ): Array>; + + createVertex(parentId: string, coordinates: Position, path: string, selected: boolean): Feature; + + doubleClickZoom: { + enable: (ctx: DrawCTX) => void; // ?? ctx + disable: (ctx: DrawCTX) => void; // ?? ctx + }; + + featuresAt: { + click: (event: MapMouseEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx + touch: (event: MapTouchEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx + }; + + getFeatureAtAndSetCursors(event: MapMouseEvent, ctx: DrawCTX): Feature; + + euclideanDistance(a: { x: number; y: number }, b: { x: number; y: number }): number; + + isClick( + start: { point?: Entry }, + end: { point: Entry }, + options?: { fineTolerance?: number; grossTolerance?: number; interval?: number }, + ): boolean; + + isEventAtCoordinates(event: MapMouseEvent, coordinates: Position[]): boolean; + + isTap( + start: { point?: Entry }, + end: { point: Entry }, + options?: { tolerance?: number; interval?: number }, + ): boolean; + + /** + * Returns a bounding box representing the event's location. + * + * @param mapEvent - Mapbox GL JS map event, with a point properties. + * @param [buffer=0] + * @return Bounding box. + */ + mapEventToBoundingBox(mapEvent: MapMouseEvent | MapTouchEvent, buffer?: number): Position[]; + + ModeHandler: ( + mode: any, + DrawContext: any, + ) => { + render: any; + stop: () => void; + trash: () => void; + combineFeatures: () => void; + uncombineFeatures: () => void; + drag: (event: any) => void; + click: (event: any) => void; + mousemove: (event: any) => void; + mousedown: (event: any) => void; + mouseup: (event: any) => void; + mouseout: (event: any) => void; + keydown: (event: any) => void; + keyup: (event: any) => void; + touchstart: (event: any) => void; + touchmove: (event: any) => void; + touchend: (event: any) => void; + tap: (event: any) => void; + }; + + moveFeatures(features: DrawFeature[], delta: { lng: number; lat: number }): void; + + /** + * Sort features in the following order Point: 0, LineString: 1, MultiLineString: 1, + * Polygon: 2, then sort polygons by area ascending. + * @param features + */ + sortFeatures(features: DrawFeature[]): DrawFeature[]; + + stringSetsAreEqual(a: Array>, b: Array>): boolean; + + StringSet(items?: Array): StringSet; + + theme: Array< + (FillLayerSpecification | LineLayerSpecification | CircleLayerSpecification) & { id: ThemeLayerId } + >; + + /** + * Derive a dense array (no `undefined`s) from a single value or array. + */ + toDenseArray(x: any): Array>; + } + +type ThemeLayerId = + | "gl-draw-polygon-fill-static" + | "gl-draw-polygon-fill-active" + | "gl-draw-polygon-fill-inactive" + | "gl-draw-polygon-stroke-static" + | "gl-draw-polygon-stroke-active" + | "gl-draw-polygon-stroke-inactive" + | "gl-draw-polygon-midpoint" + | "gl-draw-polygon-and-line-vertex-inactive" + | "gl-draw-polygon-and-line-vertex-stroke-inactive" + | "gl-draw-line-static" + | "gl-draw-line-active" + | "gl-draw-line-inactive" + | "gl-draw-point-static" + | "gl-draw-point-active" + | "gl-draw-point-inactive" + | "gl-draw-point-stroke-active" + | "gl-draw-point-point-stroke-inactive"; + +export interface DrawOptions { + displayControlsDefault?: boolean | undefined; + keybindings?: boolean | undefined; + touchEnabled?: boolean | undefined; + boxSelect?: boolean | undefined; + clickBuffer?: number | undefined; + touchBuffer?: number | undefined; + controls?: DrawControls | undefined; + styles?: object[] | undefined; + modes?: { [modeKey: string]: DrawCustomMode } | undefined; + defaultMode?: string | undefined; + userProperties?: boolean | undefined; +} + export declare class Draw implements IControl { - options: DrawOptions; - types: typeof types; - modes: Modes; + static modes: Modes; + static constants: Constants; + static lib: Lib; + + modes: DrawModes; + getDefaultPosition: () => ControlPosition; constructor(options?: DrawOptions); add(geojson: Feature | StrictFeatureCollection | Geometry): string[]; From 711f71cb02f7c09888fbdcc5e9ca351c79271ec7 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 6 Mar 2025 13:12:38 +0200 Subject: [PATCH 13/59] Reformatting wave --- index.ts | 1 - src/events.ts | 92 ++--- src/feature_types/feature.ts | 1 - src/feature_types/line_string.ts | 4 +- src/feature_types/multi_feature.ts | 31 +- src/feature_types/polygon.ts | 5 +- src/lib/create_midpoint.ts | 8 +- src/lib/create_vertex.ts | 9 +- src/lib/euclidean_distance.ts | 2 +- src/lib/features_at.ts | 7 +- src/lib/index.ts | 2 +- src/lib/is_click.ts | 15 +- src/lib/is_event_at_coordinates.ts | 2 +- src/lib/is_tap.ts | 11 +- src/lib/mouse_event_point.ts | 5 +- src/lib/string_sets_are_equal.ts | 2 +- src/lib/to_dense_array.ts | 2 +- src/modes/mode_interface_accessors.ts | 387 +++++++----------- src/modes/object_to_mode.ts | 4 +- src/options.ts | 2 +- src/setup.ts | 4 +- src/store.ts | 546 ++++++++------------------ src/types/types.ts | 456 +++++++++++++-------- src/ui.ts | 6 +- test/is_click.test.js | 2 +- 25 files changed, 720 insertions(+), 886 deletions(-) diff --git a/index.ts b/index.ts index e4d95767..805e2f3a 100644 --- a/index.ts +++ b/index.ts @@ -27,7 +27,6 @@ const setupDraw = (options: DrawOptions, api: Draw) => { }; function MapboxDraw(options: DrawOptions) { - console.log('THIS??', this); setupDraw(options, this); diff --git a/src/events.ts b/src/events.ts index 0223609e..fe693310 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,13 +1,14 @@ import setupModeHandler from './lib/mode_handler'; import { getFeatureAtAndSetCursors } from './lib/get_features_at_and_set_cursor'; import * as featuresAt from './lib/features_at'; -import isClick from './lib/is_click'; +import { isClick } from './lib/is_click'; import { isTap } from './lib/is_tap'; import * as Constants from './constants'; import { objectToMode } from './modes/object_to_mode'; -import type { DrawCTX } from './types/types'; +import type { CTX } from './types/types'; + +export default function(ctx: CTX) { -export default function (ctx: DrawCTX) { const modes = Object.keys(ctx.options.modes).reduce((m, k) => { m[k] = objectToMode(ctx.options.modes[k]); return m; @@ -19,13 +20,11 @@ export default function (ctx: DrawCTX) { let currentModeName = null; let currentMode = null; - events.drag = function (event, isDrag) { - if ( - isDrag({ - point: event.point, - time: new Date().getTime() - }) - ) { + events.drag = function(event, isDrag) { + if (isDrag({ + point: event.point, + time: new Date().getTime() + })) { ctx.ui.queueMapClasses({ mouse: Constants.cursors.DRAG }); currentMode.drag(event); } else { @@ -33,19 +32,16 @@ export default function (ctx: DrawCTX) { } }; - events.mousedrag = function (event) { + events.mousedrag = function(event) { events.drag(event, endInfo => !isClick(mouseDownInfo, endInfo)); }; - events.touchdrag = function (event) { + events.touchdrag = function(event) { events.drag(event, endInfo => !isTap(touchStartInfo, endInfo)); }; - events.mousemove = function (event) { - const button = - event.originalEvent.buttons !== undefined - ? event.originalEvent.buttons - : event.originalEvent.which; + events.mousemove = function(event) { + const button = event.originalEvent.buttons !== undefined ? event.originalEvent.buttons : event.originalEvent.which; if (button === 1) { return events.mousedrag(event); } @@ -54,7 +50,7 @@ export default function (ctx: DrawCTX) { currentMode.mousemove(event); }; - events.mousedown = function (event) { + events.mousedown = function(event) { mouseDownInfo = { time: new Date().getTime(), point: event.point @@ -64,27 +60,25 @@ export default function (ctx: DrawCTX) { currentMode.mousedown(event); }; - events.mouseup = function (event) { + events.mouseup = function(event) { const target = getFeatureAtAndSetCursors(event, ctx); event.featureTarget = target; - if ( - isClick(mouseDownInfo, { - point: event.point, - time: new Date().getTime() - }) - ) { + if (isClick(mouseDownInfo, { + point: event.point, + time: new Date().getTime() + })) { currentMode.click(event); } else { currentMode.mouseup(event); } }; - events.mouseout = function (event) { + events.mouseout = function(event) { currentMode.mouseout(event); }; - events.touchstart = function (event) { + events.touchstart = function(event) { if (!ctx.options.touchEnabled) { return; } @@ -98,7 +92,7 @@ export default function (ctx: DrawCTX) { currentMode.touchstart(event); }; - events.touchmove = function (event) { + events.touchmove = function(event) { if (!ctx.options.touchEnabled) { return; } @@ -107,7 +101,7 @@ export default function (ctx: DrawCTX) { return events.touchdrag(event); }; - events.touchend = function (event) { + events.touchend = function(event) { // Prevent emulated mouse events because we will fully handle the touch here. // This does not stop the touch events from propogating to mapbox though. event.originalEvent.preventDefault(); @@ -117,12 +111,10 @@ export default function (ctx: DrawCTX) { const target = featuresAt.touch(event, null, ctx)[0]; event.featureTarget = target; - if ( - isTap(touchStartInfo, { - time: new Date().getTime(), - point: event.point - }) - ) { + if (isTap(touchStartInfo, { + time: new Date().getTime(), + point: event.point + })) { currentMode.tap(event); } else { currentMode.touchend(event); @@ -131,19 +123,13 @@ export default function (ctx: DrawCTX) { // 8 - Backspace // 46 - Delete - const isKeyModeValid = code => - !(code === 8 || code === 46 || (code >= 48 && code <= 57)); + const isKeyModeValid = code => !(code === 8 || code === 46 || (code >= 48 && code <= 57)); - events.keydown = function (event) { - const isMapElement = (event.srcElement || event.target).classList.contains( - Constants.classes.CANVAS - ); + events.keydown = function(event) { + const isMapElement = (event.srcElement || event.target).classList.contains(Constants.classes.CANVAS); if (!isMapElement) return; // we only handle events on the map - if ( - (event.keyCode === 8 || event.keyCode === 46) && - ctx.options.controls.trash - ) { + if ((event.keyCode === 8 || event.keyCode === 46) && ctx.options.controls.trash) { event.preventDefault(); currentMode.trash(); } else if (isKeyModeValid(event.keyCode)) { @@ -157,17 +143,17 @@ export default function (ctx: DrawCTX) { } }; - events.keyup = function (event) { + events.keyup = function(event) { if (isKeyModeValid(event.keyCode)) { currentMode.keyup(event); } }; - events.zoomend = function () { + events.zoomend = function() { ctx.store.changeZoom(); }; - events.data = function (event) { + events.data = function(event) { if (event.dataType === 'style') { const { setup, map, options, store } = ctx; const hasLayers = options.styles.some(style => map.getLayer(style.id)); @@ -191,7 +177,7 @@ export default function (ctx: DrawCTX) { currentMode = setupModeHandler(mode, ctx); if (!eventOptions.silent) { - ctx.map.fire(Constants.events.MODE_CHANGE, { mode: modename }); + ctx.map.fire(Constants.events.MODE_CHANGE, { mode: modename}); } ctx.store.setDirty(); @@ -206,14 +192,12 @@ export default function (ctx: DrawCTX) { function actionable(actions) { let changed = false; - Object.keys(actions).forEach(action => { - if (actionState[action] === undefined) - throw new Error('Invalid action type'); + Object.keys(actions).forEach((action) => { + if (actionState[action] === undefined) throw new Error('Invalid action type'); if (actionState[action] !== actions[action]) changed = true; actionState[action] = actions[action]; }); - if (changed) - ctx.map.fire(Constants.events.ACTIONABLE, { actions: actionState }); + if (changed) ctx.map.fire(Constants.events.ACTIONABLE, { actions: actionState }); } const api = { diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index 823d1f9f..1eaade36 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -78,4 +78,3 @@ class Feature { } export default Feature; - diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index 948946a3..5c83806f 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -20,7 +20,9 @@ class LineString extends Feature { getCoordinate(path: string): Coordinate | undefined { const id = parseInt(path, 10); - return this.coordinates[id] ? [...this.coordinates[id] as Coordinate] : undefined; + return this.coordinates[id] + ? [...(this.coordinates[id] as Coordinate)] + : undefined; } removeCoordinate(path: string): void { diff --git a/src/feature_types/multi_feature.ts b/src/feature_types/multi_feature.ts index 6fb15d35..874813b1 100644 --- a/src/feature_types/multi_feature.ts +++ b/src/feature_types/multi_feature.ts @@ -16,7 +16,11 @@ type FeatureType = MultiPoint | MultiLineString | MultiPolygon; const takeAction = ( features: FeatureType[], - action: 'getCoordinate' | 'updateCoordinate' | 'addCoordinate' | 'removeCoordinate', + action: + | 'getCoordinate' + | 'updateCoordinate' + | 'addCoordinate' + | 'removeCoordinate', path: string, lng?: number, lat?: number @@ -35,7 +39,7 @@ class MultiFeature extends Feature { super(ctx, geojson); delete this.coordinates; - + // Determine the model based on geojson type this.model = models[geojson.geometry.type]; if (this.model === undefined) { @@ -48,16 +52,17 @@ class MultiFeature extends Feature { private _coordinatesToFeatures(coordinates: any[]): FeatureType[] { const Model = this.model.bind(this); - return coordinates.map((coords) => - new Model(this.ctx, { - id: generateID(), - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - coordinates: coords, - type: this.type.replace('Multi', '') - } - }) + return coordinates.map( + coords => + new Model(this.ctx, { + id: generateID(), + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + coordinates: coords, + type: this.type.replace('Multi', '') + } + }) ); } @@ -77,7 +82,7 @@ class MultiFeature extends Feature { getCoordinates(): any[] { return JSON.parse( JSON.stringify( - this.features.map((f) => { + this.features.map(f => { if (f.type === Constants.geojsonTypes.POLYGON) { return f.getCoordinates(); } diff --git a/src/feature_types/polygon.ts b/src/feature_types/polygon.ts index 07fdcabf..9e400f21 100644 --- a/src/feature_types/polygon.ts +++ b/src/feature_types/polygon.ts @@ -6,7 +6,9 @@ class Polygon extends Feature { super(ctx, geojson); // Ensure coordinates are properly typed and adjust them. - this.coordinates = this.coordinates.map((ring: Coords) => ring.slice(0, -1)); + this.coordinates = this.coordinates.map((ring: Coords) => + ring.slice(0, -1) + ); } isValid(): boolean { @@ -70,4 +72,3 @@ class Polygon extends Feature { } export default Polygon; - diff --git a/src/lib/create_midpoint.ts b/src/lib/create_midpoint.ts index 420f8305..b50e5c84 100644 --- a/src/lib/create_midpoint.ts +++ b/src/lib/create_midpoint.ts @@ -1,7 +1,11 @@ import * as Constants from '../constants'; import type { Feature, Point } from 'geojson'; -export const createMidPoint = (parent: string, startVertex: Feature, endVertex: Feature): Feature => { +export const createMidPoint = ( + parent: string, + startVertex: Feature, + endVertex: Feature +): Feature => { const startCoord = (startVertex.geometry as Point).coordinates; const endCoord = (endVertex.geometry as Point).coordinates; @@ -35,4 +39,4 @@ export const createMidPoint = (parent: string, startVertex: Feature, endVertex: coordinates: [mid.lng, mid.lat] } }; -} +}; diff --git a/src/lib/create_vertex.ts b/src/lib/create_vertex.ts index 627784f9..31b523a7 100644 --- a/src/lib/create_vertex.ts +++ b/src/lib/create_vertex.ts @@ -1,7 +1,12 @@ import * as Constants from '../constants'; import type { Feature } from 'geojson'; -export const createVertex = (parentId: string, coordinates: [number, number], path: string, selected: boolean): Feature => { +export const createVertex = ( + parentId: string, + coordinates: [number, number], + path: string, + selected: boolean +): Feature => { return { type: Constants.geojsonTypes.FEATURE as 'Feature', properties: { @@ -17,4 +22,4 @@ export const createVertex = (parentId: string, coordinates: [number, number], pa coordinates } }; -} +}; diff --git a/src/lib/euclidean_distance.ts b/src/lib/euclidean_distance.ts index 70880d51..44f094da 100644 --- a/src/lib/euclidean_distance.ts +++ b/src/lib/euclidean_distance.ts @@ -4,4 +4,4 @@ export const euclideanDistance = (a: XY, b: XY) => { const x = a.x - b.x; const y = a.y - b.y; return Math.sqrt(x * x + y * y); -} +}; diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index a9d7e6ef..8929b2d0 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -14,12 +14,7 @@ const META_TYPES = [ Constants.meta.VERTEX ]; -const featuresAt = ( - event: Event, - bbox: BBox, - ctx: DrawCTX, - buffer: number -) => { +const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: number) => { if (ctx.map === null) return []; const box = event ? mapEventToBoundingBox(event, buffer) : bbox; diff --git a/src/lib/index.ts b/src/lib/index.ts index 9d0aac7c..170567ea 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -7,7 +7,7 @@ import { doubleClickZoom } from './double_click_zoom'; import { euclideanDistance } from './euclidean_distance'; import * as featuresAt from './features_at'; import { getFeatureAtAndSetCursors } from './get_features_at_and_set_cursor'; -import isClick from './is_click'; +import { isClick } from './is_click'; import { isEventAtCoordinates } from './is_event_at_coordinates'; import { isTap } from './is_tap'; import mapEventToBoundingBox from './map_event_to_bounding_box'; diff --git a/src/lib/is_click.ts b/src/lib/is_click.ts index fb0fb4fc..0351c569 100644 --- a/src/lib/is_click.ts +++ b/src/lib/is_click.ts @@ -7,16 +7,12 @@ interface Options { interval: number; } -export default function isClick( - start: Entry, - end: Entry, +export const isClick = ( + start: Entry, + end: Entry, options: Partial = {} -) { - const { - fineTolerance = 4, - grossTolerance = 12, - interval = 500 - } = options; +) => { + const { fineTolerance = 4, grossTolerance = 12, interval = 500 } = options; const adjustedStart = { point: start.point || end.point, @@ -34,4 +30,3 @@ export default function isClick( (moveDistance < grossTolerance && end.time - adjustedStart.time < interval) ); } - diff --git a/src/lib/is_event_at_coordinates.ts b/src/lib/is_event_at_coordinates.ts index d434c3ac..b7286190 100644 --- a/src/lib/is_event_at_coordinates.ts +++ b/src/lib/is_event_at_coordinates.ts @@ -7,4 +7,4 @@ export const isEventAtCoordinates = ( Math.abs(event.lngLat.lng - coordinates[0]) < tolerance && Math.abs(event.lngLat.lat - coordinates[1]) < tolerance ); -} +}; diff --git a/src/lib/is_tap.ts b/src/lib/is_tap.ts index 558db0fb..359dc4fd 100644 --- a/src/lib/is_tap.ts +++ b/src/lib/is_tap.ts @@ -6,12 +6,13 @@ interface Options { interval: number; } -export const isTap = (start: Entry, end: Entry, { - tolerance = 25, - interval = 250 -}: Options) => { +export const isTap = ( + start: Entry, + end: Entry, + { tolerance = 25, interval = 250 }: Options +) => { start.point = start.point || end.point; start.time = start.time || end.time; const moveDistance = euclideanDistance(start.point, end.point); return moveDistance < tolerance && end.time - start.time < interval; -} +}; diff --git a/src/lib/mouse_event_point.ts b/src/lib/mouse_event_point.ts index 4e8b8127..3b1311c0 100644 --- a/src/lib/mouse_event_point.ts +++ b/src/lib/mouse_event_point.ts @@ -1,7 +1,10 @@ import Point from '@mapbox/point-geometry'; import type { PointLike } from 'mapbox-gl'; -function mouseEventPoint(mouseEvent: MouseEvent, container: HTMLElement): PointLike { +function mouseEventPoint( + mouseEvent: MouseEvent, + container: HTMLElement +): PointLike { const rect = container.getBoundingClientRect(); return new Point( mouseEvent.clientX - rect.left - (container.clientLeft || 0), diff --git a/src/lib/string_sets_are_equal.ts b/src/lib/string_sets_are_equal.ts index 6d10b037..6e77a92d 100644 --- a/src/lib/string_sets_are_equal.ts +++ b/src/lib/string_sets_are_equal.ts @@ -4,4 +4,4 @@ export const stringSetsAreEqual = (a: Array, b: Array) => { JSON.stringify(a.map(id => id).sort()) === JSON.stringify(b.map(id => id).sort()) ); -} +}; diff --git a/src/lib/to_dense_array.ts b/src/lib/to_dense_array.ts index fd477d51..77c76438 100644 --- a/src/lib/to_dense_array.ts +++ b/src/lib/to_dense_array.ts @@ -1,3 +1,3 @@ export const toDenseArray = (x: unknown): Array => { return [].concat(x).filter(y => y !== undefined); -} +}; diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index c90f3f89..48875a8e 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -1,244 +1,161 @@ import * as Constants from '../constants'; -import * as featuresAt from '../lib/features_at'; +import * as featuresAt from '../lib/features_at'; import Point from '../feature_types/point'; import LineString from '../feature_types/line_string'; import Polygon from '../feature_types/polygon'; import MultiFeature from '../feature_types/multi_feature'; +import type { DrawCTX } from '../types/types'; +import type { Feature as GeoJSONFeature } from 'geojson'; -export default function ModeInterface(ctx) { - this.map = ctx.map; - this.drawConfig = JSON.parse(JSON.stringify(ctx.options || {})); - this._ctx = ctx; +type DrawFeature = Point | LineString | Polygon | MultiFeature; + +interface SelectedCoordinate { + coord_path: string; + feature_id: string; +} + +interface DrawActions { + trash?: boolean; + combineFeatures?: boolean; + uncombineFeatures?: boolean; } -/** - * Sets Draw's interal selected state - * @name this.setSelected - * @param {DrawFeature[]} - whats selected as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) - */ -ModeInterface.prototype.setSelected = function (features) { - return this._ctx.store.setSelected(features); -}; - -/** - * Sets Draw's internal selected coordinate state - * @name this.setSelectedCoordinates - * @param {Object[]} coords - a array of {coord_path: 'string', feature_id: 'string'} - */ -ModeInterface.prototype.setSelectedCoordinates = function (coords) { - this._ctx.store.setSelectedCoordinates(coords); - coords.reduce((m, c) => { - if (m[c.feature_id] === undefined) { - m[c.feature_id] = true; - this._ctx.store.get(c.feature_id).changed(); +export default class ModeInterface { + private map: any; + private drawConfig: any; + private _ctx: DrawCTX; + + constructor(ctx: DrawCTX) { + console.log('CTX', ctx); + + this.map = ctx.map; + this.drawConfig = { ...ctx.options }; + this._ctx = ctx; + } + + setSelected(features: DrawFeature[]): void { + this._ctx.store.setSelected(features); + } + + setSelectedCoordinates(coords: SelectedCoordinate[]): void { + this._ctx.store.setSelectedCoordinates(coords); + coords.reduce( + (m, c) => { + if (!m[c.feature_id]) { + m[c.feature_id] = true; + this._ctx.store.get(c.feature_id)?.changed(); + } + return m; + }, + {} as Record + ); + } + + getSelected(): DrawFeature[] { + return this._ctx.store.getSelected(); + } + + getSelectedIds(): string[] { + return this._ctx.store.getSelectedIds(); + } + + isSelected(id: string): boolean { + return this._ctx.store.isSelected(id); + } + + getFeature(id: string): DrawFeature | undefined { + return this._ctx.store.get(id); + } + + select(id: string): void { + this._ctx.store.select(id); + } + + deselect(id: string): void { + this._ctx.store.deselect(id); + } + + deleteFeature(id: string, opts: Record = {}): void { + this._ctx.store.delete(id, opts); + } + + addFeature(feature: DrawFeature, opts: Record = {}): void { + this._ctx.store.add(feature, opts); + } + + clearSelectedFeatures(): void { + this._ctx.store.clearSelected(); + } + + clearSelectedCoordinates(): void { + this._ctx.store.clearSelectedCoordinates(); + } + + setActionableState({ + trash, + combineFeatures, + uncombineFeatures + }: DrawActions): void { + this._ctx.events.actionable({ + trash: trash || false, + combineFeatures: combineFeatures || false, + uncombineFeatures: uncombineFeatures || false + }); + } + + changeMode( + mode: string, + opts: Record = {}, + eventOpts: Record = {} + ): void { + this._ctx.events.changeMode(mode, opts, eventOpts); + } + + fire(eventName: string, eventData: any): void { + this._ctx.events.fire(eventName, eventData); + } + + updateUIClasses(opts: Record): void { + this._ctx.ui.queueMapClasses(opts); + } + + activateUIButton(name?: string): void { + this._ctx.ui.setActiveButton(name); + } + + featuresAt( + event: any, + bbox: any, + bufferType: 'click' | 'touch' = 'click' + ): any { + if (bufferType !== 'click' && bufferType !== 'touch') { + throw new Error('invalid buffer type'); } - return m; - }, {}); -}; - -/** - * Get all selected features as a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) - * @name this.getSelected - * @returns {DrawFeature[]} - */ -ModeInterface.prototype.getSelected = function () { - return this._ctx.store.getSelected(); -}; - -/** - * Get the ids of all currently selected features - * @name this.getSelectedIds - * @returns {String[]} - */ -ModeInterface.prototype.getSelectedIds = function () { - return this._ctx.store.getSelectedIds(); -}; - -/** - * Check if a feature is selected - * @name this.isSelected - * @param {String} id - a feature id - * @returns {Boolean} - */ -ModeInterface.prototype.isSelected = function (id) { - return this._ctx.store.isSelected(id); -}; - -/** - * Get a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) by its id - * @name this.getFeature - * @param {String} id - a feature id - * @returns {DrawFeature} - */ -ModeInterface.prototype.getFeature = function (id) { - return this._ctx.store.get(id); -}; - -/** - * Add a feature to draw's internal selected state - * @name this.select - * @param {String} id - */ -ModeInterface.prototype.select = function (id) { - return this._ctx.store.select(id); -}; - -/** - * Remove a feature from draw's internal selected state - * @name this.delete - * @param {String} id - */ -ModeInterface.prototype.deselect = function (id) { - return this._ctx.store.deselect(id); -}; - -/** - * Delete a feature from draw - * @name this.deleteFeature - * @param {String} id - a feature id - */ -ModeInterface.prototype.deleteFeature = function (id, opts = {}) { - return this._ctx.store.delete(id, opts); -}; - -/** - * Add a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) to draw. - * See `this.newFeature` for converting geojson into a DrawFeature - * @name this.addFeature - * @param {DrawFeature} feature - the feature to add - */ -ModeInterface.prototype.addFeature = function (feature, opts = {}) { - return this._ctx.store.add(feature, opts); -}; - -/** - * Clear all selected features - */ -ModeInterface.prototype.clearSelectedFeatures = function () { - return this._ctx.store.clearSelected(); -}; - -/** - * Clear all selected coordinates - */ -ModeInterface.prototype.clearSelectedCoordinates = function () { - return this._ctx.store.clearSelectedCoordinates(); -}; - -/** - * Indicate if the different action are currently possible with your mode - * See [draw.actionalbe](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#drawactionable) for a list of possible actions. All undefined actions are set to **false** by default - * @name this.setActionableState - * @param {Object} actions - */ -ModeInterface.prototype.setActionableState = function (actions = {}) { - const newSet = { - trash: actions.trash || false, - combineFeatures: actions.combineFeatures || false, - uncombineFeatures: actions.uncombineFeatures || false - }; - return this._ctx.events.actionable(newSet); -}; - -/** - * Trigger a mode change - * @name this.changeMode - * @param {String} mode - the mode to transition into - * @param {Object} opts - the options object to pass to the new mode - * @param {Object} eventOpts - used to control what kind of events are emitted. - */ -ModeInterface.prototype.changeMode = function ( - mode, - opts = {}, - eventOpts = {} -) { - return this._ctx.events.changeMode(mode, opts, eventOpts); -}; - -/** - * Fire a map event - * @name this.fire - * @param {String} eventName - the event name. - * @param {Object} eventData - the event data object. - */ -ModeInterface.prototype.fire = function (eventName, eventData) { - return this._ctx.events.fire(eventName, eventData); -}; - -/** - * Update the state of draw map classes - * @name this.updateUIClasses - * @param {Object} opts - */ -ModeInterface.prototype.updateUIClasses = function (opts) { - return this._ctx.ui.queueMapClasses(opts); -}; - -/** - * If a name is provided it makes that button active, else if makes all buttons inactive - * @name this.activateUIButton - * @param {String?} name - name of the button to make active, leave as undefined to set buttons to be inactive - */ -ModeInterface.prototype.activateUIButton = function (name) { - return this._ctx.ui.setActiveButton(name); -}; - -/** - * Get the features at the location of an event object or in a bbox - * @name this.featuresAt - * @param {Event||NULL} event - a mapbox-gl event object - * @param {BBOX||NULL} bbox - the area to get features from - * @param {String} bufferType - is this `click` or `tap` event, defaults to click - */ -ModeInterface.prototype.featuresAt = function ( - event, - bbox, - bufferType = 'click' -) { - if (bufferType !== 'click' && bufferType !== 'touch') - throw new Error('invalid buffer type'); - return featuresAt[bufferType](event, bbox, this._ctx); -}; - -/** - * Create a new [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) from geojson - * @name this.newFeature - * @param {GeoJSONFeature} geojson - * @returns {DrawFeature} - */ -ModeInterface.prototype.newFeature = function (geojson) { - const type = geojson.geometry.type; - if (type === Constants.geojsonTypes.POINT) - return new Point(this._ctx, geojson); - if (type === Constants.geojsonTypes.LINE_STRING) - return new LineString(this._ctx, geojson); - if (type === Constants.geojsonTypes.POLYGON) - return new Polygon(this._ctx, geojson); - return new MultiFeature(this._ctx, geojson); -}; - -/** - * Check is an object is an instance of a [DrawFeature](https://github.com/mapbox/mapbox-gl-draw/blob/main/src/feature_types/feature) - * @name this.isInstanceOf - * @param {String} type - `Point`, `LineString`, `Polygon`, `MultiFeature` - * @param {Object} feature - the object that needs to be checked - * @returns {Boolean} - */ -ModeInterface.prototype.isInstanceOf = function (type, feature) { - if (type === Constants.geojsonTypes.POINT) return feature instanceof Point; - if (type === Constants.geojsonTypes.LINE_STRING) - return feature instanceof LineString; - if (type === Constants.geojsonTypes.POLYGON) - return feature instanceof Polygon; - if (type === 'MultiFeature') return feature instanceof MultiFeature; - throw new Error(`Unknown feature class: ${type}`); -}; - -/** - * Force draw to rerender the feature of the provided id - * @name this.doRender - * @param {String} id - a feature id - */ -ModeInterface.prototype.doRender = function (id) { - return this._ctx.store.featureChanged(id); -}; + return featuresAt[bufferType](event, bbox, this._ctx); + } + + newFeature(geojson: GeoJSONFeature): DrawFeature { + const type = geojson.geometry.type; + if (type === Constants.geojsonTypes.POINT) + return new Point(this._ctx, geojson); + if (type === Constants.geojsonTypes.LINE_STRING) + return new LineString(this._ctx, geojson); + if (type === Constants.geojsonTypes.POLYGON) + return new Polygon(this._ctx, geojson); + return new MultiFeature(this._ctx, geojson); + } + + isInstanceOf(type: string, feature: any): boolean { + if (type === Constants.geojsonTypes.POINT) return feature instanceof Point; + if (type === Constants.geojsonTypes.LINE_STRING) + return feature instanceof LineString; + if (type === Constants.geojsonTypes.POLYGON) + return feature instanceof Polygon; + if (type === 'MultiFeature') return feature instanceof MultiFeature; + throw new Error(`Unknown feature class: ${type}`); + } + + doRender(id: string): void { + this._ctx.store.featureChanged(id); + } +} diff --git a/src/modes/object_to_mode.ts b/src/modes/object_to_mode.ts index a8ab9bcb..660abb5a 100644 --- a/src/modes/object_to_mode.ts +++ b/src/modes/object_to_mode.ts @@ -19,7 +19,7 @@ const eventMapper = { const eventKeys = Object.keys(eventMapper); -export const objectToMode = (modeObject) => { +export const objectToMode = modeObject => { const modeObjectKeys = Object.keys(modeObject); return function (ctx: DrawCTX, startOpts = {}) { @@ -69,4 +69,4 @@ export const objectToMode = (modeObject) => { } }; }; -} +}; diff --git a/src/options.ts b/src/options.ts index 4d201cbd..01c6fd55 100644 --- a/src/options.ts +++ b/src/options.ts @@ -47,7 +47,7 @@ function addSources(styles, sourceBucket) { } export default function (options = {}) { - let withDefaults = { ...options} + let withDefaults = { ...options }; if (!options.controls) { withDefaults.controls = {}; diff --git a/src/setup.ts b/src/setup.ts index 31abe261..9802f95d 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -2,9 +2,9 @@ import events from './events'; import Store from './store'; import ui from './ui'; import * as Constants from './constants'; -import type { DrawCTX } from './types/types'; +import type { CTX } from './types/types'; -export default function (ctx: DrawCTX) { +export default function (ctx: CTX) { let controlContainer = null; let mapLoadedInterval = null; diff --git a/src/store.ts b/src/store.ts index e09736b4..96214f9a 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,31 +2,38 @@ import { toDenseArray } from './lib/to_dense_array'; import StringSet from './lib/string_set'; import render from './render'; import * as Constants from './constants'; -import type { DrawCTX } from './types/types'; - -export default function Store(ctx: DrawCTX) { - this._features = {}; - this._featureIds = new StringSet(); - this._selectedFeatureIds = new StringSet(); - this._selectedCoordinates = []; - this._changedFeatureIds = new StringSet(); - this._emitSelectionChange = false; - this._mapInitialConfig = {}; - this.ctx = ctx; - this.sources = { - hot: [], - cold: [] - }; +import type { DrawCTX, Feature, FeatureId, Coordinate, StoreOptions } from './types/types'; + +type MapConfig = Record; + +type FeaturePropertyOptions = { + silent?: boolean; + action?: string; +}; + +export default class Store { + private _features: Record = {}; + private _featureIds = new StringSet(); + private _selectedFeatureIds = new StringSet(); + private _selectedCoordinates: Coordinate[] = []; + private _changedFeatureIds = new StringSet(); + private _emitSelectionChange = false; + private _mapInitialConfig: MapConfig = {}; + private ctx: DrawCTX; + private isDirty = false; + private sources = { hot: [], cold: [] }; + private renderRequest: number | null = null; + + constructor(ctx: DrawCTX) { + this.ctx = ctx; + } - // Deduplicate requests to render and tie them to animation frames. - let renderRequest; - this.render = () => { - if (!renderRequest) { - renderRequest = requestAnimationFrame(() => { - renderRequest = null; + render = (): void => { + if (!this.renderRequest) { + this.renderRequest = requestAnimationFrame(() => { + this.renderRequest = null; render.call(this); - // Fire deduplicated selection change event if (this._emitSelectionChange) { this.ctx.events.fire(Constants.events.SELECTION_CHANGE, { features: this.getSelected().map(feature => feature.toGeoJSON()), @@ -35,401 +42,186 @@ export default function Store(ctx: DrawCTX) { properties: {}, geometry: { type: Constants.geojsonTypes.POINT, - coordinates: coordinate.coordinates - } - })) + coordinates: coordinate.coordinates, + }, + })), }); - this._emitSelectionChange = false; } - // Fire render event this.ctx.events.fire(Constants.events.RENDER, {}); }); } }; - this.isDirty = false; -} - -/** - * Delays all rendering until the returned function is invoked - * @return {Function} renderBatch - */ -Store.prototype.createRenderBatch = function () { - const holdRender = this.render; - let numRenders = 0; - this.render = function () { - numRenders++; - }; - - return () => { - this.render = holdRender; - if (numRenders > 0) { - this.render(); - } - }; -}; - -/** - * Sets the store's state to dirty. - * @return {Store} this - */ -Store.prototype.setDirty = function () { - this.isDirty = true; - return this; -}; + createRenderBatch(): () => void { + const holdRender = this.render; + let numRenders = 0; + this.render = () => numRenders++; -/** - * Sets a feature's state to changed. - * @param {string} featureId - * @return {Store} this - */ -Store.prototype.featureCreated = function (featureId, options = {}) { - this._changedFeatureIds.add(featureId); - - const silent = - options.silent != null - ? options.silent - : this.ctx.options.suppressAPIEvents; - if (silent !== true) { - const feature = this.get(featureId); - this.ctx.events.fire(Constants.events.CREATE, { - features: [feature.toGeoJSON()] - }); + return () => { + this.render = holdRender; + if (numRenders > 0) this.render(); + }; } - return this; -}; + setDirty(): this { + this.isDirty = true; + return this; + } -/** - * Sets a feature's state to changed. - * @param {string} featureId - * @return {Store} this - */ -Store.prototype.featureChanged = function (featureId, options = {}) { - this._changedFeatureIds.add(featureId); - - const silent = - options.silent != null - ? options.silent - : this.ctx.options.suppressAPIEvents; - if (silent !== true) { - this.ctx.events.fire(Constants.events.UPDATE, { - action: options.action - ? options.action - : Constants.updateActions.CHANGE_COORDINATES, - features: [this.get(featureId).toGeoJSON()] - }); + featureCreated(featureId: FeatureId, options: StoreOptions = {}): this { + this._changedFeatureIds.add(featureId); + if (!options.silent) { + const feature = this.get(featureId); + this.ctx.events.fire(Constants.events.CREATE, { features: [feature.toGeoJSON()] }); + } + return this; } - return this; -}; + featureChanged(featureId: FeatureId, options: FeaturePropertyOptions = {}): this { + this._changedFeatureIds.add(featureId); + if (!options.silent) { + this.ctx.events.fire(Constants.events.UPDATE, { + action: options.action ?? Constants.updateActions.CHANGE_COORDINATES, + features: [this.get(featureId).toGeoJSON()], + }); + } + return this; + } -/** - * Gets the ids of all features currently in changed state. - * @return {Store} this - */ -Store.prototype.getChangedIds = function () { - return this._changedFeatureIds.values(); -}; + getChangedIds(): string[] { + return this._changedFeatureIds.values(); + } -/** - * Sets all features to unchanged state. - * @return {Store} this - */ -Store.prototype.clearChangedIds = function () { - this._changedFeatureIds.clear(); - return this; -}; + clearChangedIds(): this { + this._changedFeatureIds.clear(); + return this; + } -/** - * Gets the ids of all features in the store. - * @return {Store} this - */ -Store.prototype.getAllIds = function () { - return this._featureIds.values(); -}; + getAllIds(): string[] { + return this._featureIds.values(); + } -/** - * Adds a feature to the store. - * @param {Object} feature - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - * - * @return {Store} this - */ -Store.prototype.add = function (feature, options = {}) { - this._features[feature.id] = feature; - this._featureIds.add(feature.id); - this.featureCreated(feature.id, { silent: options.silent }); - return this; -}; + add(feature: Feature, options: StoreOptions = {}): this { + this._features[feature.id] = feature; + this._featureIds.add(feature.id); + this.featureCreated(feature.id, { silent: options.silent }); + return this; + } -/** - * Deletes a feature or array of features from the store. - * Cleans up after the deletion by deselecting the features. - * If changes were made, sets the state to the dirty - * and fires an event. - * @param {string | Array} featureIds - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - * @return {Store} this - */ -Store.prototype.delete = function (featureIds, options = {}) { - const deletedFeaturesToEmit = []; - toDenseArray(featureIds).forEach(id => { - if (!this._featureIds.has(id)) return; - this._featureIds.delete(id); - this._selectedFeatureIds.delete(id); - if (!options.silent) { - if (deletedFeaturesToEmit.indexOf(this._features[id]) === -1) { - deletedFeaturesToEmit.push(this._features[id].toGeoJSON()); + delete(featureIds: FeatureId | FeatureId[], options: StoreOptions = {}): this { + const deletedFeatures: Feature[] = []; + toDenseArray(featureIds).forEach(id => { + if (!this._featureIds.has(id)) return; + this._featureIds.delete(id); + this._selectedFeatureIds.delete(id); + if (!options.silent) { + deletedFeatures.push(this._features[id].toGeoJSON()); } + delete this._features[id]; + this.isDirty = true; + }); + + if (deletedFeatures.length) { + this.ctx.events.fire(Constants.events.DELETE, { features: deletedFeatures }); } - delete this._features[id]; - this.isDirty = true; - }); - if (deletedFeaturesToEmit.length) { - this.ctx.events.fire(Constants.events.DELETE, { - features: deletedFeaturesToEmit - }); + this.refreshSelectedCoordinates(options); + return this; } - refreshSelectedCoordinates(this, options); - return this; -}; - -/** - * Returns a feature in the store matching the specified value. - * @return {Object | undefined} feature - */ -Store.prototype.get = function (id) { - return this._features[id]; -}; + get(id: FeatureId): Feature { + return this._features[id]; + } -/** - * Returns all features in the store. - * @return {Array} - */ -Store.prototype.getAll = function () { - return Object.keys(this._features).map(id => this._features[id]); -}; + getAll(): Feature[] { + return Object.values(this._features); + } -/** - * Adds features to the current selection. - * @param {string | Array} featureIds - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - * @return {Store} this - */ -Store.prototype.select = function (featureIds, options = {}) { - toDenseArray(featureIds).forEach(id => { - if (this._selectedFeatureIds.has(id)) return; - this._selectedFeatureIds.add(id); - this._changedFeatureIds.add(id); - if (!options.silent) { - this._emitSelectionChange = true; - } - }); - return this; -}; + getSelectedIds(): string[] { + return this._selectedFeatureIds.values(); + } -/** - * Deletes features from the current selection. - * @param {string | Array} featureIds - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - * @return {Store} this - */ -Store.prototype.deselect = function (featureIds, options = {}) { - toDenseArray(featureIds).forEach(id => { - if (!this._selectedFeatureIds.has(id)) return; - this._selectedFeatureIds.delete(id); - this._changedFeatureIds.add(id); - if (!options.silent) { - this._emitSelectionChange = true; - } - }); - refreshSelectedCoordinates(this, options); - return this; -}; + getSelected(): Feature[] { + return this.getSelectedIds().map(id => this.get(id)); + } -/** - * Clears the current selection. - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - * @return {Store} this - */ -Store.prototype.clearSelected = function (options = {}) { - this.deselect(this._selectedFeatureIds.values(), { silent: options.silent }); - return this; -}; + getSelectedCoordinates(): Coordinate[] { + return this._selectedCoordinates.map(coordinate => { + const feature = this.get(coordinate.feature_id); + return { coordinates: feature.getCoordinate(coordinate.coord_path) }; + }); + } -/** - * Sets the store's selection, clearing any prior values. - * If no feature ids are passed, the store is just cleared. - * @param {string | Array | undefined} featureIds - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - * @return {Store} this - */ -Store.prototype.setSelected = function (featureIds, options = {}) { - featureIds = toDenseArray(featureIds); - - // Deselect any features not in the new selection - this.deselect( - this._selectedFeatureIds - .values() - .filter(id => featureIds.indexOf(id) === -1), - { silent: options.silent } - ); - - // Select any features in the new selection that were not already selected - this.select( - featureIds.filter(id => !this._selectedFeatureIds.has(id)), - { silent: options.silent } - ); - - return this; -}; + select(featureIds: FeatureId[], options: StoreOptions = {}): this { + toDenseArray(featureIds).forEach(id => { + if (this._selectedFeatureIds.has(id)) return; + this._selectedFeatureIds.add(id); + this._changedFeatureIds.add(id); + if (!options.silent) this._emitSelectionChange = true; + }); + return this; + } -/** - * Sets the store's coordinates selection, clearing any prior values. - * @param {Array>} coordinates - * @return {Store} this - */ -Store.prototype.setSelectedCoordinates = function (coordinates) { - this._selectedCoordinates = coordinates; - this._emitSelectionChange = true; - return this; -}; + deselect(featureIds: FeatureId[], options: StoreOptions = {}): this { + toDenseArray(featureIds).forEach(id => { + if (!this._selectedFeatureIds.has(id)) return; + this._selectedFeatureIds.delete(id); + this._changedFeatureIds.add(id); + if (!options.silent) this._emitSelectionChange = true; + }); + this.refreshSelectedCoordinates(options); + return this; + } -/** - * Clears the current coordinates selection. - * @param {Object} [options] - * @return {Store} this - */ -Store.prototype.clearSelectedCoordinates = function () { - this._selectedCoordinates = []; - this._emitSelectionChange = true; - return this; -}; + setSelected(featureIds: FeatureId[], options: StoreOptions = {}): this { + featureIds = toDenseArray(featureIds); -/** - * Returns the ids of features in the current selection. - * @return {Array} Selected feature ids. - */ -Store.prototype.getSelectedIds = function () { - return this._selectedFeatureIds.values(); -}; + // Deselect any features not in the new selection + this.deselect(this._selectedFeatureIds.values().filter(id => featureIds.indexOf(id) === -1), { silent: options.silent }); -/** - * Returns features in the current selection. - * @return {Array} Selected features. - */ -Store.prototype.getSelected = function () { - return this.getSelectedIds().map(id => this.get(id)); -}; + // Select any features in the new selection that were not already selected + this.select(featureIds.filter(id => !this._selectedFeatureIds.has(id)), { silent: options.silent }); -/** - * Returns selected coordinates in the currently selected feature. - * @return {Array} Selected coordinates. - */ -Store.prototype.getSelectedCoordinates = function () { - const selected = this._selectedCoordinates.map(coordinate => { - const feature = this.get(coordinate.feature_id); - return { - coordinates: feature.getCoordinate(coordinate.coord_path) - }; - }); - return selected; -}; + return this; + }; -/** - * Indicates whether a feature is selected. - * @param {string} featureId - * @return {boolean} `true` if the feature is selected, `false` if not. - */ -Store.prototype.isSelected = function (featureId) { - return this._selectedFeatureIds.has(featureId); -}; + isSelected(featureId: string): this { + return this._selectedFeatureIds.has(featureId); + }; -/** - * Sets a property on the given feature - * @param {string} featureId - * @param {string} property property - * @param {string} property value - * @param {Object} [options] - * @param {Object} [options.silent] - If `true`, this invocation will not fire an event. - */ -Store.prototype.setFeatureProperty = function ( - featureId, - property, - value, - options = {} -) { - this.get(featureId).setProperty(property, value); - - this.featureChanged(featureId, { - silent: options.silent, - action: Constants.updateActions.CHANGE_PROPERTIES - }); -}; + clearSelected(options: StoreOptions = {}): this { + this.deselect(this._selectedFeatureIds.values(), { silent: options.silent }); + return this; + }; -function refreshSelectedCoordinates(store, options = {}) { - const newSelectedCoordinates = store._selectedCoordinates.filter(point => - store._selectedFeatureIds.has(point.feature_id) - ); - if ( - store._selectedCoordinates.length !== newSelectedCoordinates.length && - !options.silent - ) { - store._emitSelectionChange = true; + storeMapConfig() { + Constants.interactions.forEach((interaction) => { + const interactionSet = this.ctx.map[interaction]; + if (interactionSet) { + this._mapInitialConfig[interaction] = this.ctx.map[interaction].isEnabled(); + } + }); } - store._selectedCoordinates = newSelectedCoordinates; -} -/** - * Stores the initial config for a map, so that we can set it again after we're done. - */ -Store.prototype.storeMapConfig = function () { - Constants.interactions.forEach(interaction => { - const interactionSet = this.ctx.map[interaction]; - if (interactionSet) { - this._mapInitialConfig[interaction] = - this.ctx.map[interaction].isEnabled(); - } - }); -}; + restoreMapConfig() { + Object.keys(this._mapInitialConfig).forEach((key) => { + const value = this._mapInitialConfig[key]; + if (value) { + this.ctx.map[key].enable(); + } else { + this.ctx.map[key].disable(); + } + }); + } -/** - * Restores the initial config for a map, ensuring all is well. - */ -Store.prototype.restoreMapConfig = function () { - Object.keys(this._mapInitialConfig).forEach(key => { - const value = this._mapInitialConfig[key]; - if (value) { - this.ctx.map[key].enable(); - } else { - this.ctx.map[key].disable(); + private refreshSelectedCoordinates(options: StoreOptions = {}): void { + const newSelectedCoordinates = this._selectedCoordinates.filter(point => this._selectedFeatureIds.has(point.feature_id)); + if (this._selectedCoordinates.length !== newSelectedCoordinates.length && !options.silent) { + this._emitSelectionChange = true; } - }); -}; - -/** - * Returns the initial state of an interaction setting. - * @param {string} interaction - * @return {boolean} `true` if the interaction is enabled, `false` if not. - * Defaults to `true`. (Todo: include defaults.) - */ -Store.prototype.getInitialConfigValue = function (interaction) { - if (this._mapInitialConfig[interaction] !== undefined) { - return this._mapInitialConfig[interaction]; - } else { - // This needs to be set to whatever the default is for that interaction - // It seems to be true for all cases currently, so let's send back `true`. - return true; + this._selectedCoordinates = newSelectedCoordinates; } -}; +} + diff --git a/src/types/types.ts b/src/types/types.ts index 573daf25..05331fb3 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -36,18 +36,20 @@ import type { } from 'mapbox-gl'; // Extend Feature to require geometry and properties -export interface StrictFeature extends Omit { +export interface StrictFeature + extends Omit { geometry: Geometry & { coordinates: unknown }; properties: Record; } // Extend FeatureCollection to use StrictFeature -export interface StrictFeatureCollection extends Omit { +export interface StrictFeatureCollection + extends Omit { features: StrictFeature[]; } // Example usage -export type XY = { x: number, y: number }; +export type XY = { x: number; y: number }; export type Coords = Array<[number, number]>; @@ -101,7 +103,11 @@ interface DrawFeatureBase { } export interface DrawUI { - queueMapClasses: (options: { mode: null, feature: null, mouse: null }) => void; + queueMapClasses: (options: { + mode: null; + feature: null; + mouse: null; + }) => void; setActiveButton: (id: string) => void; updateMapClasses: () => void; clearMapClasses: () => void; @@ -112,20 +118,20 @@ export interface DrawUI { type DrawMode = DrawModes[keyof DrawModes]; interface DrawEvents { - "draw.create": DrawCreateEvent; - "draw.delete": DrawDeleteEvent; - "draw.update": DrawUpdateEvent; - "draw.selectionchange": DrawSelectionChangeEvent; - "draw.render": DrawRenderEvent; - "draw.combine": DrawCombineEvent; - "draw.uncombine": DrawUncombineEvent; - "draw.modechange": DrawModeChangeEvent; - "draw.actionable": DrawActionableEvent; + 'draw.create': DrawCreateEvent; + 'draw.delete': DrawDeleteEvent; + 'draw.update': DrawUpdateEvent; + 'draw.selectionchange': DrawSelectionChangeEvent; + 'draw.render': DrawRenderEvent; + 'draw.combine': DrawCombineEvent; + 'draw.uncombine': DrawUncombineEvent; + 'draw.modechange': DrawModeChangeEvent; + 'draw.actionable': DrawActionableEvent; } type DrawEventType = keyof DrawEvents; -type DrawModes = typeof modes[keyof typeof modes]; +type DrawModes = (typeof modes)[keyof typeof modes]; interface DrawControls { point?: boolean | undefined; @@ -143,14 +149,14 @@ interface DrawActionableState { } interface DrawFeatureBase { - readonly properties: Readonly; + readonly properties: Readonly; readonly coordinates: Coordinates; - readonly id: NonNullable; + readonly id: NonNullable; readonly type: GeoJsonTypes; changed(): void; isValid(): boolean; - incomingCoords: this["setCoordinates"]; + incomingCoords: this['setCoordinates']; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; getCoordinate(path: string): Position; @@ -159,40 +165,44 @@ interface DrawFeatureBase { toGeoJSON(): GeoJSON; } -interface DrawMultiFeature extends - Omit< +interface DrawMultiFeature< + Type extends 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' +> extends Omit< DrawFeatureBase< - | (Type extends "MultiPoint" ? Array : never) - | (Type extends "MultiLineString" ? Array : never) - | (Type extends "MultiPolygon" ? Array : never) + | (Type extends 'MultiPoint' ? Array : never) + | (Type extends 'MultiLineString' + ? Array + : never) + | (Type extends 'MultiPolygon' + ? Array + : never) >, - "coordinates" - > -{ + 'coordinates' + > { readonly type: Type; readonly features: Array< - | (Type extends "MultiPoint" ? DrawPoint : never) - | (Type extends "MultiLineString" ? DrawLineString : never) - | (Type extends "MultiPolygon" ? DrawPolygon : never) + | (Type extends 'MultiPoint' ? DrawPoint : never) + | (Type extends 'MultiLineString' ? DrawLineString : never) + | (Type extends 'MultiPolygon' ? DrawPolygon : never) >; - getFeatures(): this["features"]; + getFeatures(): this['features']; } interface DrawPoint extends DrawFeatureBase { - readonly type: "Point"; + readonly type: 'Point'; getCoordinate(): Position; updateCoordinate(lng: number, lat: number): void; updateCoordinate(path: string, lng: number, lat: number): void; } interface DrawLineString extends DrawFeatureBase { - readonly type: "LineString"; + readonly type: 'LineString'; addCoordinate(path: string | number, lng: number, lat: number): void; removeCoordinate(path: string | number): void; } interface DrawPolygon extends DrawFeatureBase { - readonly type: "Polygon"; + readonly type: 'Polygon'; addCoordinate(path: string, lng: number, lat: number): void; removeCoordinate(path: string): void; } @@ -201,15 +211,15 @@ type DrawFeature = | DrawPoint | DrawLineString | DrawPolygon - | DrawMultiFeature<"MultiPoint"> - | DrawMultiFeature<"MultiLineString"> - | DrawMultiFeature<"MultiPolygon">; + | DrawMultiFeature<'MultiPoint'> + | DrawMultiFeature<'MultiLineString'> + | DrawMultiFeature<'MultiPolygon'>; -interface MapMouseEvent extends MapboxMapMouseEvent { +export interface MapMouseEvent extends MapboxMapMouseEvent { featureTarget: DrawFeature; } -interface MapTouchEvent extends MapboxMapTouchEvent { +export interface MapTouchEvent extends MapboxMapTouchEvent { featureTarget: DrawFeature; } @@ -221,7 +231,7 @@ interface DrawEvent { interface DrawCreateEvent extends DrawEvent { // Array of GeoJSON objects representing the features that were created features: Feature[]; - type: "draw.create"; + type: 'draw.create'; } interface DrawDeleteEvent extends DrawEvent { @@ -272,7 +282,9 @@ export interface DrawCTX { map: Map; drawConfig: DrawOptions; setSelected(features?: string | string[]): void; - setSelectedCoordinates(coords: Array<{ coord_path: string; feature_id: string }>): void; + setSelectedCoordinates( + coords: Array<{ coord_path: string; feature_id: string }> + ): void; getSelected(): DrawFeature[]; getSelectedIds(): string[]; isSelected(id: string): boolean; @@ -287,7 +299,11 @@ export interface DrawCTX { changeMode(mode: DrawMode, opts?: object, eventOpts?: object): void; updateUIClasses(opts: object): void; activateUIButton(name?: string): void; - featuresAt(event: Event, bbox: BBox, bufferType: "click" | "tap"): DrawFeature[]; + featuresAt( + event: Event, + bbox: BBox, + bufferType: 'click' | 'tap' + ): DrawFeature[]; newFeature(geojson: GeoJSON): DrawFeature; isInstanceOf(type: string, feature: object): boolean; doRender(id: string): void; @@ -296,16 +312,56 @@ export interface DrawCTX { interface DrawCustomMode { onSetup?(this: DrawCTX & this, options: CustomModeOptions): CustomModeState; onDrag?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onClick?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseMove?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseDown?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseUp?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onMouseOut?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; - onKeyUp?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; - onKeyDown?(this: DrawCTX & this, state: CustomModeState, e: KeyboardEvent): void; - onTouchStart?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; - onTouchMove?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; - onTouchEnd?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; + onClick?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseMove?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseDown?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseUp?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onMouseOut?( + this: DrawCTX & this, + state: CustomModeState, + e: MapMouseEvent + ): void; + onKeyUp?( + this: DrawCTX & this, + state: CustomModeState, + e: KeyboardEvent + ): void; + onKeyDown?( + this: DrawCTX & this, + state: CustomModeState, + e: KeyboardEvent + ): void; + onTouchStart?( + this: DrawCTX & this, + state: CustomModeState, + e: MapTouchEvent + ): void; + onTouchMove?( + this: DrawCTX & this, + state: CustomModeState, + e: MapTouchEvent + ): void; + onTouchEnd?( + this: DrawCTX & this, + state: CustomModeState, + e: MapTouchEvent + ): void; onTap?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; onStop?(this: DrawCTX & this, state: CustomModeState): void; onTrash?(this: DrawCTX & this, state: CustomModeState): void; @@ -315,7 +371,7 @@ interface DrawCustomMode { this: DrawCTX & this, state: CustomModeState, geojson: GeoJSON, - display: (geojson: GeoJSON) => void, + display: (geojson: GeoJSON) => void ): void; } @@ -329,16 +385,16 @@ interface Modes { // Convert these to use imports from constants interface Constants { - readonly classes: typeof classes[keyof typeof classes]; - readonly sources: typeof sources[keyof typeof sources]; - readonly cursors: typeof cursors[keyof typeof cursors]; - readonly types: typeof types[keyof typeof types]; - readonly geojsonTypes: typeof geojsonTypes[keyof typeof geojsonTypes]; - readonly events: typeof events[keyof typeof events]; - readonly updateActions: typeof updateActions[keyof typeof updateActions]; - readonly meta: typeof meta[keyof typeof meta]; - readonly activeStates: typeof activeStates[keyof typeof activeStates]; - readonly interactions: typeof interactions[keyof typeof interactions]; + readonly classes: (typeof classes)[keyof typeof classes]; + readonly sources: (typeof sources)[keyof typeof sources]; + readonly cursors: (typeof cursors)[keyof typeof cursors]; + readonly types: (typeof types)[keyof typeof types]; + readonly geojsonTypes: (typeof geojsonTypes)[keyof typeof geojsonTypes]; + readonly events: (typeof events)[keyof typeof events]; + readonly updateActions: (typeof updateActions)[keyof typeof updateActions]; + readonly meta: (typeof meta)[keyof typeof meta]; + readonly activeStates: (typeof activeStates)[keyof typeof activeStates]; + readonly interactions: (typeof interactions)[keyof typeof interactions]; readonly LAT_MIN: -90; readonly LAT_RENDERED_MIN: -85; readonly LAT_MAX: 90; @@ -355,10 +411,10 @@ interface StringSet { clear(): StringSet; } -interface Lib { +export interface Lib { CommonSelectors: { isOfMetaType: ( - type: Constants["meta"][keyof Constants["meta"]], + type: Constants['meta'][keyof Constants['meta']] ) => (e: MapMouseEvent | MapTouchEvent) => boolean; isShiftMousedown: (e: MapEvent) => boolean; isActiveFeature: (e: MapMouseEvent | MapTouchEvent) => boolean; @@ -374,120 +430,149 @@ interface Lib { constrainFeatureMovement( geojsonFeatures: DrawFeature[], - delta: { lng: number; lat: number }, + delta: { lng: number; lat: number } ): { lng: number; lat: number }; - createMidPoint(parent: string, startVertex: Feature, endVertex: Feature): Feature | null; + createMidPoint( + parent: string, + startVertex: Feature, + endVertex: Feature + ): Feature | null; createSupplementaryPoints( geojson: Feature, options?: { midpoints?: boolean; selectedPaths?: string[] }, - basePath?: string, + basePath?: string ): Array>; - createVertex(parentId: string, coordinates: Position, path: string, selected: boolean): Feature; + createVertex( + parentId: string, + coordinates: Position, + path: string, + selected: boolean + ): Feature; doubleClickZoom: { enable: (ctx: DrawCTX) => void; // ?? ctx disable: (ctx: DrawCTX) => void; // ?? ctx }; - featuresAt: { - click: (event: MapMouseEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx - touch: (event: MapTouchEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx - }; - - getFeatureAtAndSetCursors(event: MapMouseEvent, ctx: DrawCTX): Feature; - - euclideanDistance(a: { x: number; y: number }, b: { x: number; y: number }): number; - - isClick( - start: { point?: Entry }, - end: { point: Entry }, - options?: { fineTolerance?: number; grossTolerance?: number; interval?: number }, - ): boolean; - - isEventAtCoordinates(event: MapMouseEvent, coordinates: Position[]): boolean; - - isTap( - start: { point?: Entry }, - end: { point: Entry }, - options?: { tolerance?: number; interval?: number }, - ): boolean; - - /** - * Returns a bounding box representing the event's location. - * - * @param mapEvent - Mapbox GL JS map event, with a point properties. - * @param [buffer=0] - * @return Bounding box. - */ - mapEventToBoundingBox(mapEvent: MapMouseEvent | MapTouchEvent, buffer?: number): Position[]; - - ModeHandler: ( - mode: any, - DrawContext: any, - ) => { - render: any; - stop: () => void; - trash: () => void; - combineFeatures: () => void; - uncombineFeatures: () => void; - drag: (event: any) => void; - click: (event: any) => void; - mousemove: (event: any) => void; - mousedown: (event: any) => void; - mouseup: (event: any) => void; - mouseout: (event: any) => void; - keydown: (event: any) => void; - keyup: (event: any) => void; - touchstart: (event: any) => void; - touchmove: (event: any) => void; - touchend: (event: any) => void; - tap: (event: any) => void; - }; - - moveFeatures(features: DrawFeature[], delta: { lng: number; lat: number }): void; - - /** - * Sort features in the following order Point: 0, LineString: 1, MultiLineString: 1, - * Polygon: 2, then sort polygons by area ascending. - * @param features - */ - sortFeatures(features: DrawFeature[]): DrawFeature[]; - - stringSetsAreEqual(a: Array>, b: Array>): boolean; - - StringSet(items?: Array): StringSet; - - theme: Array< - (FillLayerSpecification | LineLayerSpecification | CircleLayerSpecification) & { id: ThemeLayerId } - >; - - /** - * Derive a dense array (no `undefined`s) from a single value or array. - */ - toDenseArray(x: any): Array>; - } + featuresAt: { + click: (event: MapMouseEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx + touch: (event: MapTouchEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx + }; + + getFeatureAtAndSetCursors(event: MapMouseEvent, ctx: DrawCTX): Feature; + + euclideanDistance( + a: { x: number; y: number }, + b: { x: number; y: number } + ): number; + + isClick( + start: { point?: Entry }, + end: { point: Entry }, + options?: { + fineTolerance?: number; + grossTolerance?: number; + interval?: number; + } + ): boolean; + + isEventAtCoordinates(event: MapMouseEvent, coordinates: Position[]): boolean; + + isTap( + start: { point?: Entry }, + end: { point: Entry }, + options?: { tolerance?: number; interval?: number } + ): boolean; + + /** + * Returns a bounding box representing the event's location. + * + * @param mapEvent - Mapbox GL JS map event, with a point properties. + * @param [buffer=0] + * @return Bounding box. + */ + mapEventToBoundingBox( + mapEvent: MapMouseEvent | MapTouchEvent, + buffer?: number + ): Position[]; + + ModeHandler: ( + mode: any, + DrawContext: any + ) => { + render: any; + stop: () => void; + trash: () => void; + combineFeatures: () => void; + uncombineFeatures: () => void; + drag: (event: any) => void; + click: (event: any) => void; + mousemove: (event: any) => void; + mousedown: (event: any) => void; + mouseup: (event: any) => void; + mouseout: (event: any) => void; + keydown: (event: any) => void; + keyup: (event: any) => void; + touchstart: (event: any) => void; + touchmove: (event: any) => void; + touchend: (event: any) => void; + tap: (event: any) => void; + }; + + moveFeatures( + features: DrawFeature[], + delta: { lng: number; lat: number } + ): void; + + /** + * Sort features in the following order Point: 0, LineString: 1, MultiLineString: 1, + * Polygon: 2, then sort polygons by area ascending. + * @param features + */ + sortFeatures(features: DrawFeature[]): DrawFeature[]; + + stringSetsAreEqual( + a: Array>, + b: Array> + ): boolean; + + StringSet(items?: Array): StringSet; + + theme: Array< + ( + | FillLayerSpecification + | LineLayerSpecification + | CircleLayerSpecification + ) & { id: ThemeLayerId } + >; + + /** + * Derive a dense array (no `undefined`s) from a single value or array. + */ + toDenseArray(x: any): Array>; +} type ThemeLayerId = - | "gl-draw-polygon-fill-static" - | "gl-draw-polygon-fill-active" - | "gl-draw-polygon-fill-inactive" - | "gl-draw-polygon-stroke-static" - | "gl-draw-polygon-stroke-active" - | "gl-draw-polygon-stroke-inactive" - | "gl-draw-polygon-midpoint" - | "gl-draw-polygon-and-line-vertex-inactive" - | "gl-draw-polygon-and-line-vertex-stroke-inactive" - | "gl-draw-line-static" - | "gl-draw-line-active" - | "gl-draw-line-inactive" - | "gl-draw-point-static" - | "gl-draw-point-active" - | "gl-draw-point-inactive" - | "gl-draw-point-stroke-active" - | "gl-draw-point-point-stroke-inactive"; + | 'gl-draw-polygon-fill-static' + | 'gl-draw-polygon-fill-active' + | 'gl-draw-polygon-fill-inactive' + | 'gl-draw-polygon-stroke-static' + | 'gl-draw-polygon-stroke-active' + | 'gl-draw-polygon-stroke-inactive' + | 'gl-draw-polygon-midpoint' + | 'gl-draw-polygon-and-line-vertex-inactive' + | 'gl-draw-polygon-and-line-vertex-stroke-inactive' + | 'gl-draw-line-static' + | 'gl-draw-line-active' + | 'gl-draw-line-inactive' + | 'gl-draw-point-static' + | 'gl-draw-point-active' + | 'gl-draw-point-inactive' + | 'gl-draw-point-stroke-active' + | 'gl-draw-point-point-stroke-inactive'; export interface DrawOptions { displayControlsDefault?: boolean | undefined; @@ -503,6 +588,51 @@ export interface DrawOptions { userProperties?: boolean | undefined; } +interface DrawEvents { + actionable(action: DrawActionableState): void; + addEventListeners(): void; + changeMode(mode: string, modeOptions: {}, eventOptions: {}): void; + combineFeatures(): void; + currentModeName(): void; + currentModeRender(geojson: StrictFeature, push: (geojson: StrictFeature) => void): void; + fire(eventName: string, eventData: unknown): DrawMode; + getMode(): DrawMode; + removeEventListeners(): void; + start(): void; + trash(options?: { silent: boolean}): void; + uncombineFeatures(): void; +} + +interface DrawStore { + ctx: CTX; + isDirty: boolean; + render(): void; + sources: { + hot: [], + cold: [] + } +} + +interface DrawSetup { + addLayers(): void; + removeLayers(): void; + onAdd(map: Map): void; + onRemove(): void; + connect(): void; +} + +export interface CTX { + api: Draw; + boxZoomInitial: boolean; + container: HTMLElement; + events: DrawEvents; + map: Map; + options: DrawOptions; + setup: DrawSetup; + store: DrawStore; + ui: DrawUI; +} + export declare class Draw implements IControl { static modes: Modes; static constants: Constants; @@ -522,7 +652,9 @@ export declare class Draw implements IControl { delete(ids: string | string[]): this; deleteAll(): this; set(featureCollection: StrictFeatureCollection): string[]; - trash(): this; + + trash(): DrawEvents['trash']; + combineFeatures(): this; uncombineFeatures(): this; getMode(): (Modes & {}) | string; diff --git a/src/ui.ts b/src/ui.ts index 0e12a2f1..ec8e39a7 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,10 +1,10 @@ import * as Constants from './constants'; -import type { DrawCTX } from './types/types'; +import type { CTX } from './types/types'; const classTypes = ['mode', 'feature', 'mouse']; -export default function (ctx: DrawCTX) { +export default function (ctx: CTX) { const buttonElements = {}; let activeButton = null; @@ -89,7 +89,7 @@ export default function (ctx: DrawCTX) { activeButton = null; } - function setActiveButton(id) { + function setActiveButton(id: string) { deactivateButtons(); const button = buttonElements[id]; diff --git a/test/is_click.test.js b/test/is_click.test.js index 605ea80f..fb3a167c 100644 --- a/test/is_click.test.js +++ b/test/is_click.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import isClick from '../src/lib/is_click.js'; +import { isClick } from '../src/lib/is_click.js'; // By adding these values as options and stating them in the test, // we can know the calculation works from the tests, but tweak From 045467dd113769e71175bd402f3592fd4eefeae3 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 6 Mar 2025 13:58:33 +0200 Subject: [PATCH 14/59] More typing --- src/lib/constrain_feature_movement.ts | 11 +++++--- src/lib/create_supplementary_points.ts | 33 +++++++++++++++--------- src/lib/index.ts | 4 +-- src/lib/move_features.ts | 2 +- src/modes/direct_select.ts | 4 +-- src/modes/simple_select.ts | 2 +- test/create_supplementary_points.test.js | 2 +- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/lib/constrain_feature_movement.ts b/src/lib/constrain_feature_movement.ts index 7136a6a6..2948fbb0 100644 --- a/src/lib/constrain_feature_movement.ts +++ b/src/lib/constrain_feature_movement.ts @@ -1,4 +1,7 @@ import * as Constants from '../constants'; +import type { StrictFeature } from '../types/types'; + +type Delta = { lng: number; lat: number; } const { LAT_MIN, @@ -8,7 +11,7 @@ const { LNG_MIN, LNG_MAX } = Constants; -function extent(feature) { +function extent(feature: StrictFeature) { const depth = { Point: 0, LineString: 1, @@ -21,8 +24,8 @@ function extent(feature) { const coords = [feature.geometry.coordinates].flat(depth); const lngs = coords.map(coord => coord[0]); const lats = coords.map(coord => coord[1]); - const min = vals => Math.min.apply(null, vals); - const max = vals => Math.max.apply(null, vals); + const min = (vals: Array) => Math.min.apply(null, vals); + const max = (vals: Array) => Math.max.apply(null, vals); return [min(lngs), min(lats), max(lngs), max(lats)]; } @@ -30,7 +33,7 @@ function extent(feature) { // - any part of any feature to exceed the poles // - any feature to be completely lost in the space between the projection's // edge and the poles, such that it couldn't be re-selected and moved back -export default function (geojsonFeatures, delta) { +export const constrainFeatureMovement = (geojsonFeatures: Array, delta: Delta) => { // "inner edge" = a feature's latitude closest to the equator let northInnerEdge = LAT_MIN; let southInnerEdge = LAT_MAX; diff --git a/src/lib/create_supplementary_points.ts b/src/lib/create_supplementary_points.ts index 9448f71f..0ad8c4ba 100644 --- a/src/lib/create_supplementary_points.ts +++ b/src/lib/create_supplementary_points.ts @@ -1,34 +1,44 @@ import { createVertex } from './create_vertex'; import { createMidPoint } from './create_midpoint'; import * as Constants from '../constants'; +import type { Coords, StrictFeature } from '../types/types'; +import type { Map } from 'mapbox-gl'; -function createSupplementaryPoints(geojson, options = {}, basePath = null) { +interface Options { + map?: Map; + midpoints?: boolean; + selectedPaths?: string; +} + +export const createSupplementaryPoints = (geojson: StrictFeature, options: Options = {}, basePath = null) => { const { type, coordinates } = geojson.geometry; - const featureId = geojson.properties && geojson.properties.id; + const featureId = geojson.properties && geojson.properties.id as string; let supplementaryPoints = []; if (type === Constants.geojsonTypes.POINT) { // For points, just create a vertex supplementaryPoints.push( - createVertex(featureId, coordinates, basePath, isSelectedPath(basePath)) + createVertex(featureId, coordinates as [number, number], basePath, isSelectedPath(basePath)) ); } else if (type === Constants.geojsonTypes.POLYGON) { + const lineCoordinates = coordinates as Array; + // Cycle through a Polygon's rings and // process each line - coordinates.forEach((line, lineIndex) => { + lineCoordinates.forEach((line, lineIndex) => { processLine( line, basePath !== null ? `${basePath}.${lineIndex}` : String(lineIndex) ); }); } else if (type === Constants.geojsonTypes.LINE_STRING) { - processLine(coordinates, basePath); + processLine(coordinates as Coords, basePath); } else if (type.indexOf(Constants.geojsonTypes.MULTI_PREFIX) === 0) { processMultiGeometry(); } - function processLine(line, lineBasePath) { + function processLine(line: Coords, lineBasePath?: string) { let firstPointString = ''; let lastVertex = null; line.forEach((point, pointIndex) => { @@ -67,7 +77,7 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { }); } - function isSelectedPath(path) { + function isSelectedPath(path: string) { if (!options.selectedPaths) return false; return options.selectedPaths.indexOf(path) !== -1; } @@ -76,8 +86,9 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { // geometries, and accumulate the supplementary points // for each of those constituents function processMultiGeometry() { + const lineCoordinates = coordinates as Array; const subType = type.replace(Constants.geojsonTypes.MULTI_PREFIX, ''); - coordinates.forEach((subCoordinates, index) => { + lineCoordinates.forEach((subCoordinates, index) => { const subFeature = { type: Constants.geojsonTypes.FEATURE, properties: geojson.properties, @@ -85,7 +96,7 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { type: subType, coordinates: subCoordinates } - }; + } as StrictFeature; supplementaryPoints = supplementaryPoints.concat( createSupplementaryPoints(subFeature, options, index) ); @@ -93,6 +104,4 @@ function createSupplementaryPoints(geojson, options = {}, basePath = null) { } return supplementaryPoints; -} - -export default createSupplementaryPoints; +}; diff --git a/src/lib/index.ts b/src/lib/index.ts index 170567ea..e5de82c8 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,7 +1,7 @@ import * as CommonSelectors from './common_selectors'; -import constrainFeatureMovement from './constrain_feature_movement'; +import { constrainFeatureMovement } from './constrain_feature_movement'; import { createMidPoint } from './create_midpoint'; -import createSupplementaryPoints from './create_supplementary_points'; +import { createSupplementaryPoints } from './create_supplementary_points'; import { createVertex } from './create_vertex'; import { doubleClickZoom } from './double_click_zoom'; import { euclideanDistance } from './euclidean_distance'; diff --git a/src/lib/move_features.ts b/src/lib/move_features.ts index a6b1e1ac..ffe4d9c2 100644 --- a/src/lib/move_features.ts +++ b/src/lib/move_features.ts @@ -1,4 +1,4 @@ -import constrainFeatureMovement from './constrain_feature_movement'; +import { constrainFeatureMovement } from './constrain_feature_movement'; import * as Constants from '../constants'; export default function (features, delta) { diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 523eea8f..0bd45440 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -5,8 +5,8 @@ import { isInactiveFeature, isShiftDown } from '../lib/common_selectors'; -import createSupplementaryPoints from '../lib/create_supplementary_points'; -import constrainFeatureMovement from '../lib/constrain_feature_movement'; +import { createSupplementaryPoints } from '../lib/create_supplementary_points'; +import { constrainFeatureMovement } from '../lib/constrain_feature_movement'; import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; diff --git a/src/modes/simple_select.ts b/src/modes/simple_select.ts index ede18a34..35843024 100644 --- a/src/modes/simple_select.ts +++ b/src/modes/simple_select.ts @@ -1,6 +1,6 @@ import * as CommonSelectors from '../lib/common_selectors'; import mouseEventPoint from '../lib/mouse_event_point'; -import createSupplementaryPoints from '../lib/create_supplementary_points'; +import { createSupplementaryPoints } from '../lib/create_supplementary_points'; import StringSet from '../lib/string_set'; import { doubleClickZoom } from '../lib/double_click_zoom'; import moveFeatures from '../lib/move_features'; diff --git a/test/create_supplementary_points.test.js b/test/create_supplementary_points.test.js index 98cc3a38..37458713 100644 --- a/test/create_supplementary_points.test.js +++ b/test/create_supplementary_points.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import createMap from './utils/create_map.js'; -import createSupplementaryPoints from '../src/lib/create_supplementary_points.js'; +import { createSupplementaryPoints } from '../src/lib/create_supplementary_points.js'; test('createSupplementaryPoints with a point', () => { const point = { From 5b71f7b630dc341c9d595203d29d4b491f82a4d5 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 6 Mar 2025 14:23:46 +0200 Subject: [PATCH 15/59] Simple typings for common selectors --- src/lib/common_selectors.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/lib/common_selectors.ts b/src/lib/common_selectors.ts index 590dac96..9841519b 100644 --- a/src/lib/common_selectors.ts +++ b/src/lib/common_selectors.ts @@ -1,7 +1,9 @@ import * as Constants from '../constants'; +import { MapMouseEvent, MapTouchEvent } from '../types/types'; -export function isOfMetaType(type) { - return function (e) { +type E = MapMouseEvent | MapTouchEvent; + +export function isOfMetaType(type: string) { return function (e: E) { const featureTarget = e.featureTarget; if (!featureTarget) return false; if (!featureTarget.properties) return false; @@ -9,13 +11,13 @@ export function isOfMetaType(type) { }; } -export function isShiftMousedown(e) { +export function isShiftMousedown(e: MapMouseEvent) { if (!e.originalEvent) return false; if (!e.originalEvent.shiftKey) return false; return e.originalEvent.button === 0; } -export function isActiveFeature(e) { +export function isActiveFeature(e: E) { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; return ( @@ -24,7 +26,7 @@ export function isActiveFeature(e) { ); } -export function isInactiveFeature(e) { +export function isInactiveFeature(e: E) { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; return ( @@ -33,34 +35,34 @@ export function isInactiveFeature(e) { ); } -export function noTarget(e) { +export function noTarget(e: E) { return e.featureTarget === undefined; } -export function isFeature(e) { +export function isFeature(e: E) { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; return e.featureTarget.properties.meta === Constants.meta.FEATURE; } -export function isVertex(e) { +export function isVertex(e: E) { const featureTarget = e.featureTarget; if (!featureTarget) return false; if (!featureTarget.properties) return false; return featureTarget.properties.meta === Constants.meta.VERTEX; } -export function isShiftDown(e) { +export function isShiftDown(e: MapMouseEvent) { if (!e.originalEvent) return false; return e.originalEvent.shiftKey === true; } -export function isEscapeKey(e) { - return e.keyCode === 27; +export function isEscapeKey(e: KeyboardEvent) { + return e.key === 'Escape'; } -export function isEnterKey(e) { - return e.keyCode === 13; +export function isEnterKey(e: KeyboardEvent) { + return e.key === 'Enter'; } export function isTrue() { From bf78fe604c354d9da908047f5f989b82ceaf5337 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 6 Mar 2025 16:11:26 +0200 Subject: [PATCH 16/59] More typings --- src/feature_types/feature.ts | 6 +- src/lib/double_click_zoom.ts | 6 +- src/lib/features_at.ts | 14 +-- src/lib/get_features_at_and_set_cursor.ts | 9 +- src/lib/string_set.ts | 110 ++++++++++++---------- src/store.ts | 35 +++++-- src/types/types.ts | 41 +++++--- 7 files changed, 138 insertions(+), 83 deletions(-) diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index 1eaade36..dabc650b 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -1,16 +1,16 @@ import { generateID } from '../lib/id'; import * as Constants from '../constants'; import type { Geometry } from 'geojson'; -import type { StrictFeature, Draw } from '../types/types'; +import type { StrictFeature, CTX } from '../types/types'; class Feature { - protected ctx: Draw; + ctx: CTX; properties: Record; coordinates: any; id: string; type: Geometry['type']; - constructor(ctx: Draw, geojson: StrictFeature) { + constructor(ctx: CTX, geojson: StrictFeature) { this.ctx = ctx; this.properties = geojson.properties || {}; this.coordinates = geojson.geometry.coordinates; diff --git a/src/lib/double_click_zoom.ts b/src/lib/double_click_zoom.ts index 2f167ea4..167ae9d3 100644 --- a/src/lib/double_click_zoom.ts +++ b/src/lib/double_click_zoom.ts @@ -1,7 +1,7 @@ -import type { DrawCTX } from '../types/types'; +import type { ModeCTX } from '../types/types'; export const doubleClickZoom = { - enable: (ctx: DrawCTX) => { + enable: (ctx: ModeCTX) => { setTimeout(() => { // First check we've got a map and some context. if ( @@ -17,7 +17,7 @@ export const doubleClickZoom = { ctx.map.doubleClickZoom.enable(); }, 0); }, - disable: (ctx: DrawCTX) => { + disable: (ctx: ModeCTX) => { setTimeout(() => { if (!ctx.map || !ctx.map.doubleClickZoom) return; // Always disable here, as it's necessary in some cases. diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index 8929b2d0..a77f53a8 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -4,9 +4,9 @@ import * as Constants from '../constants'; import StringSet from './string_set'; import type { BBox } from 'geojson'; -import type { DrawCTX, MapMouseEvent, MapTouchEvent } from '../types/types'; +import type { CTX, DrawStyleLayer, MapMouseEvent, MapTouchEvent } from '../types/types'; -type Event = MapMouseEvent | MapTouchEvent; +type E = MapMouseEvent | MapTouchEvent; const META_TYPES = [ Constants.meta.FEATURE, @@ -14,12 +14,14 @@ const META_TYPES = [ Constants.meta.VERTEX ]; -const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: number) => { +const featuresAt = (event: E, bbox: BBox, ctx: CTX, buffer: number) => { if (ctx.map === null) return []; const box = event ? mapEventToBoundingBox(event, buffer) : bbox; - const queryParams = {}; + const queryParams: { + layers?: Array; + } = {}; if (ctx.options.styles) queryParams.layers = ctx.options.styles @@ -42,11 +44,11 @@ const featuresAt = (event: Event, bbox: BBox, ctx: DrawCTX, buffer: number) => { return sortFeatures(uniqueFeatures); }; -function featuresAtClick(event: Event, bbox: BBox, ctx: DrawCTX) { +function featuresAtClick(event: E, bbox: BBox, ctx: CTX) { return featuresAt(event, bbox, ctx, ctx.options.clickBuffer); } -function featuresAtTouch(event: Event, bbox: BBox, ctx: DrawCTX) { +function featuresAtTouch(event: E, bbox: BBox, ctx: CTX) { return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); } diff --git a/src/lib/get_features_at_and_set_cursor.ts b/src/lib/get_features_at_and_set_cursor.ts index 7869228f..5b4d898d 100644 --- a/src/lib/get_features_at_and_set_cursor.ts +++ b/src/lib/get_features_at_and_set_cursor.ts @@ -1,10 +1,13 @@ import * as featuresAt from './features_at'; import * as Constants from '../constants'; -import type { DrawCTX } from '../types/types'; +import type { CTX, DrawMapClasses } from '../types/types'; +import type { MapMouseEvent, MapTouchEvent } from 'mapbox-gl'; -export const getFeatureAtAndSetCursors = (event: Event, ctx: DrawCTX) => { +type E = MapMouseEvent | MapTouchEvent; + +export const getFeatureAtAndSetCursors = (event: E, ctx: CTX) => { const features = featuresAt.click(event, null, ctx); - const classes = { mouse: Constants.cursors.NONE }; + const classes: DrawMapClasses = { mouse: Constants.cursors.NONE }; if (features[0]) { classes.mouse = diff --git a/src/lib/string_set.ts b/src/lib/string_set.ts index 368c40ea..67a2cd8a 100644 --- a/src/lib/string_set.ts +++ b/src/lib/string_set.ts @@ -1,54 +1,64 @@ -function StringSet(items) { - this._items = {}; - this._nums = {}; - this._length = items ? items.length : 0; - if (!items) return; - for (let i = 0, l = items.length; i < l; i++) { - this.add(items[i]); - if (items[i] === undefined) continue; - if (typeof items[i] === 'string') this._items[items[i]] = i; - else this._nums[items[i]] = i; +class StringSet { + private _items: Record; + private _nums: Record; + private _length: number; + + constructor(items?: (string | number)[]) { + this._items = {}; + this._nums = {}; + this._length = items ? items.length : 0; + + if (!items) return; + + for (let i = 0; i < items.length; i++) { + this.add(items[i]); + if (items[i] === undefined) continue; + if (typeof items[i] === 'string') this._items[items[i]] = i; + else this._nums[items[i]] = i; + } + } + + add(x: string | number): this { + if (this.has(x)) return this; + this._length++; + if (typeof x === 'string') this._items[x] = this._length; + else this._nums[x] = this._length; + return this; + } + + delete(x: string | number): this { + if (!this.has(x)) return this; + this._length--; + delete this._items[x as string]; + delete this._nums[x as number]; + return this; } -} -StringSet.prototype.add = function (x) { - if (this.has(x)) return this; - this._length++; - if (typeof x === 'string') this._items[x] = this._length; - else this._nums[x] = this._length; - return this; -}; - -StringSet.prototype.delete = function (x) { - if (this.has(x) === false) return this; - this._length--; - delete this._items[x]; - delete this._nums[x]; - return this; -}; - -StringSet.prototype.has = function (x) { - if (typeof x !== 'string' && typeof x !== 'number') return false; - return this._items[x] !== undefined || this._nums[x] !== undefined; -}; - -StringSet.prototype.values = function () { - const values = []; - Object.keys(this._items).forEach(k => { - values.push({ k, v: this._items[k] }); - }); - Object.keys(this._nums).forEach(k => { - values.push({ k: JSON.parse(k), v: this._nums[k] }); - }); - - return values.sort((a, b) => a.v - b.v).map(a => a.k); -}; - -StringSet.prototype.clear = function () { - this._length = 0; - this._items = {}; - this._nums = {}; - return this; -}; + has(x: unknown): boolean { + if (typeof x !== 'string' && typeof x !== 'number') return false; + return this._items[x as string] !== undefined || this._nums[x as number] !== undefined; + } + + values(): (string | number)[] { + const values: { k: string | number; v: number }[] = []; + + Object.keys(this._items).forEach(k => { + values.push({ k, v: this._items[k] }); + }); + + Object.keys(this._nums).forEach(k => { + values.push({ k: JSON.parse(k), v: this._nums[+k] }); + }); + + return values.sort((a, b) => a.v - b.v).map(a => a.k); + } + + clear(): this { + this._length = 0; + this._items = {}; + this._nums = {}; + return this; + } +} export default StringSet; diff --git a/src/store.ts b/src/store.ts index 96214f9a..77c9214d 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,7 +2,7 @@ import { toDenseArray } from './lib/to_dense_array'; import StringSet from './lib/string_set'; import render from './render'; import * as Constants from './constants'; -import type { DrawCTX, Feature, FeatureId, Coordinate, StoreOptions } from './types/types'; +import type { CTX, Feature, FeatureId, Coordinate, StoreOptions } from './types/types'; type MapConfig = Record; @@ -19,12 +19,13 @@ export default class Store { private _changedFeatureIds = new StringSet(); private _emitSelectionChange = false; private _mapInitialConfig: MapConfig = {}; - private ctx: DrawCTX; - private isDirty = false; - private sources = { hot: [], cold: [] }; + private ctx: CTX; private renderRequest: number | null = null; - constructor(ctx: DrawCTX) { + sources = { hot: [], cold: [] }; + isDirty = false; + + constructor(ctx: CTX) { this.ctx = ctx; } @@ -187,7 +188,19 @@ export default class Store { return this; }; - isSelected(featureId: string): this { + setSelectedCoordinates(coordinates) { + this._selectedCoordinates = coordinates; + this._emitSelectionChange = true; + return this; + }; + + clearSelectedCoordinates() { + this._selectedCoordinates = []; + this._emitSelectionChange = true; + return this; + }; + + isSelected(featureId: string): boolean { return this._selectedFeatureIds.has(featureId); }; @@ -216,6 +229,16 @@ export default class Store { }); } + getInitialConfigValue(interaction: string) { + if (this._mapInitialConfig[interaction] !== undefined) { + return this._mapInitialConfig[interaction]; + } else { + // This needs to be set to whatever the default is for that interaction + // It seems to be true for all cases currently, so let's send back `true`. + return true; + } + }; + private refreshSelectedCoordinates(options: StoreOptions = {}): void { const newSelectedCoordinates = this._selectedCoordinates.filter(point => this._selectedFeatureIds.has(point.feature_id)); if (this._selectedCoordinates.length !== newSelectedCoordinates.length && !options.silent) { diff --git a/src/types/types.ts b/src/types/types.ts index 05331fb3..c5bc69c7 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -29,12 +29,19 @@ import type { FillLayerSpecification, IControl, LineLayerSpecification, + Layer, Map, MapEvent, MapMouseEvent as MapboxMapMouseEvent, MapTouchEvent as MapboxMapTouchEvent } from 'mapbox-gl'; +export interface DrawStyleLayer + extends Omit { + id: string; + type: string; +} + // Extend Feature to require geometry and properties export interface StrictFeature extends Omit { @@ -102,12 +109,14 @@ interface DrawFeatureBase { toGeoJSON(): GeoJSON; } +export interface DrawMapClasses { + mode?: Constants['modes']; + feature?: Constants['meta']; + mouse?: Constants['cursors']; +} + export interface DrawUI { - queueMapClasses: (options: { - mode: null; - feature: null; - mouse: null; - }) => void; + queueMapClasses: (options: DrawMapClasses) => void; setActiveButton: (id: string) => void; updateMapClasses: () => void; clearMapClasses: () => void; @@ -278,6 +287,7 @@ interface DrawActionableEvent extends DrawEvent { type: 'draw.actionable'; } +// TODO This seems wrong. Remove now? export interface DrawCTX { map: Map; drawConfig: DrawOptions; @@ -383,8 +393,14 @@ interface Modes { direct_select: DrawCustomMode; } +export interface ModeCTX extends DrawCustomMode { + map: Map; + _ctx: CTX; +} + // Convert these to use imports from constants interface Constants { + readonly modes: (typeof modes)[keyof typeof modes]; readonly classes: (typeof classes)[keyof typeof classes]; readonly sources: (typeof sources)[keyof typeof sources]; readonly cursors: (typeof cursors)[keyof typeof cursors]; @@ -582,7 +598,7 @@ export interface DrawOptions { clickBuffer?: number | undefined; touchBuffer?: number | undefined; controls?: DrawControls | undefined; - styles?: object[] | undefined; + styles?: Array | undefined; modes?: { [modeKey: string]: DrawCustomMode } | undefined; defaultMode?: string | undefined; userProperties?: boolean | undefined; @@ -593,7 +609,7 @@ interface DrawEvents { addEventListeners(): void; changeMode(mode: string, modeOptions: {}, eventOptions: {}): void; combineFeatures(): void; - currentModeName(): void; + currentModeName(): string; currentModeRender(geojson: StrictFeature, push: (geojson: StrictFeature) => void): void; fire(eventName: string, eventData: unknown): DrawMode; getMode(): DrawMode; @@ -610,7 +626,12 @@ interface DrawStore { sources: { hot: [], cold: [] - } + }, + getInitialConfigValue(interaction: string): boolean; + featureChanged(id: string, options: { + silent?: boolean; + action?: string; + }): boolean; } interface DrawSetup { @@ -637,9 +658,7 @@ export declare class Draw implements IControl { static modes: Modes; static constants: Constants; static lib: Lib; - modes: DrawModes; - getDefaultPosition: () => ControlPosition; constructor(options?: DrawOptions); add(geojson: Feature | StrictFeatureCollection | Geometry): string[]; @@ -652,9 +671,7 @@ export declare class Draw implements IControl { delete(ids: string | string[]): this; deleteAll(): this; set(featureCollection: StrictFeatureCollection): string[]; - trash(): DrawEvents['trash']; - combineFeatures(): this; uncombineFeatures(): this; getMode(): (Modes & {}) | string; From e1cc5007af350334f77bb88c6258b40f401d8a8b Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 12:37:42 -0400 Subject: [PATCH 17/59] More type safety, nest properties in mode objects --- index.ts | 2 - src/api.ts | 4 +- src/feature_types/feature.ts | 6 +- src/feature_types/line_string.ts | 4 +- src/feature_types/multi_feature.ts | 3 +- src/feature_types/point.ts | 14 +- src/feature_types/polygon.ts | 4 +- src/lib/get_features_at_and_set_cursor.ts | 3 +- src/modes/direct_select.ts | 482 +++++++++++----------- src/modes/draw_line_string.ts | 353 ++++++++-------- src/modes/draw_point.ts | 110 ++--- src/modes/draw_polygon.ts | 326 +++++++-------- src/modes/mode_interface.ts | 210 +++------- src/modes/mode_interface_accessors.ts | 16 +- src/modes/object_to_mode.ts | 6 +- src/options.ts | 59 ++- src/store.ts | 39 +- src/types/types.ts | 106 +++-- 18 files changed, 861 insertions(+), 886 deletions(-) diff --git a/index.ts b/index.ts index 805e2f3a..4740c73a 100644 --- a/index.ts +++ b/index.ts @@ -27,8 +27,6 @@ const setupDraw = (options: DrawOptions, api: Draw) => { }; function MapboxDraw(options: DrawOptions) { - console.log('THIS??', this); - setupDraw(options, this); } diff --git a/src/api.ts b/src/api.ts index e25f7832..18dd63f0 100644 --- a/src/api.ts +++ b/src/api.ts @@ -11,7 +11,7 @@ import LineString from './feature_types/line_string'; import Point from './feature_types/point'; import MultiFeature from './feature_types/multi_feature'; -import type { DrawCTX, Draw } from './types/types'; +import type { CTX, Draw } from './types/types'; const featureTypes = { Polygon, @@ -22,7 +22,7 @@ const featureTypes = { MultiPoint: MultiFeature }; -export default function (ctx: DrawCTX, api: Draw) { +export default function (ctx: CTX, api: Draw) { api.modes = Constants.modes; // API doesn't emit events by default diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index dabc650b..f09cbfc1 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -39,14 +39,14 @@ class Feature { this.properties[property] = value; } - toGeoJSON(): any { + toGeoJSON(): StrictFeature { return { id: this.id, - type: Constants.geojsonTypes.FEATURE, + type: Constants.geojsonTypes.FEATURE as 'Feature', properties: this.properties, geometry: { coordinates: this.getCoordinates(), - type: this.type + type: this.type as 'Point' | 'LineString' | 'Polygon' } }; } diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index 5c83806f..d9118652 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -1,10 +1,10 @@ import Feature from './feature.js'; -import type { StrictFeature, Draw } from '../types/types'; +import type { StrictFeature, CTX } from '../types/types'; type Coordinate = [number, number]; class LineString extends Feature { - constructor(ctx: Draw, geojson: StrictFeature) { + constructor(ctx: CTX, geojson: StrictFeature) { super(ctx, geojson); } diff --git a/src/feature_types/multi_feature.ts b/src/feature_types/multi_feature.ts index 874813b1..61c4c35b 100644 --- a/src/feature_types/multi_feature.ts +++ b/src/feature_types/multi_feature.ts @@ -13,6 +13,7 @@ const models = { }; type FeatureType = MultiPoint | MultiLineString | MultiPolygon; +type FeatureConstructor = new (...args: any[]) => FeatureType; const takeAction = ( features: FeatureType[], @@ -32,7 +33,7 @@ const takeAction = ( }; class MultiFeature extends Feature { - model: FeatureType; + model: FeatureConstructor; features: FeatureType[]; constructor(ctx: any, geojson: any) { diff --git a/src/feature_types/point.ts b/src/feature_types/point.ts index e9d5fae6..a511a956 100644 --- a/src/feature_types/point.ts +++ b/src/feature_types/point.ts @@ -1,14 +1,10 @@ import Feature from './feature.js'; -import type { Draw, StrictFeature } from '../types/types'; - -type Coordinate = [number, number]; +import type { CTX, StrictFeature } from '../types/types'; class Point extends Feature { - coordinates: Coordinate; - - constructor(ctx: Draw, geojson: StrictFeature) { + constructor(ctx: CTX, geojson: StrictFeature) { super(ctx, geojson); - this.coordinates = geojson.geometry.coordinates as Coordinate; + this.coordinates = geojson.geometry.coordinates; } isValid(): boolean { @@ -27,8 +23,8 @@ class Point extends Feature { this.changed(); } - getCoordinate(): Coordinate { - return this.getCoordinates() as Coordinate; + getCoordinate() { + return this.getCoordinates(); } } diff --git a/src/feature_types/polygon.ts b/src/feature_types/polygon.ts index 9e400f21..1f9e35af 100644 --- a/src/feature_types/polygon.ts +++ b/src/feature_types/polygon.ts @@ -1,8 +1,8 @@ import Feature from './feature.js'; -import type { Draw, Coords, StrictFeature } from '../types/types'; +import type { CTX, Coords, StrictFeature } from '../types/types'; class Polygon extends Feature { - constructor(ctx: Draw, geojson: StrictFeature) { + constructor(ctx: CTX, geojson: StrictFeature) { super(ctx, geojson); // Ensure coordinates are properly typed and adjust them. diff --git a/src/lib/get_features_at_and_set_cursor.ts b/src/lib/get_features_at_and_set_cursor.ts index 5b4d898d..96cacf5c 100644 --- a/src/lib/get_features_at_and_set_cursor.ts +++ b/src/lib/get_features_at_and_set_cursor.ts @@ -1,7 +1,6 @@ import * as featuresAt from './features_at'; import * as Constants from '../constants'; -import type { CTX, DrawMapClasses } from '../types/types'; -import type { MapMouseEvent, MapTouchEvent } from 'mapbox-gl'; +import type { CTX, DrawMapClasses, MapMouseEvent, MapTouchEvent } from '../types/types'; type E = MapMouseEvent | MapTouchEvent; diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 0bd45440..7affb1a5 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,279 +11,277 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { DrawCTX, DrawCTXCustomMode } from '../types/types'; -import type { MapMouseEvent } from 'mapbox-gl'; +import type { SelectedDrawModeFeature } from '../types/types'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); -interface DirectSelectMode extends DrawCTXCustomMode { - fireUpdate(): void; - clickInactive(): void; - fireActionable(state: DrawCTX): void; - clickNoTarget(state: DrawCTX, e: MapMouseEvent): void; - startDragging(state: DrawCTX, e: MapMouseEvent): void; +interface State { + featureId: string; + canDragMove: boolean; + dragMoveLocation: null; + dragMoving: boolean; + feature: SelectedDrawModeFeature; + initialDragPanState?: null; + selectedCoordPaths: [][]; } -const DirectSelect: DirectSelectMode = { +const DirectSelect = { clickInactive: function () { this.changeMode(Constants.modes.SIMPLE_SELECT); - } -}; - -// INTERNAL FUNCTIONS - -DirectSelect.fireUpdate = function () { - this.fire(Constants.events.UPDATE, { - action: Constants.updateActions.CHANGE_COORDINATES, - features: this.getSelected().map(f => f.toGeoJSON()) - }); -}; - -DirectSelect.fireActionable = function (state) { - this.setActionableState({ - combineFeatures: false, - uncombineFeatures: false, - trash: state.selectedCoordPaths.length > 0 - }); -}; + }, + + // INTERNAL FUNCTIONS + fireUpdate: function () { + this.fire(Constants.events.UPDATE, { + action: Constants.updateActions.CHANGE_COORDINATES, + features: this.getSelected().map(f => f.toGeoJSON()) + }); + }, + + fireActionable: function (state: State) { + this.setActionableState({ + combineFeatures: false, + uncombineFeatures: false, + trash: state.selectedCoordPaths.length > 0 + }); + }, + + startDragging: function (state: State, e) { + if (state.initialDragPanState == null) { + state.initialDragPanState = this.map.dragPan.isEnabled(); + } -DirectSelect.startDragging = function (state, e) { - if (state.initialDragPanState == null) { - state.initialDragPanState = this.map.dragPan.isEnabled(); - } + this.map.dragPan.disable(); + state.canDragMove = true; + state.dragMoveLocation = e.lngLat; + }, - this.map.dragPan.disable(); - state.canDragMove = true; - state.dragMoveLocation = e.lngLat; -}; + stopDragging: function (state: State) { + if (state.canDragMove && state.initialDragPanState === true) { + this.map.dragPan.enable(); + } -DirectSelect.stopDragging = function (state) { - if (state.canDragMove && state.initialDragPanState === true) { - this.map.dragPan.enable(); - } + state.initialDragPanState = null; + state.dragMoving = false; + state.canDragMove = false; + state.dragMoveLocation = null; + }, + + onVertex: function (state: State, e) { + this.startDragging(state, e); + const about = e.featureTarget.properties; + const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); + if (!isShiftDown(e) && selectedIndex === -1) { + state.selectedCoordPaths = [about.coord_path]; + } else if (isShiftDown(e) && selectedIndex === -1) { + state.selectedCoordPaths.push(about.coord_path); + } - state.initialDragPanState = null; - state.dragMoving = false; - state.canDragMove = false; - state.dragMoveLocation = null; -}; + const selectedCoordinates = this.pathsToCoordinates( + state.featureId, + state.selectedCoordPaths + ); + this.setSelectedCoordinates(selectedCoordinates); + }, -DirectSelect.onVertex = function (state, e) { - this.startDragging(state, e); - const about = e.featureTarget.properties; - const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); - if (!isShiftDown(e) && selectedIndex === -1) { + onMidpoint: function (state: State, e) { + this.startDragging(state, e); + const about = e.featureTarget.properties; + state.feature.addCoordinate(about.coord_path, about.lng, about.lat); + this.fireUpdate(); state.selectedCoordPaths = [about.coord_path]; - } else if (isShiftDown(e) && selectedIndex === -1) { - state.selectedCoordPaths.push(about.coord_path); - } + }, - const selectedCoordinates = this.pathsToCoordinates( - state.featureId, - state.selectedCoordPaths - ); - this.setSelectedCoordinates(selectedCoordinates); -}; + pathsToCoordinates: function (featureId, paths) { + return paths.map(coord_path => ({ feature_id: featureId, coord_path })); + }, -DirectSelect.onMidpoint = function (state, e) { - this.startDragging(state, e); - const about = e.featureTarget.properties; - state.feature.addCoordinate(about.coord_path, about.lng, about.lat); - this.fireUpdate(); - state.selectedCoordPaths = [about.coord_path]; -}; - -DirectSelect.pathsToCoordinates = function (featureId, paths) { - return paths.map(coord_path => ({ feature_id: featureId, coord_path })); -}; + onFeature: function (state: State, e) { + if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); + else this.stopDragging(state); + }, -DirectSelect.onFeature = function (state, e) { - if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); - else this.stopDragging(state); -}; + dragFeature: function (state: State, e, delta) { + moveFeatures(this.getSelected(), delta); + state.dragMoveLocation = e.lngLat; + }, -DirectSelect.dragFeature = function (state, e, delta) { - moveFeatures(this.getSelected(), delta); - state.dragMoveLocation = e.lngLat; -}; - -DirectSelect.dragVertex = function (state, e, delta) { - const selectedCoords = state.selectedCoordPaths.map(coord_path => - state.feature.getCoordinate(coord_path) - ); - const selectedCoordPoints = selectedCoords.map(coords => ({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POINT, - coordinates: coords - } - })); - - const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); - for (let i = 0; i < selectedCoords.length; i++) { - const coord = selectedCoords[i]; - state.feature.updateCoordinate( - state.selectedCoordPaths[i], - coord[0] + constrainedDelta.lng, - coord[1] + constrainedDelta.lat + dragVertex: function (state: State, e, delta) { + const selectedCoords = state.selectedCoordPaths.map(coord_path => + state.feature.getCoordinate(coord_path) ); - } -}; - -DirectSelect.clickNoTarget = function () { - this.changeMode(Constants.modes.SIMPLE_SELECT); -}; - -DirectSelect.clickActiveFeature = function (state) { - state.selectedCoordPaths = []; - this.clearSelectedCoordinates(); - state.feature.changed(); -}; - -// EXTERNAL FUNCTIONS - -DirectSelect.onSetup = function (opts) { - const featureId = opts.featureId; - const feature = this.getFeature(featureId); - - if (!feature) { - throw new Error('You must provide a featureId to enter direct_select mode'); - } - - if (feature.type === Constants.geojsonTypes.POINT) { - throw new TypeError("direct_select mode doesn't handle point features"); - } - - const state = { - featureId, - feature, - dragMoveLocation: opts.startPos || null, - dragMoving: false, - canDragMove: false, - selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] - }; - - this.setSelectedCoordinates( - this.pathsToCoordinates(featureId, state.selectedCoordPaths) - ); - this.setSelected(featureId); - doubleClickZoom.disable(this); - - this.setActionableState({ - trash: true - }); - - return state; -}; - -DirectSelect.onStop = function () { - doubleClickZoom.enable(this); - this.clearSelectedCoordinates(); -}; - -DirectSelect.onTrash = function (state) { - // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them - // in reverse order so that we can remove by index safely. - state.selectedCoordPaths - .sort((a, b) => b.localeCompare(a, 'en', { numeric: true })) - .forEach(id => state.feature.removeCoordinate(id)); - this.fireUpdate(); - state.selectedCoordPaths = []; - this.clearSelectedCoordinates(); - this.fireActionable(state); - if (state.feature.isValid() === false) { - this.deleteFeature([state.featureId]); - this.changeMode(Constants.modes.SIMPLE_SELECT, {}); - } -}; + const selectedCoordPoints = selectedCoords.map(coords => ({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POINT, + coordinates: coords + } + })); + + const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); + for (let i = 0; i < selectedCoords.length; i++) { + const coord = selectedCoords[i]; + state.feature.updateCoordinate( + state.selectedCoordPaths[i], + coord[0] + constrainedDelta.lng, + coord[1] + constrainedDelta.lat + ); + } + }, -DirectSelect.onMouseMove = function (state, e) { - // On mousemove that is not a drag, stop vertex movement. - const isFeature = isActiveFeature(e); - const onVertex = isVertex(e); - const isMidPoint = isMidpoint(e); - const noCoords = state.selectedCoordPaths.length === 0; - if (isFeature && noCoords) - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else if (onVertex && !noCoords) - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else this.updateUIClasses({ mouse: Constants.cursors.NONE }); - - const isDraggableItem = onVertex || isFeature || isMidPoint; - if (isDraggableItem && state.dragMoving) this.fireUpdate(); - - this.stopDragging(state); - - // Skip render - return true; -}; + clickNoTarget: function () { + this.changeMode(Constants.modes.SIMPLE_SELECT); + }, -DirectSelect.onMouseOut = function (state) { - // As soon as you mouse leaves the canvas, update the feature - if (state.dragMoving) this.fireUpdate(); + clickActiveFeature: function (state: State) { + state.selectedCoordPaths = []; + this.clearSelectedCoordinates(); + state.feature.changed(); + }, - // Skip render - return true; -}; + // EXTERNAL FUNCTIONS + onSetup: function (opts) { + const featureId = opts.featureId; + const feature = this.getFeature(featureId); -DirectSelect.onTouchStart = DirectSelect.onMouseDown = function (state, e) { - if (isVertex(e)) return this.onVertex(state, e); - if (isActiveFeature(e)) return this.onFeature(state, e); - if (isMidpoint(e)) return this.onMidpoint(state, e); -}; + if (!feature) { + throw new Error('You must provide a featureId to enter direct_select mode'); + } -DirectSelect.onDrag = function (state, e) { - if (state.canDragMove !== true) return; - state.dragMoving = true; - e.originalEvent.stopPropagation(); + if (feature.type === Constants.geojsonTypes.POINT) { + throw new TypeError("direct_select mode doesn't handle point features"); + } - const delta = { - lng: e.lngLat.lng - state.dragMoveLocation.lng, - lat: e.lngLat.lat - state.dragMoveLocation.lat - }; - if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta); - else this.dragFeature(state, e, delta); + const state = { + featureId, + feature, + dragMoveLocation: opts.startPos || null, + dragMoving: false, + canDragMove: false, + selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] + }; + + this.setSelectedCoordinates( + this.pathsToCoordinates(featureId, state.selectedCoordPaths) + ); + this.setSelected(featureId); + doubleClickZoom.disable(this); - state.dragMoveLocation = e.lngLat; -}; + this.setActionableState({ + trash: true + }); -DirectSelect.onClick = function (state, e) { - if (noTarget(e)) return this.clickNoTarget(state, e); - if (isActiveFeature(e)) return this.clickActiveFeature(state, e); - if (isInactiveFeature(e)) return this.clickInactive(state, e); - this.stopDragging(state); -}; + return state; + }, -DirectSelect.onTap = function (state, e) { - if (noTarget(e)) return this.clickNoTarget(state, e); - if (isActiveFeature(e)) return this.clickActiveFeature(state, e); - if (isInactiveFeature(e)) return this.clickInactive(state, e); -}; + onStop: function () { + doubleClickZoom.enable(this); + this.clearSelectedCoordinates(); + }, -DirectSelect.onTouchEnd = DirectSelect.onMouseUp = function (state) { - if (state.dragMoving) { + onTrash: function (state) { + // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them + // in reverse order so that we can remove by index safely. + state.selectedCoordPaths + .sort((a, b) => b.localeCompare(a, 'en', { numeric: true })) + .forEach(id => state.feature.removeCoordinate(id)); this.fireUpdate(); - } - this.stopDragging(state); -}; + state.selectedCoordPaths = []; + this.clearSelectedCoordinates(); + this.fireActionable(state); + if (state.feature.isValid() === false) { + this.deleteFeature([state.featureId]); + this.changeMode(Constants.modes.SIMPLE_SELECT, {}); + } + }, + + onMouseMove: function (state, e) { + // On mousemove that is not a drag, stop vertex movement. + const isFeature = isActiveFeature(e); + const onVertex = isVertex(e); + const isMidPoint = isMidpoint(e); + const noCoords = state.selectedCoordPaths.length === 0; + if (isFeature && noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else if (onVertex && !noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else this.updateUIClasses({ mouse: Constants.cursors.NONE }); + + const isDraggableItem = onVertex || isFeature || isMidPoint; + if (isDraggableItem && state.dragMoving) this.fireUpdate(); + + this.stopDragging(state); + + // Skip render + return true; + }, + + onMouseOut: function (state) { + // As soon as you mouse leaves the canvas, update the feature + if (state.dragMoving) this.fireUpdate(); + + // Skip render + return true; + }, + + onTouchStart: function (state, e) { + if (isVertex(e)) return this.onVertex(state, e); + if (isActiveFeature(e)) return this.onFeature(state, e); + if (isMidpoint(e)) return this.onMidpoint(state, e); + }, + + onDrag: function (state, e) { + if (state.canDragMove !== true) return; + state.dragMoving = true; + e.originalEvent.stopPropagation(); + + const delta = { + lng: e.lngLat.lng - state.dragMoveLocation.lng, + lat: e.lngLat.lat - state.dragMoveLocation.lat + }; + if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta); + else this.dragFeature(state, e, delta); + + state.dragMoveLocation = e.lngLat; + }, + + _select: function (state, e) { + if (noTarget(e)) return this.clickNoTarget(state, e); + if (isActiveFeature(e)) return this.clickActiveFeature(state, e); + if (isInactiveFeature(e)) return this.clickInactive(state, e); + this.stopDragging(state); + }, + + _end: function (state) { + if (state.dragMoving) { + this.fireUpdate(); + } + this.stopDragging(state); + }, + + toDisplayFeatures: function (state: State, geojson, push) { + if (state.featureId === geojson.properties.id) { + geojson.properties.active = Constants.activeStates.ACTIVE; + push(geojson); + createSupplementaryPoints(geojson, { + map: this.map, + midpoints: true, + selectedPaths: state.selectedCoordPaths + }).forEach(push); + } else { + geojson.properties.active = Constants.activeStates.INACTIVE; + push(geojson); + } + + this.fireActionable(state); + }, -DirectSelect.toDisplayFeatures = function (state: DrawCTX, geojson, push) { - if (state.featureId === geojson.properties.id) { - geojson.properties.active = Constants.activeStates.ACTIVE; - push(geojson); - createSupplementaryPoints(geojson, { - map: this.map, - midpoints: true, - selectedPaths: state.selectedCoordPaths - }).forEach(push); - } else { - geojson.properties.active = Constants.activeStates.INACTIVE; - push(geojson); - } - - this.fireActionable(state); + onTap: function (state, e) { return this._select(state, e); }, + onClick: function (state, e) { return this._select(state, e); }, + onMouseUp: function (state) { return this._end(state); }, + onTouchEnd: function (state) { return this._end(state); } }; export default DirectSelect; diff --git a/src/modes/draw_line_string.ts b/src/modes/draw_line_string.ts index 8ba84fd1..5e8c8e4d 100644 --- a/src/modes/draw_line_string.ts +++ b/src/modes/draw_line_string.ts @@ -4,205 +4,208 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import { createVertex } from '../lib/create_vertex'; -const DrawLineString = {}; - -DrawLineString.onSetup = function (opts) { - opts = opts || {}; - const featureId = opts.featureId; - - let line, currentVertexPosition; - let direction = 'forward'; - if (featureId) { - line = this.getFeature(featureId); - if (!line) { - throw new Error('Could not find a feature with the provided featureId'); - } - let from = opts.from; - if ( - from && - from.type === 'Feature' && - from.geometry && - from.geometry.type === 'Point' - ) { - from = from.geometry; +const DrawLineString = { + onSetup: function (opts) { + opts = opts || {}; + const featureId = opts.featureId; + + let line, currentVertexPosition; + let direction = 'forward'; + if (featureId) { + line = this.getFeature(featureId); + if (!line) { + throw new Error('Could not find a feature with the provided featureId'); + } + let from = opts.from; + if ( + from && + from.type === 'Feature' && + from.geometry && + from.geometry.type === 'Point' + ) { + from = from.geometry; + } + if ( + from && + from.type === 'Point' && + from.coordinates && + from.coordinates.length === 2 + ) { + from = from.coordinates; + } + if (!from || !Array.isArray(from)) { + throw new Error( + 'Please use the `from` property to indicate which point to continue the line from' + ); + } + const lastCoord = line.coordinates.length - 1; + if ( + line.coordinates[lastCoord][0] === from[0] && + line.coordinates[lastCoord][1] === from[1] + ) { + currentVertexPosition = lastCoord + 1; + // add one new coordinate to continue from + line.addCoordinate(currentVertexPosition, ...line.coordinates[lastCoord]); + } else if ( + line.coordinates[0][0] === from[0] && + line.coordinates[0][1] === from[1] + ) { + direction = 'backwards'; + currentVertexPosition = 0; + // add one new coordinate to continue from + line.addCoordinate(currentVertexPosition, ...line.coordinates[0]); + } else { + throw new Error( + '`from` should match the point at either the start or the end of the provided LineString' + ); + } + } else { + line = this.newFeature({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.LINE_STRING, + coordinates: [] + } + }); + currentVertexPosition = 0; + this.addFeature(line); } + + this.clearSelectedFeatures(); + doubleClickZoom.disable(this); + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + this.activateUIButton(Constants.types.LINE); + this.setActionableState({ + trash: true + }); + + return { + line, + currentVertexPosition, + direction + }; + }, + + clickAnywhere: function (state, e) { if ( - from && - from.type === 'Point' && - from.coordinates && - from.coordinates.length === 2 + (state.currentVertexPosition > 0 && + isEventAtCoordinates( + e, + state.line.coordinates[state.currentVertexPosition - 1] + )) || + (state.direction === 'backwards' && + isEventAtCoordinates( + e, + state.line.coordinates[state.currentVertexPosition + 1] + )) ) { - from = from.coordinates; + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.line.id] + }); } - if (!from || !Array.isArray(from)) { - throw new Error( - 'Please use the `from` property to indicate which point to continue the line from' + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + state.line.updateCoordinate( + state.currentVertexPosition, + e.lngLat.lng, + e.lngLat.lat + ); + if (state.direction === 'forward') { + state.currentVertexPosition++; + state.line.updateCoordinate( + state.currentVertexPosition, + e.lngLat.lng, + e.lngLat.lat ); - } - const lastCoord = line.coordinates.length - 1; - if ( - line.coordinates[lastCoord][0] === from[0] && - line.coordinates[lastCoord][1] === from[1] - ) { - currentVertexPosition = lastCoord + 1; - // add one new coordinate to continue from - line.addCoordinate(currentVertexPosition, ...line.coordinates[lastCoord]); - } else if ( - line.coordinates[0][0] === from[0] && - line.coordinates[0][1] === from[1] - ) { - direction = 'backwards'; - currentVertexPosition = 0; - // add one new coordinate to continue from - line.addCoordinate(currentVertexPosition, ...line.coordinates[0]); } else { - throw new Error( - '`from` should match the point at either the start or the end of the provided LineString' - ); + state.line.addCoordinate(0, e.lngLat.lng, e.lngLat.lat); } - } else { - line = this.newFeature({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.LINE_STRING, - coordinates: [] - } - }); - currentVertexPosition = 0; - this.addFeature(line); - } - - this.clearSelectedFeatures(); - doubleClickZoom.disable(this); - this.updateUIClasses({ mouse: Constants.cursors.ADD }); - this.activateUIButton(Constants.types.LINE); - this.setActionableState({ - trash: true - }); - - return { - line, - currentVertexPosition, - direction - }; -}; + }, -DrawLineString.clickAnywhere = function (state, e) { - if ( - (state.currentVertexPosition > 0 && - isEventAtCoordinates( - e, - state.line.coordinates[state.currentVertexPosition - 1] - )) || - (state.direction === 'backwards' && - isEventAtCoordinates( - e, - state.line.coordinates[state.currentVertexPosition + 1] - )) - ) { + clickOnVertex: function (state) { return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.line.id] }); - } - this.updateUIClasses({ mouse: Constants.cursors.ADD }); - state.line.updateCoordinate( - state.currentVertexPosition, - e.lngLat.lng, - e.lngLat.lat - ); - if (state.direction === 'forward') { - state.currentVertexPosition++; + }, + + onMouseMove: function (state, e) { state.line.updateCoordinate( state.currentVertexPosition, e.lngLat.lng, e.lngLat.lat ); - } else { - state.line.addCoordinate(0, e.lngLat.lng, e.lngLat.lat); - } -}; + if (CommonSelectors.isVertex(e)) { + this.updateUIClasses({ mouse: Constants.cursors.POINTER }); + } + }, + + _select: function(state, e) { + if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); + this.clickAnywhere(state, e); + }, + + onKeyUp: function (state, e) { + if (CommonSelectors.isEnterKey(e)) { + this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.line.id] + }); + } else if (CommonSelectors.isEscapeKey(e)) { + this.deleteFeature([state.line.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT); + } + }, -DrawLineString.clickOnVertex = function (state) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: [state.line.id] - }); -}; + onStop: function (state) { + doubleClickZoom.enable(this); + this.activateUIButton(); -DrawLineString.onMouseMove = function (state, e) { - state.line.updateCoordinate( - state.currentVertexPosition, - e.lngLat.lng, - e.lngLat.lat - ); - if (CommonSelectors.isVertex(e)) { - this.updateUIClasses({ mouse: Constants.cursors.POINTER }); - } -}; + // check to see if we've deleted this feature + if (this.getFeature(state.line.id) === undefined) return; -DrawLineString.onTap = DrawLineString.onClick = function (state, e) { - if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); - this.clickAnywhere(state, e); -}; + //remove last added coordinate + state.line.removeCoordinate(`${state.currentVertexPosition}`); + if (state.line.isValid()) { + this.fire(Constants.events.CREATE, { + features: [state.line.toGeoJSON()] + }); + } else { + this.deleteFeature([state.line.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT, {}, { silent: true }); + } + }, -DrawLineString.onKeyUp = function (state, e) { - if (CommonSelectors.isEnterKey(e)) { - this.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: [state.line.id] - }); - } else if (CommonSelectors.isEscapeKey(e)) { + onTrash: function (state) { this.deleteFeature([state.line.id], { silent: true }); this.changeMode(Constants.modes.SIMPLE_SELECT); - } -}; - -DrawLineString.onStop = function (state) { - doubleClickZoom.enable(this); - this.activateUIButton(); - - // check to see if we've deleted this feature - if (this.getFeature(state.line.id) === undefined) return; - - //remove last added coordinate - state.line.removeCoordinate(`${state.currentVertexPosition}`); - if (state.line.isValid()) { - this.fire(Constants.events.CREATE, { - features: [state.line.toGeoJSON()] - }); - } else { - this.deleteFeature([state.line.id], { silent: true }); - this.changeMode(Constants.modes.SIMPLE_SELECT, {}, { silent: true }); - } -}; + }, + + toDisplayFeatures: function (state, geojson, display) { + const isActiveLine = geojson.properties.id === state.line.id; + geojson.properties.active = isActiveLine + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; + if (!isActiveLine) return display(geojson); + // Only render the line if it has at least one real coordinate + if (geojson.geometry.coordinates.length < 2) return; + geojson.properties.meta = Constants.meta.FEATURE; + display( + createVertex( + state.line.id, + geojson.geometry.coordinates[ + state.direction === 'forward' + ? geojson.geometry.coordinates.length - 2 + : 1 + ], + `${state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1}`, + false + ) + ); -DrawLineString.onTrash = function (state) { - this.deleteFeature([state.line.id], { silent: true }); - this.changeMode(Constants.modes.SIMPLE_SELECT); -}; + display(geojson); + }, -DrawLineString.toDisplayFeatures = function (state, geojson, display) { - const isActiveLine = geojson.properties.id === state.line.id; - geojson.properties.active = isActiveLine - ? Constants.activeStates.ACTIVE - : Constants.activeStates.INACTIVE; - if (!isActiveLine) return display(geojson); - // Only render the line if it has at least one real coordinate - if (geojson.geometry.coordinates.length < 2) return; - geojson.properties.meta = Constants.meta.FEATURE; - display( - createVertex( - state.line.id, - geojson.geometry.coordinates[ - state.direction === 'forward' - ? geojson.geometry.coordinates.length - 2 - : 1 - ], - `${state.direction === 'forward' ? geojson.geometry.coordinates.length - 2 : 1}`, - false - ) - ); - - display(geojson); + onTap: function (state, e) { return this._select(state, e); }, + onClick: function (state, e) { return this._select(state, e); }, }; export default DrawLineString; diff --git a/src/modes/draw_point.ts b/src/modes/draw_point.ts index 95af2608..d18aefba 100644 --- a/src/modes/draw_point.ts +++ b/src/modes/draw_point.ts @@ -1,69 +1,71 @@ import * as CommonSelectors from '../lib/common_selectors'; import * as Constants from '../constants'; +import {StrictFeature} from '../types/types'; -const DrawPoint = {}; +const DrawPoint = { + onSetup() { + const point = this.newFeature({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POINT, + coordinates: [] + } + }); -DrawPoint.onSetup = function () { - const point = this.newFeature({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POINT, - coordinates: [] - } - }); - - this.addFeature(point); + this.addFeature(point); + this.clearSelectedFeatures(); + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + this.activateUIButton(Constants.types.POINT); - this.clearSelectedFeatures(); - this.updateUIClasses({ mouse: Constants.cursors.ADD }); - this.activateUIButton(Constants.types.POINT); + this.setActionableState({ + trash: true + }); - this.setActionableState({ - trash: true - }); - - return { point }; -}; + return { point }; + }, -DrawPoint.stopDrawingAndRemove = function (state) { - this.deleteFeature([state.point.id], { silent: true }); - this.changeMode(Constants.modes.SIMPLE_SELECT); -}; + stopDrawingAndRemove(state) { + this.deleteFeature([state.point.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT); + }, -DrawPoint.onTap = DrawPoint.onClick = function (state, e) { - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - state.point.updateCoordinate('', e.lngLat.lng, e.lngLat.lat); - this.fire(Constants.events.CREATE, { - features: [state.point.toGeoJSON()] - }); - this.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: [state.point.id] - }); -}; + _select(state, e) { + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + state.point.updateCoordinate('', e.lngLat.lng, e.lngLat.lat); + this.fire(Constants.events.CREATE, { + features: [state.point.toGeoJSON()] + }); + this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.point.id] + }); + }, -DrawPoint.onStop = function (state) { - this.activateUIButton(); - if (!state.point.getCoordinate().length) { - this.deleteFeature([state.point.id], { silent: true }); - } -}; + onStop(state) { + this.activateUIButton(); + if (!state.point.getCoordinate().length) { + this.deleteFeature([state.point.id], { silent: true }); + } + }, -DrawPoint.toDisplayFeatures = function (state, geojson, display) { - // Never render the point we're drawing - const isActivePoint = geojson.properties.id === state.point.id; - geojson.properties.active = isActivePoint - ? Constants.activeStates.ACTIVE - : Constants.activeStates.INACTIVE; - if (!isActivePoint) return display(geojson); -}; + toDisplayFeatures(state, geojson: StrictFeature, display) { + const isActivePoint = geojson.properties.id === state.point.id; + geojson.properties.active = isActivePoint + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; + if (!isActivePoint) return display(geojson); + }, -DrawPoint.onTrash = DrawPoint.stopDrawingAndRemove; + onKeyUp(state, e) { + if (CommonSelectors.isEscapeKey(e) || CommonSelectors.isEnterKey(e)) { + return this.stopDrawingAndRemove(state, e); + } + }, -DrawPoint.onKeyUp = function (state, e) { - if (CommonSelectors.isEscapeKey(e) || CommonSelectors.isEnterKey(e)) { - return this.stopDrawingAndRemove(state, e); - } + onTap: function (state, e) { return this._select(state, e); }, + onClick: function (state, e) { return this._select(state, e); }, + onTrash: function (state, e) { return this.stopDrawingAndRemove(state, e); } }; export default DrawPoint; + diff --git a/src/modes/draw_polygon.ts b/src/modes/draw_polygon.ts index 37808ab9..b613dff3 100644 --- a/src/modes/draw_polygon.ts +++ b/src/modes/draw_polygon.ts @@ -4,185 +4,187 @@ import * as Constants from '../constants'; import { isEventAtCoordinates } from '../lib/is_event_at_coordinates'; import { createVertex } from '../lib/create_vertex'; -const DrawPolygon = {}; - -DrawPolygon.onSetup = function () { - const polygon = this.newFeature({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POLYGON, - coordinates: [[]] - } - }); - - this.addFeature(polygon); - - this.clearSelectedFeatures(); - doubleClickZoom.disable(this); - this.updateUIClasses({ mouse: Constants.cursors.ADD }); - this.activateUIButton(Constants.types.POLYGON); - this.setActionableState({ - trash: true - }); - - return { - polygon, - currentVertexPosition: 0 - }; -}; - -DrawPolygon.clickAnywhere = function (state, e) { - if ( - state.currentVertexPosition > 0 && - isEventAtCoordinates( - e, - state.polygon.coordinates[0][state.currentVertexPosition - 1] - ) - ) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: [state.polygon.id] +const DrawPolygon = { + onSetup: function () { + const polygon = this.newFeature({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POLYGON, + coordinates: [[]] + } }); - } - this.updateUIClasses({ mouse: Constants.cursors.ADD }); - state.polygon.updateCoordinate( - `0.${state.currentVertexPosition}`, - e.lngLat.lng, - e.lngLat.lat - ); - state.currentVertexPosition++; - state.polygon.updateCoordinate( - `0.${state.currentVertexPosition}`, - e.lngLat.lng, - e.lngLat.lat - ); -}; -DrawPolygon.clickOnVertex = function (state) { - return this.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: [state.polygon.id] - }); -}; + this.addFeature(polygon); -DrawPolygon.onMouseMove = function (state, e) { - state.polygon.updateCoordinate( - `0.${state.currentVertexPosition}`, - e.lngLat.lng, - e.lngLat.lat - ); - if (CommonSelectors.isVertex(e)) { - this.updateUIClasses({ mouse: Constants.cursors.POINTER }); - } -}; - -DrawPolygon.onTap = DrawPolygon.onClick = function (state, e) { - if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); - return this.clickAnywhere(state, e); -}; - -DrawPolygon.onKeyUp = function (state, e) { - if (CommonSelectors.isEscapeKey(e)) { - this.deleteFeature([state.polygon.id], { silent: true }); - this.changeMode(Constants.modes.SIMPLE_SELECT); - } else if (CommonSelectors.isEnterKey(e)) { - this.changeMode(Constants.modes.SIMPLE_SELECT, { - featureIds: [state.polygon.id] + this.clearSelectedFeatures(); + doubleClickZoom.disable(this); + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + this.activateUIButton(Constants.types.POLYGON); + this.setActionableState({ + trash: true }); - } -}; - -DrawPolygon.onStop = function (state) { - this.updateUIClasses({ mouse: Constants.cursors.NONE }); - doubleClickZoom.enable(this); - this.activateUIButton(); - // check to see if we've deleted this feature - if (this.getFeature(state.polygon.id) === undefined) return; + return { + polygon, + currentVertexPosition: 0 + }; + }, + + clickAnywhere: function (state, e) { + if ( + state.currentVertexPosition > 0 && + isEventAtCoordinates( + e, + state.polygon.coordinates[0][state.currentVertexPosition - 1] + ) + ) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.polygon.id] + }); + } + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + state.polygon.updateCoordinate( + `0.${state.currentVertexPosition}`, + e.lngLat.lng, + e.lngLat.lat + ); + state.currentVertexPosition++; + state.polygon.updateCoordinate( + `0.${state.currentVertexPosition}`, + e.lngLat.lng, + e.lngLat.lat + ); + }, - //remove last added coordinate - state.polygon.removeCoordinate(`0.${state.currentVertexPosition}`); - if (state.polygon.isValid()) { - this.fire(Constants.events.CREATE, { - features: [state.polygon.toGeoJSON()] + clickOnVertex: function (state) { + return this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.polygon.id] }); - } else { - this.deleteFeature([state.polygon.id], { silent: true }); - this.changeMode(Constants.modes.SIMPLE_SELECT, {}, { silent: true }); - } -}; + }, -DrawPolygon.toDisplayFeatures = function (state, geojson, display) { - const isActivePolygon = geojson.properties.id === state.polygon.id; - geojson.properties.active = isActivePolygon - ? Constants.activeStates.ACTIVE - : Constants.activeStates.INACTIVE; - if (!isActivePolygon) return display(geojson); - - // Don't render a polygon until it has two positions - // (and a 3rd which is just the first repeated) - if (geojson.geometry.coordinates.length === 0) return; - - const coordinateCount = geojson.geometry.coordinates[0].length; - // 2 coordinates after selecting a draw type - // 3 after creating the first point - if (coordinateCount < 3) { - return; - } - geojson.properties.meta = Constants.meta.FEATURE; - display( - createVertex( - state.polygon.id, - geojson.geometry.coordinates[0][0], - '0.0', - false - ) - ); - if (coordinateCount > 3) { - // Add a start position marker to the map, clicking on this will finish the feature - // This should only be shown when we're in a valid spot - const endPos = geojson.geometry.coordinates[0].length - 3; + onMouseMove: function (state, e) { + state.polygon.updateCoordinate( + `0.${state.currentVertexPosition}`, + e.lngLat.lng, + e.lngLat.lat + ); + if (CommonSelectors.isVertex(e)) { + this.updateUIClasses({ mouse: Constants.cursors.POINTER }); + } + }, + + _select: function (state, e) { + if (CommonSelectors.isVertex(e)) return this.clickOnVertex(state, e); + return this.clickAnywhere(state, e); + }, + + onKeyUp: function (state, e) { + if (CommonSelectors.isEscapeKey(e)) { + this.deleteFeature([state.polygon.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT); + } else if (CommonSelectors.isEnterKey(e)) { + this.changeMode(Constants.modes.SIMPLE_SELECT, { + featureIds: [state.polygon.id] + }); + } + }, + + onStop: function (state) { + this.updateUIClasses({ mouse: Constants.cursors.NONE }); + doubleClickZoom.enable(this); + this.activateUIButton(); + + // check to see if we've deleted this feature + if (this.getFeature(state.polygon.id) === undefined) return; + + //remove last added coordinate + state.polygon.removeCoordinate(`0.${state.currentVertexPosition}`); + if (state.polygon.isValid()) { + this.fire(Constants.events.CREATE, { + features: [state.polygon.toGeoJSON()] + }); + } else { + this.deleteFeature([state.polygon.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT, {}, { silent: true }); + } + }, + + toDisplayFeatures: function (state, geojson, display) { + const isActivePolygon = geojson.properties.id === state.polygon.id; + geojson.properties.active = isActivePolygon + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; + if (!isActivePolygon) return display(geojson); + + // Don't render a polygon until it has two positions + // (and a 3rd which is just the first repeated) + if (geojson.geometry.coordinates.length === 0) return; + + const coordinateCount = geojson.geometry.coordinates[0].length; + // 2 coordinates after selecting a draw type + // 3 after creating the first point + if (coordinateCount < 3) { + return; + } + geojson.properties.meta = Constants.meta.FEATURE; display( createVertex( state.polygon.id, - geojson.geometry.coordinates[0][endPos], - `0.${endPos}`, + geojson.geometry.coordinates[0][0], + '0.0', false ) ); - } - if (coordinateCount <= 4) { - // If we've only drawn two positions (plus the closer), - // make a LineString instead of a Polygon - const lineCoordinates = [ - [ - geojson.geometry.coordinates[0][0][0], - geojson.geometry.coordinates[0][0][1] - ], - [ - geojson.geometry.coordinates[0][1][0], - geojson.geometry.coordinates[0][1][1] - ] - ]; - // create an initial vertex so that we can track the first point on mobile devices - display({ - type: Constants.geojsonTypes.FEATURE, - properties: geojson.properties, - geometry: { - coordinates: lineCoordinates, - type: Constants.geojsonTypes.LINE_STRING + if (coordinateCount > 3) { + // Add a start position marker to the map, clicking on this will finish the feature + // This should only be shown when we're in a valid spot + const endPos = geojson.geometry.coordinates[0].length - 3; + display( + createVertex( + state.polygon.id, + geojson.geometry.coordinates[0][endPos], + `0.${endPos}`, + false + ) + ); + } + if (coordinateCount <= 4) { + // If we've only drawn two positions (plus the closer), + // make a LineString instead of a Polygon + const lineCoordinates = [ + [ + geojson.geometry.coordinates[0][0][0], + geojson.geometry.coordinates[0][0][1] + ], + [ + geojson.geometry.coordinates[0][1][0], + geojson.geometry.coordinates[0][1][1] + ] + ]; + // create an initial vertex so that we can track the first point on mobile devices + display({ + type: Constants.geojsonTypes.FEATURE, + properties: geojson.properties, + geometry: { + coordinates: lineCoordinates, + type: Constants.geojsonTypes.LINE_STRING + } + }); + if (coordinateCount === 3) { + return; } - }); - if (coordinateCount === 3) { - return; } - } - // render the Polygon - return display(geojson); -}; + // render the Polygon + return display(geojson); + }, -DrawPolygon.onTrash = function (state) { - this.deleteFeature([state.polygon.id], { silent: true }); - this.changeMode(Constants.modes.SIMPLE_SELECT); + onTap: function (state, e) { return this._select(state, e); }, + onClick: function (state, e) { return this._select(state, e); }, + onTrash: function (state) { + this.deleteFeature([state.polygon.id], { silent: true }); + this.changeMode(Constants.modes.SIMPLE_SELECT); + } }; export default DrawPolygon; diff --git a/src/modes/mode_interface.ts b/src/modes/mode_interface.ts index e4a7974e..492b9574 100644 --- a/src/modes/mode_interface.ts +++ b/src/modes/mode_interface.ts @@ -1,146 +1,64 @@ -import ModeInterface from './mode_interface_accessors.js'; -export default ModeInterface; - -/** - * Triggered while a mode is being transitioned into. - * @param opts {Object} - this is the object passed via `draw.changeMode('mode', opts)`; - * @name MODE.onSetup - * @returns {Object} - this object will be passed to all other life cycle functions - */ -ModeInterface.prototype.onSetup = function () {}; - -/** - * Triggered when a drag event is detected on the map - * @name MODE.onDrag - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onDrag = function () {}; - -/** - * Triggered when the mouse is clicked - * @name MODE.onClick - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onClick = function () {}; - -/** - * Triggered with the mouse is moved - * @name MODE.onMouseMove - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onMouseMove = function () {}; - -/** - * Triggered when the mouse button is pressed down - * @name MODE.onMouseDown - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onMouseDown = function () {}; - -/** - * Triggered when the mouse button is released - * @name MODE.onMouseUp - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onMouseUp = function () {}; - -/** - * Triggered when the mouse leaves the map's container - * @name MODE.onMouseOut - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onMouseOut = function () {}; - -/** - * Triggered when a key up event is detected - * @name MODE.onKeyUp - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onKeyUp = function () {}; - -/** - * Triggered when a key down event is detected - * @name MODE.onKeyDown - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onKeyDown = function () {}; - -/** - * Triggered when a touch event is started - * @name MODE.onTouchStart - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onTouchStart = function () {}; - -/** - * Triggered when one drags thier finger on a mobile device - * @name MODE.onTouchMove - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onTouchMove = function () {}; - -/** - * Triggered when one removes their finger from the map - * @name MODE.onTouchEnd - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onTouchEnd = function () {}; - -/** - * Triggered when one quicly taps the map - * @name MODE.onTap - * @param state {Object} - a mutible state object created by onSetup - * @param e {Object} - the captured event that is triggering this life cycle event - */ -ModeInterface.prototype.onTap = function () {}; - -/** - * Triggered when the mode is being exited, to be used for cleaning up artifacts such as invalid features - * @name MODE.onStop - * @param state {Object} - a mutible state object created by onSetup - */ -ModeInterface.prototype.onStop = function () {}; - -/** - * Triggered when [draw.trash()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#trash-draw) is called. - * @name MODE.onTrash - * @param state {Object} - a mutible state object created by onSetup - */ -ModeInterface.prototype.onTrash = function () {}; - -/** - * Triggered when [draw.combineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#combinefeatures-draw) is called. - * @name MODE.onCombineFeature - * @param state {Object} - a mutible state object created by onSetup - */ -ModeInterface.prototype.onCombineFeature = function () {}; - -/** - * Triggered when [draw.uncombineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#uncombinefeatures-draw) is called. - * @name MODE.onUncombineFeature - * @param state {Object} - a mutible state object created by onSetup - */ -ModeInterface.prototype.onUncombineFeature = function () {}; - -/** - * Triggered per feature on render to convert raw features into set of features for display on the map - * See [styling draw](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#styling-draw) for information about what geojson properties Draw uses as part of rendering. - * @name MODE.toDisplayFeatures - * @param state {Object} - a mutible state object created by onSetup - * @param geojson {Object} - a geojson being evaulated. To render, pass to `display`. - * @param display {Function} - all geojson objects passed to this be rendered onto the map - */ -ModeInterface.prototype.toDisplayFeatures = function () { - throw new Error('You must overwrite toDisplayFeatures'); -}; +import ModeInterfaceAcessors from './mode_interface_accessors.js'; +import type { DrawCustomMode } from '../types/types'; + +class ModeInterface extends ModeInterfaceAcessors { + // Triggered while a mode is being transitioned into. + onSetup = function () {}; + + // Triggered when a drag event is detected on the map + onDrag = function () {}; + + // Triggered when the mouse is clicked + onClick = function () {}; + + // Triggered with the mouse is moved + onMouseMove = function () {}; + + // Triggered when the mouse button is pressed down + onMouseDown = function () {}; + + // Triggered when the mouse button is released + onMouseUp = function () {}; + + // Triggered when the mouse leaves the map's container + onMouseOut = function () {}; + + // Triggered when a key up event is detected + onKeyUp = function () {}; + + // Triggered when a key down event is detected + onKeyDown = function () {}; + + // Triggered when a touch event is started + onTouchStart = function () {}; + + // Triggered when one drags thier finger on a mobile device + onTouchMove = function () {}; + + // Triggered when one removes their finger from the map + onTouchEnd = function () {}; + + // Triggered when one quicly taps the map + onTap = function () {}; + + // Triggered when the mode is being exited, to be used for cleaning up artifacts such as invalid features + onStop = function () {}; + + // Triggered when [draw.trash()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#trash-draw) is called. + onTrash = function () {}; + + // Triggered when [draw.combineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#combinefeatures-draw) is called. + onCombineFeature = function () {}; + + // Triggered when [draw.uncombineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#uncombinefeatures-draw) is called. + onUncombineFeature = function () {}; + + // Triggered per feature on render to convert raw features into set of features for display on the map + // See [styling draw](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#styling-draw) for information about what geojson properties Draw uses as part of rendering. + toDisplayFeatures = function () { + throw new Error('You must overwrite toDisplayFeatures'); + }; + +} + +export default ModeInterface as unknown as DrawCustomMode; diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index 48875a8e..e6724b5b 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -4,8 +4,8 @@ import Point from '../feature_types/point'; import LineString from '../feature_types/line_string'; import Polygon from '../feature_types/polygon'; import MultiFeature from '../feature_types/multi_feature'; -import type { DrawCTX } from '../types/types'; -import type { Feature as GeoJSONFeature } from 'geojson'; +import type { CTX, DrawOptions, StrictFeature } from '../types/types'; +import type { Map } from 'mapbox-gl'; type DrawFeature = Point | LineString | Polygon | MultiFeature; @@ -21,13 +21,11 @@ interface DrawActions { } export default class ModeInterface { - private map: any; - private drawConfig: any; - private _ctx: DrawCTX; - - constructor(ctx: DrawCTX) { - console.log('CTX', ctx); + map: Map; + drawConfig: DrawOptions; + private _ctx: CTX; + constructor(ctx: CTX) { this.map = ctx.map; this.drawConfig = { ...ctx.options }; this._ctx = ctx; @@ -134,7 +132,7 @@ export default class ModeInterface { return featuresAt[bufferType](event, bbox, this._ctx); } - newFeature(geojson: GeoJSONFeature): DrawFeature { + newFeature(geojson: StrictFeature): DrawFeature { const type = geojson.geometry.type; if (type === Constants.geojsonTypes.POINT) return new Point(this._ctx, geojson); diff --git a/src/modes/object_to_mode.ts b/src/modes/object_to_mode.ts index 660abb5a..2466402b 100644 --- a/src/modes/object_to_mode.ts +++ b/src/modes/object_to_mode.ts @@ -1,5 +1,5 @@ import ModeInterface from './mode_interface.js'; -import type { DrawCTX } from '../types/types'; +import type { CTX, DrawCustomMode } from '../types/types'; import type { FeatureCollection } from 'geojson'; const eventMapper = { @@ -19,10 +19,10 @@ const eventMapper = { const eventKeys = Object.keys(eventMapper); -export const objectToMode = modeObject => { +export const objectToMode = (modeObject: DrawCustomMode) => { const modeObjectKeys = Object.keys(modeObject); - return function (ctx: DrawCTX, startOpts = {}) { + return function (ctx: CTX, startOpts = {}) { let state = {}; const mode = modeObjectKeys.reduce((m, k) => { diff --git a/src/options.ts b/src/options.ts index 01c6fd55..4bba0e61 100644 --- a/src/options.ts +++ b/src/options.ts @@ -2,7 +2,32 @@ import * as Constants from './constants'; import * as modes from './modes/index'; import styles from './lib/theme'; -const defaultOptions = { +type Controls = { + point: boolean; + line_string: boolean; + polygon: boolean; + trash: boolean; + combine_features: boolean; + uncombine_features: boolean; + [key: string]: boolean; +}; + +type Options = { + defaultMode?: string; + keybindings?: boolean; + touchEnabled?: boolean; + clickBuffer?: number; + touchBuffer?: number; + boxSelect?: boolean; + displayControlsDefault?: boolean; + styles?: any[]; + modes?: typeof modes; + controls?: Partial; + userProperties?: boolean; + suppressAPIEvents?: boolean; +}; + +const defaultOptions: Options = { defaultMode: Constants.modes.SIMPLE_SELECT, keybindings: true, touchEnabled: true, @@ -17,7 +42,7 @@ const defaultOptions = { suppressAPIEvents: true }; -const showControls = { +const showControls: Controls = { point: true, line_string: true, polygon: true, @@ -26,7 +51,7 @@ const showControls = { uncombine_features: true }; -const hideControls = { +const hideControls: Controls = { point: false, line_string: false, polygon: false, @@ -35,36 +60,34 @@ const hideControls = { uncombine_features: false }; -function addSources(styles, sourceBucket) { +function addSources(styles: any[], sourceBucket: 'hot' | 'cold'): any[] { return styles.map(style => { if (style.source) return style; - return Object.assign({}, style, { + return { + ...style, id: `${style.id}.${sourceBucket}`, - source: - sourceBucket === 'hot' ? Constants.sources.HOT : Constants.sources.COLD - }); + source: sourceBucket === 'hot' ? Constants.sources.HOT : Constants.sources.COLD + }; }); } -export default function (options = {}) { +export default function configureOptions(options: Options = {}): Options { let withDefaults = { ...options }; if (!options.controls) { withDefaults.controls = {}; } - if (options.displayControlsDefault === false) { - withDefaults.controls = { ...hideControls, ...options.controls }; - } else { - withDefaults.controls = { ...showControls, ...options.controls }; - } + withDefaults.controls = options.displayControlsDefault === false + ? { ...hideControls, ...options.controls } + : { ...showControls, ...options.controls }; - withDefaults = Object.assign({}, defaultOptions, withDefaults); + withDefaults = { ...defaultOptions, ...withDefaults }; - // Layers with a shared source should be adjacent for performance reasons - withDefaults.styles = addSources(withDefaults.styles, 'cold').concat( - addSources(withDefaults.styles, 'hot') + withDefaults.styles = addSources(withDefaults.styles || [], 'cold').concat( + addSources(withDefaults.styles || [], 'hot') ); return withDefaults; } + diff --git a/src/store.ts b/src/store.ts index 77c9214d..32308e68 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,20 +2,15 @@ import { toDenseArray } from './lib/to_dense_array'; import StringSet from './lib/string_set'; import render from './render'; import * as Constants from './constants'; -import type { CTX, Feature, FeatureId, Coordinate, StoreOptions } from './types/types'; +import type { CTX, StrictFeature, Coords, DrawStoreOptions } from './types/types'; type MapConfig = Record; -type FeaturePropertyOptions = { - silent?: boolean; - action?: string; -}; - export default class Store { - private _features: Record = {}; + private _features: Record = {}; private _featureIds = new StringSet(); private _selectedFeatureIds = new StringSet(); - private _selectedCoordinates: Coordinate[] = []; + private _selectedCoordinates: Coords[] = []; private _changedFeatureIds = new StringSet(); private _emitSelectionChange = false; private _mapInitialConfig: MapConfig = {}; @@ -71,7 +66,7 @@ export default class Store { return this; } - featureCreated(featureId: FeatureId, options: StoreOptions = {}): this { + featureCreated(featureId: string, options: DrawStoreOptions = {}): this { this._changedFeatureIds.add(featureId); if (!options.silent) { const feature = this.get(featureId); @@ -80,7 +75,7 @@ export default class Store { return this; } - featureChanged(featureId: FeatureId, options: FeaturePropertyOptions = {}): this { + featureChanged(featureId: string, options: DrawStoreOptions = {}): this { this._changedFeatureIds.add(featureId); if (!options.silent) { this.ctx.events.fire(Constants.events.UPDATE, { @@ -104,15 +99,15 @@ export default class Store { return this._featureIds.values(); } - add(feature: Feature, options: StoreOptions = {}): this { + add(feature: StrictFeature, options: DrawStoreOptions = {}): this { this._features[feature.id] = feature; this._featureIds.add(feature.id); this.featureCreated(feature.id, { silent: options.silent }); return this; } - delete(featureIds: FeatureId | FeatureId[], options: StoreOptions = {}): this { - const deletedFeatures: Feature[] = []; + delete(featureIds: string | string[], options: DrawStoreOptions = {}): this { + const deletedFeatures: StrictFeature[] = []; toDenseArray(featureIds).forEach(id => { if (!this._featureIds.has(id)) return; this._featureIds.delete(id); @@ -132,11 +127,11 @@ export default class Store { return this; } - get(id: FeatureId): Feature { + get(id: string): StrictFeature { return this._features[id]; } - getAll(): Feature[] { + getAll(): StrictFeature[] { return Object.values(this._features); } @@ -144,18 +139,18 @@ export default class Store { return this._selectedFeatureIds.values(); } - getSelected(): Feature[] { + getSelected(): StrictFeature[] { return this.getSelectedIds().map(id => this.get(id)); } - getSelectedCoordinates(): Coordinate[] { + getSelectedCoordinates(): Coords[] { return this._selectedCoordinates.map(coordinate => { const feature = this.get(coordinate.feature_id); return { coordinates: feature.getCoordinate(coordinate.coord_path) }; }); } - select(featureIds: FeatureId[], options: StoreOptions = {}): this { + select(featureIds: string[], options: DrawStoreOptions = {}): this { toDenseArray(featureIds).forEach(id => { if (this._selectedFeatureIds.has(id)) return; this._selectedFeatureIds.add(id); @@ -165,7 +160,7 @@ export default class Store { return this; } - deselect(featureIds: FeatureId[], options: StoreOptions = {}): this { + deselect(featureIds: string[], options: DrawStoreOptions = {}): this { toDenseArray(featureIds).forEach(id => { if (!this._selectedFeatureIds.has(id)) return; this._selectedFeatureIds.delete(id); @@ -176,7 +171,7 @@ export default class Store { return this; } - setSelected(featureIds: FeatureId[], options: StoreOptions = {}): this { + setSelected(featureIds: string[], options: DrawStoreOptions = {}): this { featureIds = toDenseArray(featureIds); // Deselect any features not in the new selection @@ -204,7 +199,7 @@ export default class Store { return this._selectedFeatureIds.has(featureId); }; - clearSelected(options: StoreOptions = {}): this { + clearSelected(options: DrawStoreOptions = {}): this { this.deselect(this._selectedFeatureIds.values(), { silent: options.silent }); return this; }; @@ -239,7 +234,7 @@ export default class Store { } }; - private refreshSelectedCoordinates(options: StoreOptions = {}): void { + private refreshSelectedCoordinates(options: DrawStoreOptions = {}): void { const newSelectedCoordinates = this._selectedCoordinates.filter(point => this._selectedFeatureIds.has(point.feature_id)); if (this._selectedCoordinates.length !== newSelectedCoordinates.length && !options.silent) { this._emitSelectionChange = true; diff --git a/src/types/types.ts b/src/types/types.ts index c5bc69c7..753810c4 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,4 +1,4 @@ -import { +import type { BBox, Feature, FeatureCollection, @@ -55,7 +55,6 @@ export interface StrictFeatureCollection features: StrictFeature[]; } -// Example usage export type XY = { x: number; y: number }; export type Coords = Array<[number, number]>; @@ -73,6 +72,14 @@ interface Modes { direct_select: DrawCustomMode; } +export interface SelectedDrawModeFeature { + id: string; + type: string; + ctx: CTX; + properties: Record + coordinates: Array<[number, number]> +} + interface DrawPoint extends DrawFeatureBase { readonly type: 'Point'; getCoordinate(): Position; @@ -287,8 +294,7 @@ interface DrawActionableEvent extends DrawEvent { type: 'draw.actionable'; } -// TODO This seems wrong. Remove now? -export interface DrawCTX { +export interface DrawCustomModeThis { map: Map; drawConfig: DrawOptions; setSelected(features?: string | string[]): void; @@ -319,66 +325,66 @@ export interface DrawCTX { doRender(id: string): void; } -interface DrawCustomMode { - onSetup?(this: DrawCTX & this, options: CustomModeOptions): CustomModeState; - onDrag?(this: DrawCTX & this, state: CustomModeState, e: MapMouseEvent): void; +export interface DrawCustomMode { + onSetup?(this: DrawCustomModeThis & this, options: CustomModeOptions): CustomModeState; + onDrag?(this: DrawCustomModeThis & this, state: CustomModeState, e: MapMouseEvent): void; onClick?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapMouseEvent ): void; onMouseMove?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapMouseEvent ): void; onMouseDown?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapMouseEvent ): void; onMouseUp?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapMouseEvent ): void; onMouseOut?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapMouseEvent ): void; onKeyUp?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: KeyboardEvent ): void; onKeyDown?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: KeyboardEvent ): void; onTouchStart?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapTouchEvent ): void; onTouchMove?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapTouchEvent ): void; onTouchEnd?( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, e: MapTouchEvent ): void; - onTap?(this: DrawCTX & this, state: CustomModeState, e: MapTouchEvent): void; - onStop?(this: DrawCTX & this, state: CustomModeState): void; - onTrash?(this: DrawCTX & this, state: CustomModeState): void; - onCombineFeature?(this: DrawCTX & this, state: CustomModeState): void; - onUncombineFeature?(this: DrawCTX & this, state: CustomModeState): void; + onTap?(this: DrawCustomModeThis & this, state: CustomModeState, e: MapTouchEvent): void; + onStop?(this: DrawCustomModeThis & this, state: CustomModeState): void; + onTrash?(this: DrawCustomModeThis & this, state: CustomModeState): void; + onCombineFeature?(this: DrawCustomModeThis & this, state: CustomModeState): void; + onUncombineFeature?(this: DrawCustomModeThis & this, state: CustomModeState): void; toDisplayFeatures( - this: DrawCTX & this, + this: DrawCustomModeThis & this, state: CustomModeState, geojson: GeoJSON, display: (geojson: GeoJSON) => void @@ -469,16 +475,16 @@ export interface Lib { ): Feature; doubleClickZoom: { - enable: (ctx: DrawCTX) => void; // ?? ctx - disable: (ctx: DrawCTX) => void; // ?? ctx + enable: (ctx: DrawCustomModeThis) => void; // ?? ctx + disable: (ctx: DrawCustomModeThis) => void; // ?? ctx }; featuresAt: { - click: (event: MapMouseEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx - touch: (event: MapTouchEvent, bbox: BBox, ctx: DrawCTX) => Feature[]; // ?? ctx + click: (event: MapMouseEvent, bbox: BBox, ctx: DrawCustomModeThis) => Feature[]; // ?? ctx + touch: (event: MapTouchEvent, bbox: BBox, ctx: DrawCustomModeThis) => Feature[]; // ?? ctx }; - getFeatureAtAndSetCursors(event: MapMouseEvent, ctx: DrawCTX): Feature; + getFeatureAtAndSetCursors(event: MapMouseEvent, ctx: DrawCustomModeThis): Feature; euclideanDistance( a: { x: number; y: number }, @@ -602,6 +608,7 @@ export interface DrawOptions { modes?: { [modeKey: string]: DrawCustomMode } | undefined; defaultMode?: string | undefined; userProperties?: boolean | undefined; + suppressAPIEvents?: boolean | undefined; } interface DrawEvents { @@ -619,6 +626,11 @@ interface DrawEvents { uncombineFeatures(): void; } +export interface DrawStoreOptions { + silent?: boolean; + action?: string; +} + interface DrawStore { ctx: CTX; isDirty: boolean; @@ -628,10 +640,40 @@ interface DrawStore { cold: [] }, getInitialConfigValue(interaction: string): boolean; - featureChanged(id: string, options: { - silent?: boolean; - action?: string; - }): boolean; + featureChanged(id: string, options?: DrawStoreOptions): boolean; + setSelected(features?: string | string[]): void; + setSelectedCoordinates( + coords: Array<{ coord_path: string; feature_id: string }> + ): void; + + getSelected(): DrawFeature[]; + getSelectedIds(): string[]; + isSelected(id: string): boolean; + get(id: string): DrawFeature; + getFeature(id: string): DrawFeature; + select(id: string): void; + deselect(features: string | string[]): void; + delete(id: string): void; + deleteFeature(id: string, opts?: any): void; + add(featureId: string): void; + addFeature(feature: DrawFeature): void; + clearSelected(): void; + clearSelectedFeatures(): void; + clearSelectedCoordinates(): void; + setActionableState(actionableState: DrawActionableState): void; + changeMode(mode: DrawMode, opts?: object, eventOpts?: object): void; + updateUIClasses(opts: object): void; + activateUIButton(name?: string): void; + featuresAt( + event: Event, + bbox: BBox, + bufferType: 'click' | 'tap' + ): DrawFeature[]; + newFeature(geojson: GeoJSON): DrawFeature; + isInstanceOf(type: string, feature: object): boolean; + doRender(id: string): void; + getAllIds(): Array + createRenderBatch(): () => void; } interface DrawSetup { From c865b76c82b84357b8395754e410a9a9789a19f5 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 15:22:30 -0400 Subject: [PATCH 18/59] More --- src/modes/mode_interface_accessors.ts | 6 +- src/modes/object_to_mode.ts | 5 +- src/modes/simple_select.ts | 747 +++++++++++++------------- src/types/types.ts | 14 +- 4 files changed, 388 insertions(+), 384 deletions(-) diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index e6724b5b..733c808d 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -4,11 +4,9 @@ import Point from '../feature_types/point'; import LineString from '../feature_types/line_string'; import Polygon from '../feature_types/polygon'; import MultiFeature from '../feature_types/multi_feature'; -import type { CTX, DrawOptions, StrictFeature } from '../types/types'; +import type { CTX, DrawOptions, StrictFeature, DrawFeature } from '../types/types'; import type { Map } from 'mapbox-gl'; -type DrawFeature = Point | LineString | Polygon | MultiFeature; - interface SelectedCoordinate { coord_path: string; feature_id: string; @@ -132,7 +130,7 @@ export default class ModeInterface { return featuresAt[bufferType](event, bbox, this._ctx); } - newFeature(geojson: StrictFeature): DrawFeature { + newFeature(geojson: StrictFeature) { const type = geojson.geometry.type; if (type === Constants.geojsonTypes.POINT) return new Point(this._ctx, geojson); diff --git a/src/modes/object_to_mode.ts b/src/modes/object_to_mode.ts index 2466402b..2f9a09a2 100644 --- a/src/modes/object_to_mode.ts +++ b/src/modes/object_to_mode.ts @@ -1,6 +1,5 @@ import ModeInterface from './mode_interface.js'; -import type { CTX, DrawCustomMode } from '../types/types'; -import type { FeatureCollection } from 'geojson'; +import type { CTX, DrawCustomMode, StrictFeature } from '../types/types'; const eventMapper = { drag: 'onDrag', @@ -64,7 +63,7 @@ export const objectToMode = (modeObject: DrawCustomMode) => { uncombineFeatures() { mode.onUncombineFeatures(state); }, - render(geojson: FeatureCollection, push) { + render(geojson: StrictFeature, push) { mode.toDisplayFeatures(state, geojson, push); } }; diff --git a/src/modes/simple_select.ts b/src/modes/simple_select.ts index 35843024..4cca80b4 100644 --- a/src/modes/simple_select.ts +++ b/src/modes/simple_select.ts @@ -6,413 +6,420 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import moveFeatures from '../lib/move_features'; import * as Constants from '../constants'; -const SimpleSelect = {}; - -SimpleSelect.onSetup = function (opts) { - // turn the opts into state. - const state = { - dragMoveLocation: null, - boxSelectStartLocation: null, - boxSelectElement: undefined, - boxSelecting: false, - canBoxSelect: false, - dragMoving: false, - canDragMove: false, - initialDragPanState: this.map.dragPan.isEnabled(), - initiallySelectedFeatureIds: opts.featureIds || [] - }; - - this.setSelected( - state.initiallySelectedFeatureIds.filter( - id => this.getFeature(id) !== undefined - ) - ); - this.fireActionable(); - - this.setActionableState({ - combineFeatures: true, - uncombineFeatures: true, - trash: true - }); - - return state; -}; - -SimpleSelect.fireUpdate = function () { - this.fire(Constants.events.UPDATE, { - action: Constants.updateActions.MOVE, - features: this.getSelected().map(f => f.toGeoJSON()) - }); -}; - -SimpleSelect.fireActionable = function () { - const selectedFeatures = this.getSelected(); - - const multiFeatures = selectedFeatures.filter(feature => - this.isInstanceOf('MultiFeature', feature) - ); - - let combineFeatures = false; +const SimpleSelect = { + + onSetup: function (opts) { + // turn the opts into state. + const state = { + dragMoveLocation: null, + boxSelectStartLocation: null, + boxSelectElement: undefined, + boxSelecting: false, + canBoxSelect: false, + dragMoving: false, + canDragMove: false, + initialDragPanState: this.map.dragPan.isEnabled(), + initiallySelectedFeatureIds: opts.featureIds || [] + }; + + this.setSelected( + state.initiallySelectedFeatureIds.filter( + id => this.getFeature(id) !== undefined + ) + ); + this.fireActionable(); - if (selectedFeatures.length > 1) { - combineFeatures = true; - const featureType = selectedFeatures[0].type.replace('Multi', ''); - selectedFeatures.forEach(feature => { - if (feature.type.replace('Multi', '') !== featureType) { - combineFeatures = false; - } + this.setActionableState({ + combineFeatures: true, + uncombineFeatures: true, + trash: true }); - } - - const uncombineFeatures = multiFeatures.length > 0; - const trash = selectedFeatures.length > 0; - - this.setActionableState({ - combineFeatures, - uncombineFeatures, - trash - }); -}; - -SimpleSelect.getUniqueIds = function (allFeatures) { - if (!allFeatures.length) return []; - const ids = allFeatures - .map(s => s.properties.id) - .filter(id => id !== undefined) - .reduce((memo, id) => { - memo.add(id); - return memo; - }, new StringSet()); - - return ids.values(); -}; - -SimpleSelect.stopExtendedInteractions = function (state) { - if (state.boxSelectElement) { - if (state.boxSelectElement.parentNode) - state.boxSelectElement.parentNode.removeChild(state.boxSelectElement); - state.boxSelectElement = null; - } - - if ( - (state.canDragMove || state.canBoxSelect) && - state.initialDragPanState === true - ) { - this.map.dragPan.enable(); - } - - state.boxSelecting = false; - state.canBoxSelect = false; - state.dragMoving = false; - state.canDragMove = false; -}; - -SimpleSelect.onStop = function () { - doubleClickZoom.enable(this); -}; - -SimpleSelect.onMouseMove = function (state, e) { - const isFeature = CommonSelectors.isFeature(e); - if (isFeature && state.dragMoving) this.fireUpdate(); - // On mousemove that is not a drag, stop extended interactions. - // This is useful if you drag off the canvas, release the button, - // then move the mouse back over the canvas --- we don't allow the - // interaction to continue then, but we do let it continue if you held - // the mouse button that whole time - this.stopExtendedInteractions(state); + return state; + }, - // Skip render - return true; -}; + fireUpdate: function () { + this.fire(Constants.events.UPDATE, { + action: Constants.updateActions.MOVE, + features: this.getSelected().map(f => f.toGeoJSON()) + }); + }, -SimpleSelect.onMouseOut = function (state) { - // As soon as you mouse leaves the canvas, update the feature - if (state.dragMoving) return this.fireUpdate(); + fireActionable: function () { + const selectedFeatures = this.getSelected(); - // Skip render - return true; -}; + const multiFeatures = selectedFeatures.filter(feature => + this.isInstanceOf('MultiFeature', feature) + ); -SimpleSelect.onTap = SimpleSelect.onClick = function (state, e) { - // Click (with or without shift) on no feature - if (CommonSelectors.noTarget(e)) return this.clickAnywhere(state, e); // also tap - if (CommonSelectors.isOfMetaType(Constants.meta.VERTEX)(e)) - return this.clickOnVertex(state, e); //tap - if (CommonSelectors.isFeature(e)) return this.clickOnFeature(state, e); -}; + let combineFeatures = false; -SimpleSelect.clickAnywhere = function (state) { - // Clear the re-render selection - const wasSelected = this.getSelectedIds(); - if (wasSelected.length) { - this.clearSelectedFeatures(); - wasSelected.forEach(id => this.doRender(id)); - } - doubleClickZoom.enable(this); - this.stopExtendedInteractions(state); -}; - -SimpleSelect.clickOnVertex = function (state, e) { - // Enter direct select mode - this.changeMode(Constants.modes.DIRECT_SELECT, { - featureId: e.featureTarget.properties.parent, - coordPath: e.featureTarget.properties.coord_path, - startPos: e.lngLat - }); - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); -}; + if (selectedFeatures.length > 1) { + combineFeatures = true; + const featureType = selectedFeatures[0].type.replace('Multi', ''); + selectedFeatures.forEach(feature => { + if (feature.type.replace('Multi', '') !== featureType) { + combineFeatures = false; + } + }); + } -SimpleSelect.startOnActiveFeature = function (state, e) { - // Stop any already-underway extended interactions - this.stopExtendedInteractions(state); + const uncombineFeatures = multiFeatures.length > 0; + const trash = selectedFeatures.length > 0; - // Disable map.dragPan immediately so it can't start - this.map.dragPan.disable(); + this.setActionableState({ + combineFeatures, + uncombineFeatures, + trash + }); + }, + + getUniqueIds: function (allFeatures) { + if (!allFeatures.length) return []; + const ids = allFeatures + .map(s => s.properties.id) + .filter(id => id !== undefined) + .reduce((memo, id) => { + memo.add(id); + return memo; + }, new StringSet()); + + return ids.values(); + }, + + stopExtendedInteractions: function (state) { + if (state.boxSelectElement) { + if (state.boxSelectElement.parentNode) + state.boxSelectElement.parentNode.removeChild(state.boxSelectElement); + state.boxSelectElement = null; + } - // Re-render it and enable drag move - this.doRender(e.featureTarget.properties.id); + if ( + (state.canDragMove || state.canBoxSelect) && + state.initialDragPanState === true + ) { + this.map.dragPan.enable(); + } - // Set up the state for drag moving - state.canDragMove = true; - state.dragMoveLocation = e.lngLat; -}; + state.boxSelecting = false; + state.canBoxSelect = false; + state.dragMoving = false; + state.canDragMove = false; + }, + + onStop: function () { + doubleClickZoom.enable(this); + }, + + onMouseMove: function (state, e) { + const isFeature = CommonSelectors.isFeature(e); + if (isFeature && state.dragMoving) this.fireUpdate(); + + // On mousemove that is not a drag, stop extended interactions. + // This is useful if you drag off the canvas, release the button, + // then move the mouse back over the canvas --- we don't allow the + // interaction to continue then, but we do let it continue if you held + // the mouse button that whole time + this.stopExtendedInteractions(state); + + // Skip render + return true; + }, + + onMouseOut: function (state) { + // As soon as you mouse leaves the canvas, update the feature + if (state.dragMoving) return this.fireUpdate(); + + // Skip render + return true; + }, + + _select: function (state, e) { + // Click (with or without shift) on no feature + if (CommonSelectors.noTarget(e)) return this.clickAnywhere(state, e); // also tap + if (CommonSelectors.isOfMetaType(Constants.meta.VERTEX)(e)) + return this.clickOnVertex(state, e); //tap + if (CommonSelectors.isFeature(e)) return this.clickOnFeature(state, e); + }, + + clickAnywhere: function (state) { + // Clear the re-render selection + const wasSelected = this.getSelectedIds(); + if (wasSelected.length) { + this.clearSelectedFeatures(); + wasSelected.forEach(id => this.doRender(id)); + } + doubleClickZoom.enable(this); + this.stopExtendedInteractions(state); + }, -SimpleSelect.clickOnFeature = function (state, e) { - // Stop everything - doubleClickZoom.disable(this); - this.stopExtendedInteractions(state); - - const isShiftClick = CommonSelectors.isShiftDown(e); - const selectedFeatureIds = this.getSelectedIds(); - const featureId = e.featureTarget.properties.id; - const isFeatureSelected = this.isSelected(featureId); - - // Click (without shift) on any selected feature but a point - if ( - !isShiftClick && - isFeatureSelected && - this.getFeature(featureId).type !== Constants.geojsonTypes.POINT - ) { + clickOnVertex: function (state, e) { // Enter direct select mode - return this.changeMode(Constants.modes.DIRECT_SELECT, { - featureId + this.changeMode(Constants.modes.DIRECT_SELECT, { + featureId: e.featureTarget.properties.parent, + coordPath: e.featureTarget.properties.coord_path, + startPos: e.lngLat }); - } - - // Shift-click on a selected feature - if (isFeatureSelected && isShiftClick) { - // Deselect it - this.deselect(featureId); - this.updateUIClasses({ mouse: Constants.cursors.POINTER }); - if (selectedFeatureIds.length === 1) { - doubleClickZoom.enable(this); - } - // Shift-click on an unselected feature - } else if (!isFeatureSelected && isShiftClick) { - // Add it to the selection - this.select(featureId); - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - // Click (without shift) on an unselected feature - } else if (!isFeatureSelected && !isShiftClick) { - // Make it the only selected feature - selectedFeatureIds.forEach(id => this.doRender(id)); - this.setSelected(featureId); this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - } - - // No matter what, re-render the clicked feature - this.doRender(featureId); -}; - -SimpleSelect.onMouseDown = function (state, e) { - state.initialDragPanState = this.map.dragPan.isEnabled(); - if (CommonSelectors.isActiveFeature(e)) - return this.startOnActiveFeature(state, e); - if (this.drawConfig.boxSelect && CommonSelectors.isShiftMousedown(e)) - return this.startBoxSelect(state, e); -}; - -SimpleSelect.startBoxSelect = function (state, e) { - this.stopExtendedInteractions(state); - this.map.dragPan.disable(); - // Enable box select - state.boxSelectStartLocation = mouseEventPoint( - e.originalEvent, - this.map.getContainer() - ); - state.canBoxSelect = true; -}; - -SimpleSelect.onTouchStart = function (state, e) { - if (CommonSelectors.isActiveFeature(e)) - return this.startOnActiveFeature(state, e); -}; - -SimpleSelect.onDrag = function (state, e) { - if (state.canDragMove) return this.dragMove(state, e); - if (this.drawConfig.boxSelect && state.canBoxSelect) - return this.whileBoxSelect(state, e); -}; - -SimpleSelect.whileBoxSelect = function (state, e) { - state.boxSelecting = true; - this.updateUIClasses({ mouse: Constants.cursors.ADD }); - - // Create the box node if it doesn't exist - if (!state.boxSelectElement) { - state.boxSelectElement = document.createElement('div'); - state.boxSelectElement.classList.add(Constants.classes.BOX_SELECT); - this.map.getContainer().appendChild(state.boxSelectElement); - } - - // Adjust the box node's width and xy position - const current = mouseEventPoint(e.originalEvent, this.map.getContainer()); - const minX = Math.min(state.boxSelectStartLocation.x, current.x); - const maxX = Math.max(state.boxSelectStartLocation.x, current.x); - const minY = Math.min(state.boxSelectStartLocation.y, current.y); - const maxY = Math.max(state.boxSelectStartLocation.y, current.y); - const translateValue = `translate(${minX}px, ${minY}px)`; - state.boxSelectElement.style.transform = translateValue; - state.boxSelectElement.style.WebkitTransform = translateValue; - state.boxSelectElement.style.width = `${maxX - minX}px`; - state.boxSelectElement.style.height = `${maxY - minY}px`; -}; - -SimpleSelect.dragMove = function (state, e) { - // Dragging when drag move is enabled - state.dragMoving = true; - e.originalEvent.stopPropagation(); - - const delta = { - lng: e.lngLat.lng - state.dragMoveLocation.lng, - lat: e.lngLat.lat - state.dragMoveLocation.lat - }; - - moveFeatures(this.getSelected(), delta); + }, + + startOnActiveFeature: function (state, e) { + // Stop any already-underway extended interactions + this.stopExtendedInteractions(state); + + // Disable map.dragPan immediately so it can't start + this.map.dragPan.disable(); + + // Re-render it and enable drag move + this.doRender(e.featureTarget.properties.id); + + // Set up the state for drag moving + state.canDragMove = true; + state.dragMoveLocation = e.lngLat; + }, + + clickOnFeature: function (state, e) { + // Stop everything + doubleClickZoom.disable(this); + this.stopExtendedInteractions(state); + + const isShiftClick = CommonSelectors.isShiftDown(e); + const selectedFeatureIds = this.getSelectedIds(); + const featureId = e.featureTarget.properties.id; + const isFeatureSelected = this.isSelected(featureId); + + // Click (without shift) on any selected feature but a point + if ( + !isShiftClick && + isFeatureSelected && + this.getFeature(featureId).type !== Constants.geojsonTypes.POINT + ) { + // Enter direct select mode + return this.changeMode(Constants.modes.DIRECT_SELECT, { + featureId + }); + } - state.dragMoveLocation = e.lngLat; -}; + // Shift-click on a selected feature + if (isFeatureSelected && isShiftClick) { + // Deselect it + this.deselect(featureId); + this.updateUIClasses({ mouse: Constants.cursors.POINTER }); + if (selectedFeatureIds.length === 1) { + doubleClickZoom.enable(this); + } + // Shift-click on an unselected feature + } else if (!isFeatureSelected && isShiftClick) { + // Add it to the selection + this.select(featureId); + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + // Click (without shift) on an unselected feature + } else if (!isFeatureSelected && !isShiftClick) { + // Make it the only selected feature + selectedFeatureIds.forEach(id => this.doRender(id)); + this.setSelected(featureId); + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + } -SimpleSelect.onTouchEnd = SimpleSelect.onMouseUp = function (state, e) { - // End any extended interactions - if (state.dragMoving) { - this.fireUpdate(); - } else if (state.boxSelecting) { - const bbox = [ - state.boxSelectStartLocation, - mouseEventPoint(e.originalEvent, this.map.getContainer()) - ]; - const featuresInBox = this.featuresAt(null, bbox, 'click'); - const idsToSelect = this.getUniqueIds(featuresInBox).filter( - id => !this.isSelected(id) + // No matter what, re-render the clicked feature + this.doRender(featureId); + }, + + onMouseDown: function (state, e) { + state.initialDragPanState = this.map.dragPan.isEnabled(); + if (CommonSelectors.isActiveFeature(e)) + return this.startOnActiveFeature(state, e); + if (this.drawConfig.boxSelect && CommonSelectors.isShiftMousedown(e)) + return this.startBoxSelect(state, e); + }, + + startBoxSelect: function (state, e) { + this.stopExtendedInteractions(state); + this.map.dragPan.disable(); + // Enable box select + state.boxSelectStartLocation = mouseEventPoint( + e.originalEvent, + this.map.getContainer() ); + state.canBoxSelect = true; + }, + + onTouchStart: function (state, e) { + if (CommonSelectors.isActiveFeature(e)) + return this.startOnActiveFeature(state, e); + }, + + onDrag: function (state, e) { + if (state.canDragMove) return this.dragMove(state, e); + if (this.drawConfig.boxSelect && state.canBoxSelect) + return this.whileBoxSelect(state, e); + }, + + whileBoxSelect: function (state, e) { + state.boxSelecting = true; + this.updateUIClasses({ mouse: Constants.cursors.ADD }); + + // Create the box node if it doesn't exist + if (!state.boxSelectElement) { + state.boxSelectElement = document.createElement('div'); + state.boxSelectElement.classList.add(Constants.classes.BOX_SELECT); + this.map.getContainer().appendChild(state.boxSelectElement); + } - if (idsToSelect.length) { - this.select(idsToSelect); - idsToSelect.forEach(id => this.doRender(id)); - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + // Adjust the box node's width and xy position + const current = mouseEventPoint(e.originalEvent, this.map.getContainer()); + const minX = Math.min(state.boxSelectStartLocation.x, current.x); + const maxX = Math.max(state.boxSelectStartLocation.x, current.x); + const minY = Math.min(state.boxSelectStartLocation.y, current.y); + const maxY = Math.max(state.boxSelectStartLocation.y, current.y); + const translateValue = `translate(${minX}px, ${minY}px)`; + state.boxSelectElement.style.transform = translateValue; + state.boxSelectElement.style.WebkitTransform = translateValue; + state.boxSelectElement.style.width = `${maxX - minX}px`; + state.boxSelectElement.style.height = `${maxY - minY}px`; + }, + + dragMove: function (state, e) { + // Dragging when drag move is enabled + state.dragMoving = true; + e.originalEvent.stopPropagation(); + + const delta = { + lng: e.lngLat.lng - state.dragMoveLocation.lng, + lat: e.lngLat.lat - state.dragMoveLocation.lat + }; + + moveFeatures(this.getSelected(), delta); + + state.dragMoveLocation = e.lngLat; + }, + + _end: function (state, e) { + // End any extended interactions + if (state.dragMoving) { + this.fireUpdate(); + } else if (state.boxSelecting) { + const bbox = [ + state.boxSelectStartLocation, + mouseEventPoint(e.originalEvent, this.map.getContainer()) + ]; + const featuresInBox = this.featuresAt(null, bbox, 'click'); + const idsToSelect = this.getUniqueIds(featuresInBox).filter( + id => !this.isSelected(id) + ); + + if (idsToSelect.length) { + this.select(idsToSelect); + idsToSelect.forEach(id => this.doRender(id)); + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + } } - } - this.stopExtendedInteractions(state); -}; + this.stopExtendedInteractions(state); + }, + + toDisplayFeatures: function (state, geojson, display) { + geojson.properties.active = this.isSelected(geojson.properties.id) + ? Constants.activeStates.ACTIVE + : Constants.activeStates.INACTIVE; + display(geojson); + this.fireActionable(); + if ( + geojson.properties.active !== Constants.activeStates.ACTIVE || + geojson.geometry.type === Constants.geojsonTypes.POINT + ) + return; + createSupplementaryPoints(geojson).forEach(display); + }, -SimpleSelect.toDisplayFeatures = function (state, geojson, display) { - geojson.properties.active = this.isSelected(geojson.properties.id) - ? Constants.activeStates.ACTIVE - : Constants.activeStates.INACTIVE; - display(geojson); - this.fireActionable(); - if ( - geojson.properties.active !== Constants.activeStates.ACTIVE || - geojson.geometry.type === Constants.geojsonTypes.POINT - ) - return; - createSupplementaryPoints(geojson).forEach(display); -}; + onTrash: function () { + this.deleteFeature(this.getSelectedIds()); + this.fireActionable(); + }, -SimpleSelect.onTrash = function () { - this.deleteFeature(this.getSelectedIds()); - this.fireActionable(); -}; + onCombineFeatures: function () { + const selectedFeatures = this.getSelected(); -SimpleSelect.onCombineFeatures = function () { - const selectedFeatures = this.getSelected(); + if (selectedFeatures.length === 0 || selectedFeatures.length < 2) return; - if (selectedFeatures.length === 0 || selectedFeatures.length < 2) return; + const coordinates = [], + featuresCombined = []; + const featureType = selectedFeatures[0].type.replace('Multi', ''); - const coordinates = [], - featuresCombined = []; - const featureType = selectedFeatures[0].type.replace('Multi', ''); + for (let i = 0; i < selectedFeatures.length; i++) { + const feature = selectedFeatures[i]; - for (let i = 0; i < selectedFeatures.length; i++) { - const feature = selectedFeatures[i]; + if (feature.type.replace('Multi', '') !== featureType) { + return; + } + if (feature.type.includes('Multi')) { + feature.getCoordinates().forEach(subcoords => { + coordinates.push(subcoords); + }); + } else { + coordinates.push(feature.getCoordinates()); + } - if (feature.type.replace('Multi', '') !== featureType) { - return; + featuresCombined.push(feature.toGeoJSON()); } - if (feature.type.includes('Multi')) { - feature.getCoordinates().forEach(subcoords => { - coordinates.push(subcoords); + + if (featuresCombined.length > 1) { + const multiFeature = this.newFeature({ + type: Constants.geojsonTypes.FEATURE, + properties: featuresCombined[0].properties, + geometry: { + type: `Multi${featureType}`, + coordinates + } }); - } else { - coordinates.push(feature.getCoordinates()); - } - featuresCombined.push(feature.toGeoJSON()); - } + this.addFeature(multiFeature); + this.deleteFeature(this.getSelectedIds(), { silent: true }); + this.setSelected([multiFeature.id]); - if (featuresCombined.length > 1) { - const multiFeature = this.newFeature({ - type: Constants.geojsonTypes.FEATURE, - properties: featuresCombined[0].properties, - geometry: { - type: `Multi${featureType}`, - coordinates + this.fire(Constants.events.COMBINE_FEATURES, { + createdFeatures: [multiFeature.toGeoJSON()], + deletedFeatures: featuresCombined + }); + } + this.fireActionable(); + }, + + onUncombineFeatures: function () { + const selectedFeatures = this.getSelected(); + if (selectedFeatures.length === 0) return; + + const createdFeatures = []; + const featuresUncombined = []; + + for (let i = 0; i < selectedFeatures.length; i++) { + const feature = selectedFeatures[i]; + + if (this.isInstanceOf('MultiFeature', feature)) { + feature.getFeatures().forEach(subFeature => { + this.addFeature(subFeature); + subFeature.properties = feature.properties; + createdFeatures.push(subFeature.toGeoJSON()); + this.select([subFeature.id]); + }); + this.deleteFeature(feature.id, { silent: true }); + featuresUncombined.push(feature.toGeoJSON()); } - }); - - this.addFeature(multiFeature); - this.deleteFeature(this.getSelectedIds(), { silent: true }); - this.setSelected([multiFeature.id]); - - this.fire(Constants.events.COMBINE_FEATURES, { - createdFeatures: [multiFeature.toGeoJSON()], - deletedFeatures: featuresCombined - }); - } - this.fireActionable(); -}; - -SimpleSelect.onUncombineFeatures = function () { - const selectedFeatures = this.getSelected(); - if (selectedFeatures.length === 0) return; - - const createdFeatures = []; - const featuresUncombined = []; - - for (let i = 0; i < selectedFeatures.length; i++) { - const feature = selectedFeatures[i]; + } - if (this.isInstanceOf('MultiFeature', feature)) { - feature.getFeatures().forEach(subFeature => { - this.addFeature(subFeature); - subFeature.properties = feature.properties; - createdFeatures.push(subFeature.toGeoJSON()); - this.select([subFeature.id]); + if (createdFeatures.length > 1) { + this.fire(Constants.events.UNCOMBINE_FEATURES, { + createdFeatures, + deletedFeatures: featuresUncombined }); - this.deleteFeature(feature.id, { silent: true }); - featuresUncombined.push(feature.toGeoJSON()); } - } + this.fireActionable(); + }, + + onTap: function (state, e) { return this._select(state, e); }, + onClick: function (state, e) { return this._select(state, e); }, + onMouseUp: function (state, e) { return this._end(state, e); }, + onTouchEnd: function (state, e) { return this._end(state, e); } - if (createdFeatures.length > 1) { - this.fire(Constants.events.UNCOMBINE_FEATURES, { - createdFeatures, - deletedFeatures: featuresUncombined - }); - } - this.fireActionable(); }; export default SimpleSelect; diff --git a/src/types/types.ts b/src/types/types.ts index 753810c4..674dee9d 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -223,7 +223,7 @@ interface DrawPolygon extends DrawFeatureBase { removeCoordinate(path: string): void; } -type DrawFeature = +export type DrawFeature = | DrawPoint | DrawLineString | DrawPolygon @@ -297,7 +297,7 @@ interface DrawActionableEvent extends DrawEvent { export interface DrawCustomModeThis { map: Map; drawConfig: DrawOptions; - setSelected(features?: string | string[]): void; + setSelected(features?: DrawFeature[]): void; setSelectedCoordinates( coords: Array<{ coord_path: string; feature_id: string }> ): void; @@ -641,7 +641,7 @@ interface DrawStore { }, getInitialConfigValue(interaction: string): boolean; featureChanged(id: string, options?: DrawStoreOptions): boolean; - setSelected(features?: string | string[]): void; + setSelected(features?: DrawFeature[]): void; setSelectedCoordinates( coords: Array<{ coord_path: string; feature_id: string }> ): void; @@ -653,10 +653,10 @@ interface DrawStore { getFeature(id: string): DrawFeature; select(id: string): void; deselect(features: string | string[]): void; - delete(id: string): void; - deleteFeature(id: string, opts?: any): void; - add(featureId: string): void; - addFeature(feature: DrawFeature): void; + delete(id: string, opts: Record): void; + deleteFeature(id: string, opts?: unknown): void; + add(feature: DrawFeature, opts: Record): void; + addFeature(feature: DrawFeature, opts: Record): void; clearSelected(): void; clearSelectedFeatures(): void; clearSelectedCoordinates(): void; From 2923db42279ddee4d9725687bb827d0f7c402efd Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 17:01:53 -0400 Subject: [PATCH 19/59] More --- src/api.ts | 363 +++++++++++++++++++++++---------------------- src/events.ts | 267 +++++++++++++++++---------------- src/lib/is_tap.ts | 12 +- src/setup.ts | 3 +- src/types/types.ts | 5 +- src/ui.ts | 11 +- 6 files changed, 339 insertions(+), 322 deletions(-) diff --git a/src/api.ts b/src/api.ts index 18dd63f0..2750c231 100644 --- a/src/api.ts +++ b/src/api.ts @@ -23,7 +23,6 @@ const featureTypes = { }; export default function (ctx: CTX, api: Draw) { - api.modes = Constants.modes; // API doesn't emit events by default const silent = @@ -31,208 +30,210 @@ export default function (ctx: CTX, api: Draw) { ? !!ctx.options.suppressAPIEvents : true; - api.getFeatureIdsAt = function (point) { - const features = featuresAt.click({ point }, null, ctx); - return features.map(feature => feature.properties.id); - }; - - api.getSelectedIds = function () { - return ctx.store.getSelectedIds(); - }; - - api.getSelected = function () { - return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store - .getSelectedIds() - .map(id => ctx.store.get(id)) - .map(feature => feature.toGeoJSON()) - }; - }; - - api.getSelectedPoints = function () { - return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store.getSelectedCoordinates().map(coordinate => ({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POINT, - coordinates: coordinate.coordinates - } - })) - }; - }; - - api.set = function (featureCollection) { - if ( - featureCollection.type === undefined || - featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || - !Array.isArray(featureCollection.features) - ) { - throw new Error('Invalid FeatureCollection'); - } - const renderBatch = ctx.store.createRenderBatch(); - let toDelete = ctx.store.getAllIds().slice(); - const newIds = api.add(featureCollection); - const newIdsLookup = new StringSet(newIds); - - toDelete = toDelete.filter(id => !newIdsLookup.has(id)); - if (toDelete.length) { - api.delete(toDelete); - } - - renderBatch(); - return newIds; - }; + return { + modes: Constants.modes, + + getFeatureIdsAt: function (point) { + const features = featuresAt.click({ point }, null, ctx); + return features.map(feature => feature.properties.id); + }, + + getSelectedIds: function () { + return ctx.store.getSelectedIds(); + }, + + getSelected: function () { + return { + type: Constants.geojsonTypes.FEATURE_COLLECTION, + features: ctx.store + .getSelectedIds() + .map(id => ctx.store.get(id)) + .map(feature => feature.toGeoJSON()) + }; + }, + + getSelectedPoints: function () { + return { + type: Constants.geojsonTypes.FEATURE_COLLECTION, + features: ctx.store.getSelectedCoordinates().map(coordinate => ({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POINT, + coordinates: coordinate.coordinates + } + })) + }; + }, + + set: function (featureCollection) { + if ( + featureCollection.type === undefined || + featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || + !Array.isArray(featureCollection.features) + ) { + throw new Error('Invalid FeatureCollection'); + } + const renderBatch = ctx.store.createRenderBatch(); + let toDelete = ctx.store.getAllIds().slice(); + const newIds = api.add(featureCollection); + const newIdsLookup = new StringSet(newIds); + + toDelete = toDelete.filter(id => !newIdsLookup.has(id)); + if (toDelete.length) { + api.delete(toDelete); + } - api.add = function (geojson) { - const featureCollection = JSON.parse(JSON.stringify(normalize(geojson))); + renderBatch(); + return newIds; + }, - const ids = featureCollection.features.map(feature => { - feature.id = feature.id || generateID(); + add: function (geojson) { + const featureCollection = JSON.parse(JSON.stringify(normalize(geojson))); - if (feature.geometry === null) { - throw new Error('Invalid geometry: null'); - } + const ids = featureCollection.features.map(feature => { + feature.id = feature.id || generateID(); - if ( - ctx.store.get(feature.id) === undefined || - ctx.store.get(feature.id).type !== feature.geometry.type - ) { - // If the feature has not yet been created ... - const Model = featureTypes[feature.geometry.type]; - if (Model === undefined) { - throw new Error(`Invalid geometry type: ${feature.geometry.type}.`); - } - const internalFeature = new Model(ctx, feature); - ctx.store.add(internalFeature, { silent }); - } else { - // If a feature of that id has already been created, and we are swapping it out ... - const internalFeature = ctx.store.get(feature.id); - const originalProperties = internalFeature.properties; - internalFeature.properties = feature.properties; - if (!isEqual(originalProperties, feature.properties)) { - ctx.store.featureChanged(internalFeature.id, { silent }); + if (feature.geometry === null) { + throw new Error('Invalid geometry: null'); } + if ( - !isEqual( - internalFeature.getCoordinates(), - feature.geometry.coordinates - ) + ctx.store.get(feature.id) === undefined || + ctx.store.get(feature.id).type !== feature.geometry.type ) { - internalFeature.incomingCoords(feature.geometry.coordinates); + // If the feature has not yet been created ... + const Model = featureTypes[feature.geometry.type]; + if (Model === undefined) { + throw new Error(`Invalid geometry type: ${feature.geometry.type}.`); + } + const internalFeature = new Model(ctx, feature); + ctx.store.add(internalFeature, { silent }); + } else { + // If a feature of that id has already been created, and we are swapping it out ... + const internalFeature = ctx.store.get(feature.id); + const originalProperties = internalFeature.properties; + internalFeature.properties = feature.properties; + if (!isEqual(originalProperties, feature.properties)) { + ctx.store.featureChanged(internalFeature.id, { silent }); + } + if ( + !isEqual( + internalFeature.getCoordinates(), + feature.geometry.coordinates + ) + ) { + internalFeature.incomingCoords(feature.geometry.coordinates); + } } - } - return feature.id; - }); - - ctx.store.render(); - return ids; - }; - - api.get = function (id) { - const feature = ctx.store.get(id); - if (feature) { - return feature.toGeoJSON(); - } - }; - - api.getAll = function () { - return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store.getAll().map(feature => feature.toGeoJSON()) - }; - }; - - api.delete = function (featureIds) { - ctx.store.delete(featureIds, { silent }); - // If we were in direct select mode and our selected feature no longer exists - // (because it was deleted), we need to get out of that mode. - if ( - api.getMode() === Constants.modes.DIRECT_SELECT && - !ctx.store.getSelectedIds().length - ) { - ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { - silent + return feature.id; }); - } else { + ctx.store.render(); - } + return ids; + }, - return api; - }; + get: function (id) { + const feature = ctx.store.get(id); + if (feature) { + return feature.toGeoJSON(); + } + }, + + getAll: function () { + return { + type: Constants.geojsonTypes.FEATURE_COLLECTION, + features: ctx.store.getAll().map(feature => feature.toGeoJSON()) + }; + }, + + delete: function (featureIds) { + ctx.store.delete(featureIds, { silent }); + // If we were in direct select mode and our selected feature no longer exists + // (because it was deleted), we need to get out of that mode. + if ( + api.getMode() === Constants.modes.DIRECT_SELECT && + !ctx.store.getSelectedIds().length + ) { + ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { + silent + }); + } else { + ctx.store.render(); + } - api.deleteAll = function () { - ctx.store.delete(ctx.store.getAllIds(), { silent }); - // If we were in direct select mode, now our selected feature no longer exists, - // so escape that mode. - if (api.getMode() === Constants.modes.DIRECT_SELECT) { - ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { - silent - }); - } else { - ctx.store.render(); - } + return api; + }, + + deleteAll: function () { + ctx.store.delete(ctx.store.getAllIds(), { silent }); + // If we were in direct select mode, now our selected feature no longer exists, + // so escape that mode. + if (api.getMode() === Constants.modes.DIRECT_SELECT) { + ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { + silent + }); + } else { + ctx.store.render(); + } - return api; - }; + return api; + }, - api.changeMode = function (mode, modeOptions = {}) { - // Avoid changing modes just to re-select what's already selected - if ( - mode === Constants.modes.SIMPLE_SELECT && - api.getMode() === Constants.modes.SIMPLE_SELECT - ) { + changeMode: function (mode, modeOptions = {}) { + // Avoid changing modes just to re-select what's already selected if ( - stringSetsAreEqual( - modeOptions.featureIds || [], - ctx.store.getSelectedIds() + mode === Constants.modes.SIMPLE_SELECT && + api.getMode() === Constants.modes.SIMPLE_SELECT + ) { + if ( + stringSetsAreEqual( + modeOptions.featureIds || [], + ctx.store.getSelectedIds() + ) ) - ) + return api; + // And if we are changing the selection within simple_select mode, just change the selection, + // instead of stopping and re-starting the mode + ctx.store.setSelected(modeOptions.featureIds, { silent }); + ctx.store.render(); return api; - // And if we are changing the selection within simple_select mode, just change the selection, - // instead of stopping and re-starting the mode - ctx.store.setSelected(modeOptions.featureIds, { silent }); - ctx.store.render(); - return api; - } - - if ( - mode === Constants.modes.DIRECT_SELECT && - api.getMode() === Constants.modes.DIRECT_SELECT && - modeOptions.featureId === ctx.store.getSelectedIds()[0] - ) { - return api; - } + } - ctx.events.changeMode(mode, modeOptions, { silent }); - return api; - }; + if ( + mode === Constants.modes.DIRECT_SELECT && + api.getMode() === Constants.modes.DIRECT_SELECT && + modeOptions.featureId === ctx.store.getSelectedIds()[0] + ) { + return api; + } - api.getMode = function () { - return ctx.events.getMode(); - }; + ctx.events.changeMode(mode, modeOptions, { silent }); + return api; + }, - api.trash = function () { - ctx.events.trash({ silent }); - return api; - }; + getMode: function () { + return ctx.events.getMode(); + }, - api.combineFeatures = function () { - ctx.events.combineFeatures({ silent }); - return api; - }; + trash: function () { + ctx.events.trash({ silent }); + return api; + }, - api.uncombineFeatures = function () { - ctx.events.uncombineFeatures({ silent }); - return api; - }; + combineFeatures: function () { + ctx.events.combineFeatures({ silent }); + return api; + }, - api.setFeatureProperty = function (featureId, property, value) { - ctx.store.setFeatureProperty(featureId, property, value, { silent }); - return api; - }; + uncombineFeatures: function () { + ctx.events.uncombineFeatures({ silent }); + return api; + }, - return api; + setFeatureProperty: function (featureId, property, value) { + ctx.store.setFeatureProperty(featureId, property, value, { silent }); + return api; + } + } } diff --git a/src/events.ts b/src/events.ts index fe693310..a203a097 100644 --- a/src/events.ts +++ b/src/events.ts @@ -5,167 +5,174 @@ import { isClick } from './lib/is_click'; import { isTap } from './lib/is_tap'; import * as Constants from './constants'; import { objectToMode } from './modes/object_to_mode'; -import type { CTX } from './types/types'; +import type { CTX, Entry } from './types/types'; export default function(ctx: CTX) { - const modes = Object.keys(ctx.options.modes).reduce((m, k) => { m[k] = objectToMode(ctx.options.modes[k]); return m; }, {}); - let mouseDownInfo = {}; - let touchStartInfo = {}; - const events = {}; + let mouseDownInfo = {} as Entry; + let touchStartInfo = {} as Entry; let currentModeName = null; let currentMode = null; - events.drag = function(event, isDrag) { - if (isDrag({ - point: event.point, - time: new Date().getTime() - })) { - ctx.ui.queueMapClasses({ mouse: Constants.cursors.DRAG }); - currentMode.drag(event); - } else { - event.originalEvent.stopPropagation(); - } - }; + // 8 - Backspace + // 46 - Delete + const isKeyModeValid = code => !(code === 8 || code === 46 || (code >= 48 && code <= 57)); - events.mousedrag = function(event) { - events.drag(event, endInfo => !isClick(mouseDownInfo, endInfo)); - }; + const events = { + drag: function(event, isDrag) { + if (isDrag) { + ctx.ui.queueMapClasses({ mouse: Constants.cursors.DRAG }); + currentMode.drag(event); + } else { + event.originalEvent.stopPropagation(); + } + }, - events.touchdrag = function(event) { - events.drag(event, endInfo => !isTap(touchStartInfo, endInfo)); - }; + mousedrag: function(event) { + const info = { + point: event.point, + time: new Date().getTime() + }; - events.mousemove = function(event) { - const button = event.originalEvent.buttons !== undefined ? event.originalEvent.buttons : event.originalEvent.which; - if (button === 1) { - return events.mousedrag(event); - } - const target = getFeatureAtAndSetCursors(event, ctx); - event.featureTarget = target; - currentMode.mousemove(event); - }; + events.drag(event, !isClick(mouseDownInfo, info)); + }, - events.mousedown = function(event) { - mouseDownInfo = { - time: new Date().getTime(), - point: event.point - }; - const target = getFeatureAtAndSetCursors(event, ctx); - event.featureTarget = target; - currentMode.mousedown(event); - }; + touchdrag: function(event) { + const info = { + point: event.point, + time: new Date().getTime() + }; - events.mouseup = function(event) { - const target = getFeatureAtAndSetCursors(event, ctx); - event.featureTarget = target; - - if (isClick(mouseDownInfo, { - point: event.point, - time: new Date().getTime() - })) { - currentMode.click(event); - } else { - currentMode.mouseup(event); - } - }; + events.drag(event, !isTap(touchStartInfo, info)); + }, - events.mouseout = function(event) { - currentMode.mouseout(event); - }; + mousemove: function(event) { + const button = event.originalEvent.buttons !== undefined ? event.originalEvent.buttons : event.originalEvent.which; + if (button === 1) { + return events.mousedrag(event); + } + const target = getFeatureAtAndSetCursors(event, ctx); + event.featureTarget = target; + currentMode.mousemove(event); + }, - events.touchstart = function(event) { - if (!ctx.options.touchEnabled) { - return; - } + mousedown: function(event) { + mouseDownInfo = { + time: new Date().getTime(), + point: event.point + }; + const target = getFeatureAtAndSetCursors(event, ctx); + event.featureTarget = target; + currentMode.mousedown(event); + }, - touchStartInfo = { - time: new Date().getTime(), - point: event.point - }; - const target = featuresAt.touch(event, null, ctx)[0]; - event.featureTarget = target; - currentMode.touchstart(event); - }; + mouseup: function(event) { + const target = getFeatureAtAndSetCursors(event, ctx); + event.featureTarget = target; + + if (isClick(mouseDownInfo, { + point: event.point, + time: new Date().getTime() + })) { + currentMode.click(event); + } else { + currentMode.mouseup(event); + } + }, - events.touchmove = function(event) { - if (!ctx.options.touchEnabled) { - return; - } + mouseout: function(event) { + currentMode.mouseout(event); + }, - currentMode.touchmove(event); - return events.touchdrag(event); - }; + touchstart: function(event) { + if (!ctx.options.touchEnabled) { + return; + } - events.touchend = function(event) { - // Prevent emulated mouse events because we will fully handle the touch here. - // This does not stop the touch events from propogating to mapbox though. - event.originalEvent.preventDefault(); - if (!ctx.options.touchEnabled) { - return; - } + touchStartInfo = { + time: new Date().getTime(), + point: event.point + }; + const target = featuresAt.touch(event, null, ctx)[0]; + event.featureTarget = target; + currentMode.touchstart(event); + }, - const target = featuresAt.touch(event, null, ctx)[0]; - event.featureTarget = target; - if (isTap(touchStartInfo, { - time: new Date().getTime(), - point: event.point - })) { - currentMode.tap(event); - } else { - currentMode.touchend(event); - } - }; + touchmove: function(event) { + if (!ctx.options.touchEnabled) { + return; + } - // 8 - Backspace - // 46 - Delete - const isKeyModeValid = code => !(code === 8 || code === 46 || (code >= 48 && code <= 57)); + currentMode.touchmove(event); + return events.touchdrag(event); + }, - events.keydown = function(event) { - const isMapElement = (event.srcElement || event.target).classList.contains(Constants.classes.CANVAS); - if (!isMapElement) return; // we only handle events on the map - - if ((event.keyCode === 8 || event.keyCode === 46) && ctx.options.controls.trash) { - event.preventDefault(); - currentMode.trash(); - } else if (isKeyModeValid(event.keyCode)) { - currentMode.keydown(event); - } else if (event.keyCode === 49 && ctx.options.controls.point) { - changeMode(Constants.modes.DRAW_POINT); - } else if (event.keyCode === 50 && ctx.options.controls.line_string) { - changeMode(Constants.modes.DRAW_LINE_STRING); - } else if (event.keyCode === 51 && ctx.options.controls.polygon) { - changeMode(Constants.modes.DRAW_POLYGON); - } - }; + touchend: function(event) { + // Prevent emulated mouse events because we will fully handle the touch here. + // This does not stop the touch events from propogating to mapbox though. + event.originalEvent.preventDefault(); + if (!ctx.options.touchEnabled) { + return; + } - events.keyup = function(event) { - if (isKeyModeValid(event.keyCode)) { - currentMode.keyup(event); - } - }; + const target = featuresAt.touch(event, null, ctx)[0]; + event.featureTarget = target; + if (isTap(touchStartInfo, { + time: new Date().getTime(), + point: event.point + })) { + currentMode.tap(event); + } else { + currentMode.touchend(event); + } + }, - events.zoomend = function() { - ctx.store.changeZoom(); - }; + keydown: function(event) { + const isMapElement = (event.srcElement || event.target).classList.contains(Constants.classes.CANVAS); + if (!isMapElement) return; // we only handle events on the map + + if ((event.keyCode === 8 || event.keyCode === 46) && ctx.options.controls.trash) { + event.preventDefault(); + currentMode.trash(); + } else if (isKeyModeValid(event.keyCode)) { + currentMode.keydown(event); + } else if (event.keyCode === 49 && ctx.options.controls.point) { + changeMode(Constants.modes.DRAW_POINT); + } else if (event.keyCode === 50 && ctx.options.controls.line_string) { + changeMode(Constants.modes.DRAW_LINE_STRING); + } else if (event.keyCode === 51 && ctx.options.controls.polygon) { + changeMode(Constants.modes.DRAW_POLYGON); + } + }, + + keyup: function(event) { + if (isKeyModeValid(event.keyCode)) { + currentMode.keyup(event); + } + }, + + zoomend: function() { + ctx.store.changeZoom(); + }, - events.data = function(event) { - if (event.dataType === 'style') { - const { setup, map, options, store } = ctx; - const hasLayers = options.styles.some(style => map.getLayer(style.id)); - if (!hasLayers) { - setup.addLayers(); - store.setDirty(); - store.render(); + data: function(event) { + if (event.dataType === 'style') { + const { setup, map, options, store } = ctx; + const hasLayers = options.styles.some(style => map.getLayer(style.id)); + if (!hasLayers) { + setup.addLayers(); + store.setDirty(); + store.render(); + } } } }; - function changeMode(modename, nextModeOptions, eventOptions = {}) { + function changeMode(modename, nextModeOptions = {}, eventOptions = {}) { currentMode.stop(); const modebuilder = modes[modename]; diff --git a/src/lib/is_tap.ts b/src/lib/is_tap.ts index 359dc4fd..6f08a1fe 100644 --- a/src/lib/is_tap.ts +++ b/src/lib/is_tap.ts @@ -2,17 +2,21 @@ import { euclideanDistance } from './euclidean_distance.js'; import type { Entry } from '../types/types'; interface Options { - tolerance: number; - interval: number; + tolerance?: number; + interval?: number; } export const isTap = ( start: Entry, end: Entry, - { tolerance = 25, interval = 250 }: Options -) => { + options: Options = {} +): boolean => { + const { tolerance = 25, interval = 250 } = options; + start.point = start.point || end.point; start.time = start.time || end.time; const moveDistance = euclideanDistance(start.point, end.point); + return moveDistance < tolerance && end.time - start.time < interval; }; + diff --git a/src/setup.ts b/src/setup.ts index 9802f95d..8a5f9909 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -2,9 +2,8 @@ import events from './events'; import Store from './store'; import ui from './ui'; import * as Constants from './constants'; -import type { CTX } from './types/types'; -export default function (ctx: CTX) { +export default function (ctx) { let controlContainer = null; let mapLoadedInterval = null; diff --git a/src/types/types.ts b/src/types/types.ts index 674dee9d..40e9ffaa 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -614,7 +614,7 @@ export interface DrawOptions { interface DrawEvents { actionable(action: DrawActionableState): void; addEventListeners(): void; - changeMode(mode: string, modeOptions: {}, eventOptions: {}): void; + changeMode(mode: string, modeOptions?: {}, eventOptions?: {}): void; combineFeatures(): void; currentModeName(): string; currentModeRender(geojson: StrictFeature, push: (geojson: StrictFeature) => void): void; @@ -639,13 +639,14 @@ interface DrawStore { hot: [], cold: [] }, + restoreMapConfig(): Record; getInitialConfigValue(interaction: string): boolean; featureChanged(id: string, options?: DrawStoreOptions): boolean; setSelected(features?: DrawFeature[]): void; setSelectedCoordinates( coords: Array<{ coord_path: string; feature_id: string }> ): void; - + getSelectedCoordinates(): Coords[]; getSelected(): DrawFeature[]; getSelectedIds(): string[]; isSelected(id: string): boolean; diff --git a/src/ui.ts b/src/ui.ts index ec8e39a7..fc3466d8 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,11 +1,16 @@ import * as Constants from './constants'; - import type { CTX } from './types/types'; const classTypes = ['mode', 'feature', 'mouse']; +interface ButtonElements { + trash?: HTMLButtonElement; + combine_features?: HTMLButtonElement; + uncombine_features?: HTMLButtonElement; +} + export default function (ctx: CTX) { - const buttonElements = {}; + const buttonElements: ButtonElements = {}; let activeButton = null; let currentMapClasses = { @@ -55,7 +60,7 @@ export default function (ctx: CTX) { currentMapClasses = Object.assign(currentMapClasses, nextMapClasses); } - function createControlButton(id: string, options = {}) { + function createControlButton(id: string, options) { const button = document.createElement('button'); button.className = `${Constants.classes.CONTROL_BUTTON} ${options.className}`; button.setAttribute('title', options.title); From 2f8abc0b0a994b92ee7c77f7fe5a14f5ee40eb93 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 17:09:25 -0400 Subject: [PATCH 20/59] Drop unused method --- src/events.ts | 4 ---- src/types/types.ts | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/events.ts b/src/events.ts index a203a097..edff102a 100644 --- a/src/events.ts +++ b/src/events.ts @@ -155,10 +155,6 @@ export default function(ctx: CTX) { } }, - zoomend: function() { - ctx.store.changeZoom(); - }, - data: function(event) { if (event.dataType === 'style') { const { setup, map, options, store } = ctx; diff --git a/src/types/types.ts b/src/types/types.ts index 40e9ffaa..d326c620 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -634,6 +634,7 @@ export interface DrawStoreOptions { interface DrawStore { ctx: CTX; isDirty: boolean; + setDirty(): this; render(): void; sources: { hot: [], From 9506e0848cbc501eaed26fea2d8fb6a65e7b9291 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 17:14:22 -0400 Subject: [PATCH 21/59] Bad typing for QRF --- src/lib/features_at.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index a77f53a8..70ca70ff 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -20,7 +20,7 @@ const featuresAt = (event: E, bbox: BBox, ctx: CTX, buffer: number) => { const box = event ? mapEventToBoundingBox(event, buffer) : bbox; const queryParams: { - layers?: Array; + layers?: Array; } = {}; if (ctx.options.styles) From 7a009689b5b7a8aad3900a022f7c44c429f5f1c8 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 17:49:19 -0400 Subject: [PATCH 22/59] Add argument signatures to mode interface and do not recast --- src/events.ts | 6 ++- src/modes/mode_interface.ts | 90 +++++++++++++------------------------ 2 files changed, 36 insertions(+), 60 deletions(-) diff --git a/src/events.ts b/src/events.ts index edff102a..2d90ae09 100644 --- a/src/events.ts +++ b/src/events.ts @@ -7,6 +7,10 @@ import * as Constants from './constants'; import { objectToMode } from './modes/object_to_mode'; import type { CTX, Entry } from './types/types'; +interface EventOptions { + silent?: boolean; +} + export default function(ctx: CTX) { const modes = Object.keys(ctx.options.modes).reduce((m, k) => { m[k] = objectToMode(ctx.options.modes[k]); @@ -168,7 +172,7 @@ export default function(ctx: CTX) { } }; - function changeMode(modename, nextModeOptions = {}, eventOptions = {}) { + function changeMode(modename, nextModeOptions = {}, eventOptions: EventOptions = {}) { currentMode.stop(); const modebuilder = modes[modename]; diff --git a/src/modes/mode_interface.ts b/src/modes/mode_interface.ts index 492b9574..aebd2ef0 100644 --- a/src/modes/mode_interface.ts +++ b/src/modes/mode_interface.ts @@ -1,64 +1,36 @@ import ModeInterfaceAcessors from './mode_interface_accessors.js'; -import type { DrawCustomMode } from '../types/types'; +import type { DrawCustomMode, StrictFeature } from '../types/types'; -class ModeInterface extends ModeInterfaceAcessors { +class ModeInterface extends ModeInterfaceAcessors implements DrawCustomMode { // Triggered while a mode is being transitioned into. - onSetup = function () {}; - - // Triggered when a drag event is detected on the map - onDrag = function () {}; - - // Triggered when the mouse is clicked - onClick = function () {}; - - // Triggered with the mouse is moved - onMouseMove = function () {}; - - // Triggered when the mouse button is pressed down - onMouseDown = function () {}; - - // Triggered when the mouse button is released - onMouseUp = function () {}; - - // Triggered when the mouse leaves the map's container - onMouseOut = function () {}; - - // Triggered when a key up event is detected - onKeyUp = function () {}; - - // Triggered when a key down event is detected - onKeyDown = function () {}; - - // Triggered when a touch event is started - onTouchStart = function () {}; - - // Triggered when one drags thier finger on a mobile device - onTouchMove = function () {}; - - // Triggered when one removes their finger from the map - onTouchEnd = function () {}; - - // Triggered when one quicly taps the map - onTap = function () {}; - - // Triggered when the mode is being exited, to be used for cleaning up artifacts such as invalid features - onStop = function () {}; - - // Triggered when [draw.trash()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#trash-draw) is called. - onTrash = function () {}; - - // Triggered when [draw.combineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#combinefeatures-draw) is called. - onCombineFeature = function () {}; - - // Triggered when [draw.uncombineFeatures()](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#uncombinefeatures-draw) is called. - onUncombineFeature = function () {}; - - // Triggered per feature on render to convert raw features into set of features for display on the map - // See [styling draw](https://github.com/mapbox/mapbox-gl-draw/blob/main/API.md#styling-draw) for information about what geojson properties Draw uses as part of rendering. - toDisplayFeatures = function () { - throw new Error('You must overwrite toDisplayFeatures'); - }; - + onSetup: (opts: any) => any = (opts) => {}; + + // Event Handlers + onDrag: (state: any, event: any) => void = (state, event) => {}; + onClick: (state: any, event: any) => void = (state, event) => {}; + onMouseMove: (state: any, event: any) => void = (state, event) => {}; + onMouseDown: (state: any, event: any) => void = (state, event) => {}; + onMouseUp: (state: any, event: any) => void = (state, event) => {}; + onMouseOut: (state: any, event: any) => void = (state, event) => {}; + onKeyUp: (state: any, event: any) => void = (state, event) => {}; + onKeyDown: (state: any, event: any) => void = (state, event) => {}; + onTouchStart: (state: any, event: any) => void = (state, event) => {}; + onTouchMove: (state: any, event: any) => void = (state, event) => {}; + onTouchEnd: (state: any, event: any) => void = (state, event) => {}; + onTap: (state: any, event: any) => void = (state, event) => {}; + + // Lifecycle Events + onStop: (state: any) => void = (state) => {}; + onTrash: (state: any) => void = (state) => {}; + onCombineFeatures: (state: any) => void = (state) => {}; + onUncombineFeatures: (state: any) => void = (state) => {}; + + // Converts raw features into display features + toDisplayFeatures: (state: any, geojson: StrictFeature, push: (feature: StrictFeature) => void) => void = + (state, geojson, push) => { + throw new Error('You must overwrite toDisplayFeatures'); + }; } -export default ModeInterface as unknown as DrawCustomMode; +export default ModeInterface; + From 1b4c52efcb8fbb25fbf2aef7272cd6b12af5dcf7 Mon Sep 17 00:00:00 2001 From: tristen Date: Thu, 13 Mar 2025 18:16:47 -0400 Subject: [PATCH 23/59] Walk back --- src/api.ts | 363 ++++++++++++++++++++++++++--------------------------- 1 file changed, 181 insertions(+), 182 deletions(-) diff --git a/src/api.ts b/src/api.ts index 2750c231..18dd63f0 100644 --- a/src/api.ts +++ b/src/api.ts @@ -23,6 +23,7 @@ const featureTypes = { }; export default function (ctx: CTX, api: Draw) { + api.modes = Constants.modes; // API doesn't emit events by default const silent = @@ -30,210 +31,208 @@ export default function (ctx: CTX, api: Draw) { ? !!ctx.options.suppressAPIEvents : true; - return { - modes: Constants.modes, - - getFeatureIdsAt: function (point) { - const features = featuresAt.click({ point }, null, ctx); - return features.map(feature => feature.properties.id); - }, - - getSelectedIds: function () { - return ctx.store.getSelectedIds(); - }, - - getSelected: function () { - return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store - .getSelectedIds() - .map(id => ctx.store.get(id)) - .map(feature => feature.toGeoJSON()) - }; - }, - - getSelectedPoints: function () { - return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store.getSelectedCoordinates().map(coordinate => ({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POINT, - coordinates: coordinate.coordinates - } - })) - }; - }, - - set: function (featureCollection) { - if ( - featureCollection.type === undefined || - featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || - !Array.isArray(featureCollection.features) - ) { - throw new Error('Invalid FeatureCollection'); - } - const renderBatch = ctx.store.createRenderBatch(); - let toDelete = ctx.store.getAllIds().slice(); - const newIds = api.add(featureCollection); - const newIdsLookup = new StringSet(newIds); - - toDelete = toDelete.filter(id => !newIdsLookup.has(id)); - if (toDelete.length) { - api.delete(toDelete); - } + api.getFeatureIdsAt = function (point) { + const features = featuresAt.click({ point }, null, ctx); + return features.map(feature => feature.properties.id); + }; + + api.getSelectedIds = function () { + return ctx.store.getSelectedIds(); + }; + + api.getSelected = function () { + return { + type: Constants.geojsonTypes.FEATURE_COLLECTION, + features: ctx.store + .getSelectedIds() + .map(id => ctx.store.get(id)) + .map(feature => feature.toGeoJSON()) + }; + }; + + api.getSelectedPoints = function () { + return { + type: Constants.geojsonTypes.FEATURE_COLLECTION, + features: ctx.store.getSelectedCoordinates().map(coordinate => ({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POINT, + coordinates: coordinate.coordinates + } + })) + }; + }; + + api.set = function (featureCollection) { + if ( + featureCollection.type === undefined || + featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || + !Array.isArray(featureCollection.features) + ) { + throw new Error('Invalid FeatureCollection'); + } + const renderBatch = ctx.store.createRenderBatch(); + let toDelete = ctx.store.getAllIds().slice(); + const newIds = api.add(featureCollection); + const newIdsLookup = new StringSet(newIds); + + toDelete = toDelete.filter(id => !newIdsLookup.has(id)); + if (toDelete.length) { + api.delete(toDelete); + } - renderBatch(); - return newIds; - }, + renderBatch(); + return newIds; + }; - add: function (geojson) { - const featureCollection = JSON.parse(JSON.stringify(normalize(geojson))); + api.add = function (geojson) { + const featureCollection = JSON.parse(JSON.stringify(normalize(geojson))); - const ids = featureCollection.features.map(feature => { - feature.id = feature.id || generateID(); + const ids = featureCollection.features.map(feature => { + feature.id = feature.id || generateID(); - if (feature.geometry === null) { - throw new Error('Invalid geometry: null'); - } + if (feature.geometry === null) { + throw new Error('Invalid geometry: null'); + } + if ( + ctx.store.get(feature.id) === undefined || + ctx.store.get(feature.id).type !== feature.geometry.type + ) { + // If the feature has not yet been created ... + const Model = featureTypes[feature.geometry.type]; + if (Model === undefined) { + throw new Error(`Invalid geometry type: ${feature.geometry.type}.`); + } + const internalFeature = new Model(ctx, feature); + ctx.store.add(internalFeature, { silent }); + } else { + // If a feature of that id has already been created, and we are swapping it out ... + const internalFeature = ctx.store.get(feature.id); + const originalProperties = internalFeature.properties; + internalFeature.properties = feature.properties; + if (!isEqual(originalProperties, feature.properties)) { + ctx.store.featureChanged(internalFeature.id, { silent }); + } if ( - ctx.store.get(feature.id) === undefined || - ctx.store.get(feature.id).type !== feature.geometry.type + !isEqual( + internalFeature.getCoordinates(), + feature.geometry.coordinates + ) ) { - // If the feature has not yet been created ... - const Model = featureTypes[feature.geometry.type]; - if (Model === undefined) { - throw new Error(`Invalid geometry type: ${feature.geometry.type}.`); - } - const internalFeature = new Model(ctx, feature); - ctx.store.add(internalFeature, { silent }); - } else { - // If a feature of that id has already been created, and we are swapping it out ... - const internalFeature = ctx.store.get(feature.id); - const originalProperties = internalFeature.properties; - internalFeature.properties = feature.properties; - if (!isEqual(originalProperties, feature.properties)) { - ctx.store.featureChanged(internalFeature.id, { silent }); - } - if ( - !isEqual( - internalFeature.getCoordinates(), - feature.geometry.coordinates - ) - ) { - internalFeature.incomingCoords(feature.geometry.coordinates); - } + internalFeature.incomingCoords(feature.geometry.coordinates); } - return feature.id; - }); + } + return feature.id; + }); + + ctx.store.render(); + return ids; + }; + api.get = function (id) { + const feature = ctx.store.get(id); + if (feature) { + return feature.toGeoJSON(); + } + }; + + api.getAll = function () { + return { + type: Constants.geojsonTypes.FEATURE_COLLECTION, + features: ctx.store.getAll().map(feature => feature.toGeoJSON()) + }; + }; + + api.delete = function (featureIds) { + ctx.store.delete(featureIds, { silent }); + // If we were in direct select mode and our selected feature no longer exists + // (because it was deleted), we need to get out of that mode. + if ( + api.getMode() === Constants.modes.DIRECT_SELECT && + !ctx.store.getSelectedIds().length + ) { + ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { + silent + }); + } else { ctx.store.render(); - return ids; - }, + } - get: function (id) { - const feature = ctx.store.get(id); - if (feature) { - return feature.toGeoJSON(); - } - }, - - getAll: function () { - return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store.getAll().map(feature => feature.toGeoJSON()) - }; - }, - - delete: function (featureIds) { - ctx.store.delete(featureIds, { silent }); - // If we were in direct select mode and our selected feature no longer exists - // (because it was deleted), we need to get out of that mode. - if ( - api.getMode() === Constants.modes.DIRECT_SELECT && - !ctx.store.getSelectedIds().length - ) { - ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { - silent - }); - } else { - ctx.store.render(); - } + return api; + }; - return api; - }, - - deleteAll: function () { - ctx.store.delete(ctx.store.getAllIds(), { silent }); - // If we were in direct select mode, now our selected feature no longer exists, - // so escape that mode. - if (api.getMode() === Constants.modes.DIRECT_SELECT) { - ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { - silent - }); - } else { - ctx.store.render(); - } + api.deleteAll = function () { + ctx.store.delete(ctx.store.getAllIds(), { silent }); + // If we were in direct select mode, now our selected feature no longer exists, + // so escape that mode. + if (api.getMode() === Constants.modes.DIRECT_SELECT) { + ctx.events.changeMode(Constants.modes.SIMPLE_SELECT, undefined, { + silent + }); + } else { + ctx.store.render(); + } - return api; - }, + return api; + }; - changeMode: function (mode, modeOptions = {}) { - // Avoid changing modes just to re-select what's already selected + api.changeMode = function (mode, modeOptions = {}) { + // Avoid changing modes just to re-select what's already selected + if ( + mode === Constants.modes.SIMPLE_SELECT && + api.getMode() === Constants.modes.SIMPLE_SELECT + ) { if ( - mode === Constants.modes.SIMPLE_SELECT && - api.getMode() === Constants.modes.SIMPLE_SELECT - ) { - if ( - stringSetsAreEqual( - modeOptions.featureIds || [], - ctx.store.getSelectedIds() - ) + stringSetsAreEqual( + modeOptions.featureIds || [], + ctx.store.getSelectedIds() ) - return api; - // And if we are changing the selection within simple_select mode, just change the selection, - // instead of stopping and re-starting the mode - ctx.store.setSelected(modeOptions.featureIds, { silent }); - ctx.store.render(); - return api; - } - - if ( - mode === Constants.modes.DIRECT_SELECT && - api.getMode() === Constants.modes.DIRECT_SELECT && - modeOptions.featureId === ctx.store.getSelectedIds()[0] - ) { + ) return api; - } + // And if we are changing the selection within simple_select mode, just change the selection, + // instead of stopping and re-starting the mode + ctx.store.setSelected(modeOptions.featureIds, { silent }); + ctx.store.render(); + return api; + } - ctx.events.changeMode(mode, modeOptions, { silent }); + if ( + mode === Constants.modes.DIRECT_SELECT && + api.getMode() === Constants.modes.DIRECT_SELECT && + modeOptions.featureId === ctx.store.getSelectedIds()[0] + ) { return api; - }, + } - getMode: function () { - return ctx.events.getMode(); - }, + ctx.events.changeMode(mode, modeOptions, { silent }); + return api; + }; - trash: function () { - ctx.events.trash({ silent }); - return api; - }, + api.getMode = function () { + return ctx.events.getMode(); + }; - combineFeatures: function () { - ctx.events.combineFeatures({ silent }); - return api; - }, + api.trash = function () { + ctx.events.trash({ silent }); + return api; + }; - uncombineFeatures: function () { - ctx.events.uncombineFeatures({ silent }); - return api; - }, + api.combineFeatures = function () { + ctx.events.combineFeatures({ silent }); + return api; + }; - setFeatureProperty: function (featureId, property, value) { - ctx.store.setFeatureProperty(featureId, property, value, { silent }); - return api; - } - } + api.uncombineFeatures = function () { + ctx.events.uncombineFeatures({ silent }); + return api; + }; + + api.setFeatureProperty = function (featureId, property, value) { + ctx.store.setFeatureProperty(featureId, property, value, { silent }); + return api; + }; + + return api; } From 2792160d7457a72b001000fd6a16a03fba7f0c45 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 12:29:14 -0400 Subject: [PATCH 24/59] Reduce the scope of this PR by skipping bench stuff --- bench/README.md | 3 +- bench/index.js | 41 +- bench/lib/evented.js | 1 + bench/lib/format_number.js | 4 +- bench/lib/fps.js | 4 +- bench/lib/mouse_drag.js | 17 +- bench/lib/mouse_draw.js | 4 +- bench/lib/mouse_events.js | 10 +- bench/lib/mouse_path.js | 10 +- bench/lib/mouse_trace.js | 5 +- bench/lib/trace_progress.js | 6 +- bench/rollup.config.js | 10 +- bench/tests/direct_select_large.js | 14 +- bench/tests/direct_select_large_zoomed.js | 14 +- bench/tests/direct_select_small.js | 10 +- bench/tests/direct_select_small_zoomed.js | 10 +- bench/tests/draw_land_polygon_large.js | 16 +- bench/tests/draw_land_polygon_small.js | 14 +- bench/tests/draw_line_string_large.js | 12 +- bench/tests/draw_line_string_large_zoomed.js | 12 +- bench/tests/draw_line_string_small.js | 10 +- bench/tests/draw_point_large.js | 16 +- bench/tests/draw_point_large_zoomed.js | 14 +- bench/tests/draw_point_small.js | 14 +- bench/tests/draw_polygon_large.js | 14 +- bench/tests/draw_polygon_large_zoomed.js | 14 +- bench/tests/draw_polygon_small.js | 12 +- bench/tests/draw_urban_areas_polygon_large.js | 18 +- bench/tests/draw_urban_areas_polygon_small.js | 16 +- bench/tests/simple_select_large.js | 14 +- bench/tests/simple_select_large_two_maps.js | 35 +- bench/tests/simple_select_large_zoomed.js | 14 +- bench/tests/simple_select_small.js | 8 +- package.json | 1 - src/modes/direct_select.ts | 487 +++++++++--------- 35 files changed, 436 insertions(+), 468 deletions(-) diff --git a/bench/README.md b/bench/README.md index a88b52ca..b014466b 100644 --- a/bench/README.md +++ b/bench/README.md @@ -1,5 +1,4 @@ -Benchmarks ---- +# Benchmarks Benchmarks help us catch performance regressions and improve performance. diff --git a/bench/index.js b/bench/index.js index 2c632f70..13ffa60d 100644 --- a/bench/index.js +++ b/bench/index.js @@ -35,7 +35,7 @@ function main() { draw_point_small: require('./tests/draw_point_small'), draw_point_large: require('./tests/draw_point_large'), - draw_point_large_zoomed: require('./tests/draw_point_large_zoomed') + draw_point_large_zoomed: require('./tests/draw_point_large_zoomed'), }; const benchmarkName = location.hash.substr(1); @@ -46,7 +46,7 @@ function main() { let innerHTML = ''; - tests.forEach(test => { + tests.forEach((test) => { innerHTML += '
'; innerHTML += `${test}`; innerHTML += '
'; @@ -59,10 +59,7 @@ function main() { window.addEventListener('hashchange', () => location.reload(), false); - log( - 'dark', - 'please keep this window in the foreground and close the debugger' - ); + log('dark', 'please keep this window in the foreground and close the debugger'); const Benchmark = benchmarks[benchmarkName]; if (!Benchmark) { @@ -75,30 +72,30 @@ function main() { createMap }); - bench.on('log', event => { + bench.on('log', (event) => { log(event.color || 'blue', event.message); }); - bench.on('pass', event => { + bench.on('pass', (event) => { log('green', `${event.message}`); }); - bench.on('fail', event => { + bench.on('fail', (event) => { log('red', `${event.message}`); }); } function log(color, message) { - document.getElementById('logs').innerHTML += - `

${message}

`; + document.getElementById('logs').innerHTML += `

${message}

`; } function getAccessToken() { - const accessToken = + const accessToken = ( process.env.MapboxAccessToken || - process.env.MAPBOX_ACCESS_TOKEN || - getURLParameter('access_token') || - localStorage.getItem('accessToken'); + process.env.MAPBOX_ACCESS_TOKEN || + getURLParameter('access_token') || + localStorage.getItem('accessToken') + ); localStorage.setItem('accessToken', accessToken); return accessToken; } @@ -112,7 +109,7 @@ function getURLParameter(name) { function createMap(options) { const mapElement = document.getElementById('map'); - options = Object.assign({ width: 512, height: 512 }, options); + options = Object.assign({width: 512, height: 512}, options); mapElement.style.display = 'block'; mapElement.style.width = `${options.width}px`; @@ -120,14 +117,10 @@ function createMap(options) { mapboxgl.accessToken = getAccessToken(); - const map = new mapboxgl.Map( - Object.assign( - { - container: 'map' - }, - options - ) - ); + const map = new mapboxgl.Map(Object.assign({ + container: 'map', + style: 'mapbox://styles/mapbox/streets-v12' + }, options)); const draw = new MapboxDraw(options); diff --git a/bench/lib/evented.js b/bench/lib/evented.js index a55abf16..3a69db51 100644 --- a/bench/lib/evented.js +++ b/bench/lib/evented.js @@ -1,3 +1,4 @@ + export default class Evented { on(type, listener) { if (!listener) { diff --git a/bench/lib/format_number.js b/bench/lib/format_number.js index e77f91a1..40846715 100644 --- a/bench/lib/format_number.js +++ b/bench/lib/format_number.js @@ -1,7 +1,5 @@ 'use strict'; export default function formatNumber(x) { - return Math.round(x) - .toString() - .replace(/\B(?=(\d{3})+(?!\d))/g, ','); + return Math.round(x).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } diff --git a/bench/lib/fps.js b/bench/lib/fps.js index de62794b..948c7890 100644 --- a/bench/lib/fps.js +++ b/bench/lib/fps.js @@ -1,9 +1,9 @@ -export default function () { +export default function() { let frameCount = 0; let start = null; let running = false; - const frameCounter = function () { + const frameCounter = function() { if (running) { frameCount++; requestAnimationFrame(frameCounter); diff --git a/bench/lib/mouse_drag.js b/bench/lib/mouse_drag.js index ae7010f2..5f2a4faa 100644 --- a/bench/lib/mouse_drag.js +++ b/bench/lib/mouse_drag.js @@ -1,18 +1,15 @@ import mouseEvents from './mouse_events'; import mousePath from './mouse_path'; -export default function (start, map) { +export default function(start, map) { + const path = mousePath(start); const events = mouseEvents(map); - events.push( - 'mousedown', - { - x: start.x, - y: start.y - }, - true - ); + events.push('mousedown', { + x: start.x, + y: start.y + }, true); for (let i = 0; i < path.length; i++) { events.push('mousemove', path[i]); @@ -26,7 +23,7 @@ export default function (start, map) { y: start.y }); - return function (cb) { + return function(cb) { events.run(cb); }; } diff --git a/bench/lib/mouse_draw.js b/bench/lib/mouse_draw.js index 0a088cdc..4ebbc7b6 100644 --- a/bench/lib/mouse_draw.js +++ b/bench/lib/mouse_draw.js @@ -1,7 +1,7 @@ import mouseEvents from './mouse_events'; import mousePath from './mouse_path'; -export default function (start, map) { +export default function(start, map) { const path = mousePath(start); const events = mouseEvents(map); @@ -24,7 +24,7 @@ export default function (start, map) { events.push('mouseup', path[path.length - 1]); - return function (cb) { + return function(cb) { events.run(cb); }; } diff --git a/bench/lib/mouse_events.js b/bench/lib/mouse_events.js index 294aa780..850576a4 100644 --- a/bench/lib/mouse_events.js +++ b/bench/lib/mouse_events.js @@ -1,7 +1,7 @@ -export default function (map) { +export default function(map) { const events = []; - events.push = function (event, point, dp) { + events.push = function(event, point, dp) { const payload = { dropPoint: dp === undefined ? false : dp, originalEvent: { @@ -14,15 +14,15 @@ export default function (map) { events[events.length] = [event, payload]; }; - events.run = function (cb) { + events.run = function(cb) { const one = 100 / events.length; - const runner = function (i) { + const runner = function(i) { const event = events[i]; if (event === undefined) { cb(); } else { map.fire(event[0], event[1]); - map.fire('progress', { done: Math.ceil(one * i) }); + map.fire('progress', {done:Math.ceil(one * i)}); setTimeout(() => { runner(i + 1); }, 0); diff --git a/bench/lib/mouse_path.js b/bench/lib/mouse_path.js index 3b22b132..057d8414 100644 --- a/bench/lib/mouse_path.js +++ b/bench/lib/mouse_path.js @@ -1,15 +1,15 @@ -export default function (start) { +export default function(start) { const path = []; - for (let i = 0; i < 7; i += 0.04) { + for (let i = 0; i < 7; i += .04) { const A = 3; const B = Math.PI / 2; const SIZE = 100; const OFFSET = 5; - const x = start.x + Math.sin(i) * SIZE + i * OFFSET; - const y = start.y + Math.sin(A * i + B) * SIZE + i * OFFSET; - path.push({ x, y }); + const x = start.x + (Math.sin(i) * SIZE) + (i * OFFSET); + const y = start.y + (Math.sin(A * i + B) * SIZE) + (i * OFFSET); + path.push({x, y}); } return path; diff --git a/bench/lib/mouse_trace.js b/bench/lib/mouse_trace.js index 9947840d..eddfb4a5 100644 --- a/bench/lib/mouse_trace.js +++ b/bench/lib/mouse_trace.js @@ -1,6 +1,7 @@ import mouseEvents from './mouse_events'; -export default function (ring, map) { +export default function(ring, map) { + const events = mouseEvents(map); let lastPoint = null; @@ -23,7 +24,7 @@ export default function (ring, map) { events.push('mouseup', lastPoint); } - return function (cb) { + return function(cb) { events.run(cb); }; } diff --git a/bench/lib/trace_progress.js b/bench/lib/trace_progress.js index c70a5b8f..16ae271c 100644 --- a/bench/lib/trace_progress.js +++ b/bench/lib/trace_progress.js @@ -1,4 +1,4 @@ -export default function (features, map) { +export default function(features, map) { const sizes = []; let total = 0; for (const feature of features) { @@ -18,7 +18,7 @@ export default function (features, map) { let pos = 0; let lastDone = -1; - map.on('progress', e => { + map.on('progress', (e) => { if (e.done < lastDone) { pos++; } @@ -27,7 +27,7 @@ export default function (features, map) { for (let i = 0; i < pos; i++) { done += sizes[i]; } - done += (sizes[pos] * e.done) / 100; + done += (sizes[pos] * e.done / 100); progressDiv.style.width = `${done}%`; }); } diff --git a/bench/rollup.config.js b/bench/rollup.config.js index 0d1561ca..8bc945ac 100644 --- a/bench/rollup.config.js +++ b/bench/rollup.config.js @@ -15,12 +15,8 @@ export default { plugins: [ json(), replace({ - 'process.env.MapboxAccessToken': JSON.stringify( - process.env.MapboxAccessToken - ), - 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify( - process.env.MAPBOX_ACCESS_TOKEN - ), + 'process.env.MapboxAccessToken': JSON.stringify(process.env.MapboxAccessToken), + 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN), preventAssignment: true }), resolve({ @@ -32,5 +28,5 @@ export default { // https://github.com/mapbox/mapbox-gl-js/pull/6956 ignoreGlobal: true }) - ] + ], }; diff --git a/bench/tests/direct_select_large.js b/bench/tests/direct_select_large.js index ca5f4b41..6f98ccf0 100644 --- a/bench/tests/direct_select_large.js +++ b/bench/tests/direct_select_large.js @@ -6,19 +6,19 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = { x: 445, y: 293 }; +const START = {x: 445, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width: 1024}); // eslint-disable-next-line new-cap const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -27,17 +27,15 @@ export default class Benchmark extends Evented { out.draw.changeMode('direct_select', { featureId: SouthAmerica.id }); setTimeout(() => { - this.fire('log', { message: 'normal - 41fps' }); + this.fire('log', {message: 'normal - 41fps'}); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); diff --git a/bench/tests/direct_select_large_zoomed.js b/bench/tests/direct_select_large_zoomed.js index d31243bc..74ddfa7b 100644 --- a/bench/tests/direct_select_large_zoomed.js +++ b/bench/tests/direct_select_large_zoomed.js @@ -6,14 +6,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = { x: 339, y: 282 }; +const START = {x: 339, y: 282}; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width: 1024, + width:1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -22,7 +22,7 @@ export default class Benchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -31,17 +31,15 @@ export default class Benchmark extends Evented { out.draw.changeMode('direct_select', { featureId: SouthAmerica.id }); setTimeout(() => { - this.fire('log', { message: 'normal - 26fps' }); + this.fire('log', {message: 'normal - 26fps'}); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); diff --git a/bench/tests/direct_select_small.js b/bench/tests/direct_select_small.js index a4866019..11317ac4 100644 --- a/bench/tests/direct_select_small.js +++ b/bench/tests/direct_select_small.js @@ -6,7 +6,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { @@ -18,7 +18,7 @@ export default class Benchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -32,11 +32,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); diff --git a/bench/tests/direct_select_small_zoomed.js b/bench/tests/direct_select_small_zoomed.js index 1e73db6a..ce5baa3d 100644 --- a/bench/tests/direct_select_small_zoomed.js +++ b/bench/tests/direct_select_small_zoomed.js @@ -6,7 +6,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DragMouse from '../lib/mouse_drag'; -const START = { x: 85, y: 282 }; +const START = {x: 85, y: 282}; export default class Benchmark extends Evented { constructor(options) { @@ -21,7 +21,7 @@ export default class Benchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -35,11 +35,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); diff --git a/bench/tests/draw_land_polygon_large.js b/bench/tests/draw_land_polygon_large.js index 9d4ac1a7..619cda7c 100644 --- a/bench/tests/draw_land_polygon_large.js +++ b/bench/tests/draw_land_polygon_large.js @@ -11,11 +11,11 @@ export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width:1024}); const drawing = []; - land.features.forEach(feature => { - feature.geometry.coordinates.forEach(ring => { + land.features.forEach((feature) => { + feature.geometry.coordinates.forEach((ring) => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function (cb) { - const runner = function (count) { + const traceMouse = function(cb) { + const runner = function(count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,11 +45,9 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_land_polygon_small.js b/bench/tests/draw_land_polygon_small.js index 9b626b1a..5d287ba9 100644 --- a/bench/tests/draw_land_polygon_small.js +++ b/bench/tests/draw_land_polygon_small.js @@ -14,8 +14,8 @@ export default class Benchmark extends Evented { const out = options.createMap(); const drawing = []; - land.features.forEach(feature => { - feature.geometry.coordinates.forEach(ring => { + land.features.forEach((feature) => { + feature.geometry.coordinates.forEach((ring) => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function (cb) { - const runner = function (count) { + const traceMouse = function(cb) { + const runner = function(count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,11 +45,9 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_line_string_large.js b/bench/tests/draw_line_string_large.js index 4c30fcff..a33a2c39 100644 --- a/bench/tests/draw_line_string_large.js +++ b/bench/tests/draw_line_string_large.js @@ -5,19 +5,19 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width:1024}); // eslint-disable-next-line new-cap const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -30,11 +30,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_line_string_large_zoomed.js b/bench/tests/draw_line_string_large_zoomed.js index 8be6c258..f8b8a7b1 100644 --- a/bench/tests/draw_line_string_large_zoomed.js +++ b/bench/tests/draw_line_string_large_zoomed.js @@ -5,14 +5,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width: 1024, + width:1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -21,7 +21,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -34,11 +34,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_line_string_small.js b/bench/tests/draw_line_string_small.js index 323d6ca4..26101255 100644 --- a/bench/tests/draw_line_string_small.js +++ b/bench/tests/draw_line_string_small.js @@ -5,7 +5,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { @@ -17,7 +17,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -30,11 +30,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_point_large.js b/bench/tests/draw_point_large.js index b7d97566..3ffa75c7 100644 --- a/bench/tests/draw_point_large.js +++ b/bench/tests/draw_point_large.js @@ -5,24 +5,24 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width:1024}); // eslint-disable-next-line new-cap const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); out.map.on('load', () => { - out.map.on('draw.modechange', e => { + out.map.on('draw.modechange', (e) => { if (e.mode === 'simple_select') { out.draw.changeMode('draw_point'); } @@ -35,11 +35,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -47,3 +45,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/draw_point_large_zoomed.js b/bench/tests/draw_point_large_zoomed.js index eaacc46f..afe6dd0c 100644 --- a/bench/tests/draw_point_large_zoomed.js +++ b/bench/tests/draw_point_large_zoomed.js @@ -5,14 +5,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width: 1024, + width:1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -21,12 +21,12 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); out.map.on('load', () => { - out.map.on('draw.modechange', e => { + out.map.on('draw.modechange', (e) => { if (e.mode === 'simple_select') { out.draw.changeMode('draw_point'); } @@ -39,11 +39,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); diff --git a/bench/tests/draw_point_small.js b/bench/tests/draw_point_small.js index c696d866..b609a510 100644 --- a/bench/tests/draw_point_small.js +++ b/bench/tests/draw_point_small.js @@ -5,7 +5,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { @@ -17,12 +17,12 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); out.map.on('load', () => { - out.map.on('draw.modechange', e => { + out.map.on('draw.modechange', (e) => { if (e.mode === 'simple_select') { out.draw.changeMode('draw_point'); } @@ -35,11 +35,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -47,3 +45,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/draw_polygon_large.js b/bench/tests/draw_polygon_large.js index 0da51f55..f8853128 100644 --- a/bench/tests/draw_polygon_large.js +++ b/bench/tests/draw_polygon_large.js @@ -5,19 +5,19 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width:1024}); // eslint-disable-next-line new-cap const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -30,11 +30,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -42,3 +40,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/draw_polygon_large_zoomed.js b/bench/tests/draw_polygon_large_zoomed.js index b4f2ead1..b24eca41 100644 --- a/bench/tests/draw_polygon_large_zoomed.js +++ b/bench/tests/draw_polygon_large_zoomed.js @@ -5,14 +5,14 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { super(); const out = options.createMap({ - width: 1024, + width:1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -21,7 +21,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -34,11 +34,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -46,3 +44,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/draw_polygon_small.js b/bench/tests/draw_polygon_small.js index de767cae..cafb5f5d 100644 --- a/bench/tests/draw_polygon_small.js +++ b/bench/tests/draw_polygon_small.js @@ -5,7 +5,7 @@ import formatNumber from '../lib/format_number'; import fpsRunner from '../lib/fps'; import DrawMouse from '../lib/mouse_draw'; -const START = { x: 189, y: 293 }; +const START = {x: 189, y: 293}; export default class Benchmark extends Evented { constructor(options) { @@ -17,7 +17,7 @@ export default class Benchmark extends Evented { const dragMouse = DrawMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -30,11 +30,9 @@ export default class Benchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -42,3 +40,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/draw_urban_areas_polygon_large.js b/bench/tests/draw_urban_areas_polygon_large.js index e4a9b84a..6b5c74d0 100644 --- a/bench/tests/draw_urban_areas_polygon_large.js +++ b/bench/tests/draw_urban_areas_polygon_large.js @@ -11,11 +11,11 @@ export default class Benchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width:1024}); const drawing = []; - land.features.forEach(feature => { - feature.geometry.coordinates.forEach(ring => { + land.features.forEach((feature) => { + feature.geometry.coordinates.forEach((ring) => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function (cb) { - const runner = function (count) { + const traceMouse = function(cb) { + const runner = function(count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,11 +45,9 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -57,3 +55,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/draw_urban_areas_polygon_small.js b/bench/tests/draw_urban_areas_polygon_small.js index 9ed5d73e..6ad92374 100644 --- a/bench/tests/draw_urban_areas_polygon_small.js +++ b/bench/tests/draw_urban_areas_polygon_small.js @@ -14,8 +14,8 @@ export default class Benchmark extends Evented { const out = options.createMap(); const drawing = []; - land.features.forEach(feature => { - feature.geometry.coordinates.forEach(ring => { + land.features.forEach((feature) => { + feature.geometry.coordinates.forEach((ring) => { // eslint-disable-next-line new-cap drawing.push(TraceMouse(ring, out.map)); }); @@ -23,8 +23,8 @@ export default class Benchmark extends Evented { traceProgress(land.features, out.map); - const traceMouse = function (cb) { - const runner = function (count) { + const traceMouse = function(cb) { + const runner = function(count) { const draw = drawing[count]; if (draw) { out.draw.changeMode('draw_polygon'); @@ -45,11 +45,9 @@ export default class Benchmark extends Evented { traceMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } out.draw.changeMode('simple_select'); }); @@ -57,3 +55,5 @@ export default class Benchmark extends Evented { }); } } + + diff --git a/bench/tests/simple_select_large.js b/bench/tests/simple_select_large.js index 22f80fb6..0d4a63f3 100644 --- a/bench/tests/simple_select_large.js +++ b/bench/tests/simple_select_large.js @@ -14,10 +14,10 @@ const START = { export default class SimpleSelectLargeBenchmark extends Evented { constructor(options) { super(); - const out = options.createMap({ width: 1024 }); + const out = options.createMap({width:1024}); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -28,20 +28,20 @@ export default class SimpleSelectLargeBenchmark extends Evented { out.draw.add(SouthAmerica); setTimeout(() => { - this.fire('log', { message: 'normal - 43fps' }); + this.fire('log', {message: 'normal - 43fps'}); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); }); } } + + diff --git a/bench/tests/simple_select_large_two_maps.js b/bench/tests/simple_select_large_two_maps.js index ef3c1c50..16ad2c51 100644 --- a/bench/tests/simple_select_large_two_maps.js +++ b/bench/tests/simple_select_large_two_maps.js @@ -12,25 +12,28 @@ const START = { }; const emptyStyle = { - version: 8, - name: 'Empty', - center: [0, -1.1368683772161603e-13], - zoom: 0.4051413497691584, - bearing: 0, - pitch: 0, - sources: {}, - layers: [] + "version": 8, + "name": "Empty", + "center": [ + 0, + -1.1368683772161603e-13 + ], + "zoom": 0.4051413497691584, + "bearing": 0, + "pitch": 0, + "sources": {}, + "layers": [], }; export default class SimpleSelectLargeTwoMapsBenchmark extends Evented { constructor(options) { super(); // eslint-disable-next-line no-unused-vars - const background = options.createMap({ container: 'backmap', width: 1024 }); - const out = options.createMap({ width: 1024, style: emptyStyle }); + const background = options.createMap({'container': 'backmap', width:1024}); + const out = options.createMap({width: 1024, style: emptyStyle}); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -41,20 +44,20 @@ export default class SimpleSelectLargeTwoMapsBenchmark extends Evented { out.draw.add(SouthAmerica); setTimeout(() => { - this.fire('log', { message: 'normal - 43fps' }); + this.fire('log', {message: 'normal - 43fps'}); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); }); } } + + diff --git a/bench/tests/simple_select_large_zoomed.js b/bench/tests/simple_select_large_zoomed.js index 59c194bb..12cc8e96 100644 --- a/bench/tests/simple_select_large_zoomed.js +++ b/bench/tests/simple_select_large_zoomed.js @@ -16,7 +16,7 @@ export default class SimpleSelectLargeZoomedBenchmark extends Evented { super(); const out = options.createMap({ - width: 1024, + width:1024, center: [-75.5597469696618, -2.6084634090944974], zoom: 5 }); @@ -25,7 +25,7 @@ export default class SimpleSelectLargeZoomedBenchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -33,20 +33,20 @@ export default class SimpleSelectLargeZoomedBenchmark extends Evented { out.draw.add(SouthAmerica); setTimeout(() => { - this.fire('log', { message: 'normal - 29fps' }); + this.fire('log', {message: 'normal - 29fps'}); const FPSControl = fpsRunner(); FPSControl.start(); dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); }); } } + + diff --git a/bench/tests/simple_select_small.js b/bench/tests/simple_select_small.js index 92fe358d..1f361c7c 100644 --- a/bench/tests/simple_select_small.js +++ b/bench/tests/simple_select_small.js @@ -20,7 +20,7 @@ export default class SimpleSelectSmallBenchmark extends Evented { const dragMouse = DragMouse(START, out.map); const progressDiv = document.getElementById('progress'); - out.map.on('progress', e => { + out.map.on('progress', (e) => { progressDiv.style.width = `${e.done}%`; }); @@ -33,11 +33,9 @@ export default class SimpleSelectSmallBenchmark extends Evented { dragMouse(() => { const fps = FPSControl.stop(); if (fps < 55) { - this.fire('fail', { - message: `${formatNumber(fps)} fps - expected 55fps or better` - }); + this.fire('fail', {message: `${formatNumber(fps)} fps - expected 55fps or better`}); } else { - this.fire('pass', { message: `${formatNumber(fps)} fps` }); + this.fire('pass', {message: `${formatNumber(fps)} fps`}); } }); }, 2000); diff --git a/package.json b/package.json index 59ed25d8..b3a5696b 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "start-server": "vite --config vite.config.js", "start-bench": "run-p build-token watch watch-bench \"start-server --base . .\"", "start": "run-p build-token start-server", - "format": "prettier --write '**/*.{js,ts,css}'", "prepare": "husky" }, "devDependencies": { diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 7affb1a5..77ac1ffa 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,277 +11,280 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { SelectedDrawModeFeature } from '../types/types'; +import type { CTX, DrawCustomMode } from '../types/types'; +import type { MapMouseEvent } from 'mapbox-gl'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); -interface State { - featureId: string; - canDragMove: boolean; - dragMoveLocation: null; - dragMoving: boolean; - feature: SelectedDrawModeFeature; - initialDragPanState?: null; - selectedCoordPaths: [][]; +interface DirectSelectMode extends DrawCustomMode { + fireUpdate(): void; + clickInactive(): void; + fireActionable(state: CTX): void; + clickNoTarget(state: CTX, e: MapMouseEvent): void; + startDragging(state: CTX, e: MapMouseEvent): void; } -const DirectSelect = { - clickInactive: function () { - this.changeMode(Constants.modes.SIMPLE_SELECT); - }, - - // INTERNAL FUNCTIONS - fireUpdate: function () { - this.fire(Constants.events.UPDATE, { - action: Constants.updateActions.CHANGE_COORDINATES, - features: this.getSelected().map(f => f.toGeoJSON()) - }); - }, - - fireActionable: function (state: State) { - this.setActionableState({ - combineFeatures: false, - uncombineFeatures: false, - trash: state.selectedCoordPaths.length > 0 - }); - }, - - startDragging: function (state: State, e) { - if (state.initialDragPanState == null) { - state.initialDragPanState = this.map.dragPan.isEnabled(); - } +const DirectSelect: DirectSelectMode = {}; - this.map.dragPan.disable(); - state.canDragMove = true; - state.dragMoveLocation = e.lngLat; - }, +// INTERNAL FUNCTIONS - stopDragging: function (state: State) { - if (state.canDragMove && state.initialDragPanState === true) { - this.map.dragPan.enable(); - } +DirectSelect.fireUpdate = function () { + this.fire(Constants.events.UPDATE, { + action: Constants.updateActions.CHANGE_COORDINATES, + features: this.getSelected().map(f => f.toGeoJSON()) + }); +}; - state.initialDragPanState = null; - state.dragMoving = false; - state.canDragMove = false; - state.dragMoveLocation = null; - }, - - onVertex: function (state: State, e) { - this.startDragging(state, e); - const about = e.featureTarget.properties; - const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); - if (!isShiftDown(e) && selectedIndex === -1) { - state.selectedCoordPaths = [about.coord_path]; - } else if (isShiftDown(e) && selectedIndex === -1) { - state.selectedCoordPaths.push(about.coord_path); - } +DirectSelect.fireActionable = function (state) { + this.setActionableState({ + combineFeatures: false, + uncombineFeatures: false, + trash: state.selectedCoordPaths.length > 0 + }); +}; - const selectedCoordinates = this.pathsToCoordinates( - state.featureId, - state.selectedCoordPaths - ); - this.setSelectedCoordinates(selectedCoordinates); - }, +DirectSelect.startDragging = function (state, e) { + if (state.initialDragPanState == null) { + state.initialDragPanState = this.map.dragPan.isEnabled(); + } - onMidpoint: function (state: State, e) { - this.startDragging(state, e); - const about = e.featureTarget.properties; - state.feature.addCoordinate(about.coord_path, about.lng, about.lat); - this.fireUpdate(); + this.map.dragPan.disable(); + state.canDragMove = true; + state.dragMoveLocation = e.lngLat; +}; + +DirectSelect.stopDragging = function (state) { + if (state.canDragMove && state.initialDragPanState === true) { + this.map.dragPan.enable(); + } + + state.initialDragPanState = null; + state.dragMoving = false; + state.canDragMove = false; + state.dragMoveLocation = null; +}; + +DirectSelect.onVertex = function (state, e) { + this.startDragging(state, e); + const about = e.featureTarget.properties; + const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); + if (!isShiftDown(e) && selectedIndex === -1) { state.selectedCoordPaths = [about.coord_path]; - }, + } else if (isShiftDown(e) && selectedIndex === -1) { + state.selectedCoordPaths.push(about.coord_path); + } - pathsToCoordinates: function (featureId, paths) { - return paths.map(coord_path => ({ feature_id: featureId, coord_path })); - }, + const selectedCoordinates = this.pathsToCoordinates( + state.featureId, + state.selectedCoordPaths + ); + this.setSelectedCoordinates(selectedCoordinates); +}; - onFeature: function (state: State, e) { - if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); - else this.stopDragging(state); - }, +DirectSelect.onMidpoint = function (state, e) { + this.startDragging(state, e); + const about = e.featureTarget.properties; + state.feature.addCoordinate(about.coord_path, about.lng, about.lat); + this.fireUpdate(); + state.selectedCoordPaths = [about.coord_path]; +}; - dragFeature: function (state: State, e, delta) { - moveFeatures(this.getSelected(), delta); - state.dragMoveLocation = e.lngLat; - }, +DirectSelect.pathsToCoordinates = function (featureId, paths) { + return paths.map(coord_path => ({ feature_id: featureId, coord_path })); +}; - dragVertex: function (state: State, e, delta) { - const selectedCoords = state.selectedCoordPaths.map(coord_path => - state.feature.getCoordinate(coord_path) - ); - const selectedCoordPoints = selectedCoords.map(coords => ({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POINT, - coordinates: coords - } - })); - - const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); - for (let i = 0; i < selectedCoords.length; i++) { - const coord = selectedCoords[i]; - state.feature.updateCoordinate( - state.selectedCoordPaths[i], - coord[0] + constrainedDelta.lng, - coord[1] + constrainedDelta.lat - ); +DirectSelect.onFeature = function (state, e) { + if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); + else this.stopDragging(state); +}; + +DirectSelect.dragFeature = function (state, e, delta) { + moveFeatures(this.getSelected(), delta); + state.dragMoveLocation = e.lngLat; +}; + +DirectSelect.dragVertex = function (state, e, delta) { + const selectedCoords = state.selectedCoordPaths.map(coord_path => + state.feature.getCoordinate(coord_path) + ); + const selectedCoordPoints = selectedCoords.map(coords => ({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POINT, + coordinates: coords } - }, + })); + + const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); + for (let i = 0; i < selectedCoords.length; i++) { + const coord = selectedCoords[i]; + state.feature.updateCoordinate( + state.selectedCoordPaths[i], + coord[0] + constrainedDelta.lng, + coord[1] + constrainedDelta.lat + ); + } +}; - clickNoTarget: function () { - this.changeMode(Constants.modes.SIMPLE_SELECT); - }, +DirectSelect.clickNoTarget = function () { + this.changeMode(Constants.modes.SIMPLE_SELECT); +}; - clickActiveFeature: function (state: State) { - state.selectedCoordPaths = []; - this.clearSelectedCoordinates(); - state.feature.changed(); - }, +DirectSelect.clickInactive = function () { + this.changeMode(Constants.modes.SIMPLE_SELECT); +} - // EXTERNAL FUNCTIONS - onSetup: function (opts) { - const featureId = opts.featureId; - const feature = this.getFeature(featureId); +DirectSelect.clickActiveFeature = function (state) { + state.selectedCoordPaths = []; + this.clearSelectedCoordinates(); + state.feature.changed(); +}; - if (!feature) { - throw new Error('You must provide a featureId to enter direct_select mode'); - } +// EXTERNAL FUNCTIONS - if (feature.type === Constants.geojsonTypes.POINT) { - throw new TypeError("direct_select mode doesn't handle point features"); - } +DirectSelect.onSetup = function (opts) { + const featureId = opts.featureId; + const feature = this.getFeature(featureId); - const state = { - featureId, - feature, - dragMoveLocation: opts.startPos || null, - dragMoving: false, - canDragMove: false, - selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] - }; - - this.setSelectedCoordinates( - this.pathsToCoordinates(featureId, state.selectedCoordPaths) - ); - this.setSelected(featureId); - doubleClickZoom.disable(this); + if (!feature) { + throw new Error('You must provide a featureId to enter direct_select mode'); + } - this.setActionableState({ - trash: true - }); + if (feature.type === Constants.geojsonTypes.POINT) { + throw new TypeError("direct_select mode doesn't handle point features"); + } - return state; - }, + const state = { + featureId, + feature, + dragMoveLocation: opts.startPos || null, + dragMoving: false, + canDragMove: false, + selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] + }; - onStop: function () { - doubleClickZoom.enable(this); - this.clearSelectedCoordinates(); - }, + this.setSelectedCoordinates( + this.pathsToCoordinates(featureId, state.selectedCoordPaths) + ); + this.setSelected(featureId); + doubleClickZoom.disable(this); - onTrash: function (state) { - // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them - // in reverse order so that we can remove by index safely. - state.selectedCoordPaths - .sort((a, b) => b.localeCompare(a, 'en', { numeric: true })) - .forEach(id => state.feature.removeCoordinate(id)); - this.fireUpdate(); - state.selectedCoordPaths = []; - this.clearSelectedCoordinates(); - this.fireActionable(state); - if (state.feature.isValid() === false) { - this.deleteFeature([state.featureId]); - this.changeMode(Constants.modes.SIMPLE_SELECT, {}); - } - }, - - onMouseMove: function (state, e) { - // On mousemove that is not a drag, stop vertex movement. - const isFeature = isActiveFeature(e); - const onVertex = isVertex(e); - const isMidPoint = isMidpoint(e); - const noCoords = state.selectedCoordPaths.length === 0; - if (isFeature && noCoords) - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else if (onVertex && !noCoords) - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else this.updateUIClasses({ mouse: Constants.cursors.NONE }); - - const isDraggableItem = onVertex || isFeature || isMidPoint; - if (isDraggableItem && state.dragMoving) this.fireUpdate(); - - this.stopDragging(state); - - // Skip render - return true; - }, - - onMouseOut: function (state) { - // As soon as you mouse leaves the canvas, update the feature - if (state.dragMoving) this.fireUpdate(); - - // Skip render - return true; - }, - - onTouchStart: function (state, e) { - if (isVertex(e)) return this.onVertex(state, e); - if (isActiveFeature(e)) return this.onFeature(state, e); - if (isMidpoint(e)) return this.onMidpoint(state, e); - }, - - onDrag: function (state, e) { - if (state.canDragMove !== true) return; - state.dragMoving = true; - e.originalEvent.stopPropagation(); - - const delta = { - lng: e.lngLat.lng - state.dragMoveLocation.lng, - lat: e.lngLat.lat - state.dragMoveLocation.lat - }; - if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta); - else this.dragFeature(state, e, delta); - - state.dragMoveLocation = e.lngLat; - }, - - _select: function (state, e) { - if (noTarget(e)) return this.clickNoTarget(state, e); - if (isActiveFeature(e)) return this.clickActiveFeature(state, e); - if (isInactiveFeature(e)) return this.clickInactive(state, e); - this.stopDragging(state); - }, - - _end: function (state) { - if (state.dragMoving) { - this.fireUpdate(); - } - this.stopDragging(state); - }, - - toDisplayFeatures: function (state: State, geojson, push) { - if (state.featureId === geojson.properties.id) { - geojson.properties.active = Constants.activeStates.ACTIVE; - push(geojson); - createSupplementaryPoints(geojson, { - map: this.map, - midpoints: true, - selectedPaths: state.selectedCoordPaths - }).forEach(push); - } else { - geojson.properties.active = Constants.activeStates.INACTIVE; - push(geojson); - } + this.setActionableState({ + trash: true + }); + + return state; +}; - this.fireActionable(state); - }, +DirectSelect.onStop = function () { + doubleClickZoom.enable(this); + this.clearSelectedCoordinates(); +}; + +DirectSelect.onTrash = function (state) { + // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them + // in reverse order so that we can remove by index safely. + state.selectedCoordPaths + .sort((a, b) => b.localeCompare(a, 'en', { numeric: true })) + .forEach(id => state.feature.removeCoordinate(id)); + this.fireUpdate(); + state.selectedCoordPaths = []; + this.clearSelectedCoordinates(); + this.fireActionable(state); + if (state.feature.isValid() === false) { + this.deleteFeature([state.featureId]); + this.changeMode(Constants.modes.SIMPLE_SELECT, {}); + } +}; + +DirectSelect.onMouseMove = function (state, e) { + // On mousemove that is not a drag, stop vertex movement. + const isFeature = isActiveFeature(e); + const onVertex = isVertex(e); + const isMidPoint = isMidpoint(e); + const noCoords = state.selectedCoordPaths.length === 0; + if (isFeature && noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else if (onVertex && !noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else this.updateUIClasses({ mouse: Constants.cursors.NONE }); + + const isDraggableItem = onVertex || isFeature || isMidPoint; + if (isDraggableItem && state.dragMoving) this.fireUpdate(); + + this.stopDragging(state); + + // Skip render + return true; +}; + +DirectSelect.onMouseOut = function (state) { + // As soon as you mouse leaves the canvas, update the feature + if (state.dragMoving) this.fireUpdate(); + + // Skip render + return true; +}; - onTap: function (state, e) { return this._select(state, e); }, - onClick: function (state, e) { return this._select(state, e); }, - onMouseUp: function (state) { return this._end(state); }, - onTouchEnd: function (state) { return this._end(state); } +DirectSelect.onTouchStart = DirectSelect.onMouseDown = function (state, e) { + if (isVertex(e)) return this.onVertex(state, e); + if (isActiveFeature(e)) return this.onFeature(state, e); + if (isMidpoint(e)) return this.onMidpoint(state, e); +}; + +DirectSelect.onDrag = function (state, e) { + if (state.canDragMove !== true) return; + state.dragMoving = true; + e.originalEvent.stopPropagation(); + + const delta = { + lng: e.lngLat.lng - state.dragMoveLocation.lng, + lat: e.lngLat.lat - state.dragMoveLocation.lat + }; + if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta); + else this.dragFeature(state, e, delta); + + state.dragMoveLocation = e.lngLat; +}; + +DirectSelect.onClick = function (state, e) { + if (noTarget(e)) return this.clickNoTarget(state, e); + if (isActiveFeature(e)) return this.clickActiveFeature(state, e); + if (isInactiveFeature(e)) return this.clickInactive(state, e); + this.stopDragging(state); +}; + +DirectSelect.onTap = function (state, e) { + if (noTarget(e)) return this.clickNoTarget(state, e); + if (isActiveFeature(e)) return this.clickActiveFeature(state, e); + if (isInactiveFeature(e)) return this.clickInactive(state, e); +}; + +DirectSelect.onTouchEnd = DirectSelect.onMouseUp = function (state) { + if (state.dragMoving) { + this.fireUpdate(); + } + this.stopDragging(state); +}; + +DirectSelect.toDisplayFeatures = function (state: DrawCTX, geojson, push) { + if (state.featureId === geojson.properties.id) { + geojson.properties.active = Constants.activeStates.ACTIVE; + push(geojson); + createSupplementaryPoints(geojson, { + map: this.map, + midpoints: true, + selectedPaths: state.selectedCoordPaths + }).forEach(push); + } else { + geojson.properties.active = Constants.activeStates.INACTIVE; + push(geojson); + } + + this.fireActionable(state); }; export default DirectSelect; + From 2e24ed1223853d3b32e4c78cabef288c1d4e361f Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 12:32:27 -0400 Subject: [PATCH 25/59] Reduce scope further --- build/generate-access-token-script.js | 22 ++++++------------ cloudformation/ci.template.js | 32 +++++++++++++++------------ debug/access_token.js | 2 +- debug/index.html | 19 +++++++++++----- docs/API.md | 3 +-- docs/EXAMPLES.md | 3 +-- docs/MODES.md | 3 +-- 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/build/generate-access-token-script.js b/build/generate-access-token-script.js index 42898404..22709381 100644 --- a/build/generate-access-token-script.js +++ b/build/generate-access-token-script.js @@ -1,21 +1,13 @@ import fs from 'fs'; import path from 'path'; -import { fileURLToPath } from 'url'; +import {fileURLToPath} from 'url'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); -const script = fs - .readFileSync(path.join(__dirname, '../debug/access_token.js'), 'utf-8') - .replace( - 'process.env.MapboxAccessToken', - JSON.stringify(process.env.MapboxAccessToken) - ) - .replace( - 'process.env.MAPBOX_ACCESS_TOKEN', - JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN) - ); +const script = fs.readFileSync(path.join(__dirname, '../debug/access_token.js'), 'utf-8') + .replace('process.env.MapboxAccessToken', + JSON.stringify(process.env.MapboxAccessToken)) + .replace('process.env.MAPBOX_ACCESS_TOKEN', + JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN)); -fs.writeFileSync( - path.join(__dirname, '../debug/access_token_generated.js'), - script -); +fs.writeFileSync(path.join(__dirname, '../debug/access_token_generated.js'), script); diff --git a/cloudformation/ci.template.js b/cloudformation/ci.template.js index 3d35b9c7..591201e6 100644 --- a/cloudformation/ci.template.js +++ b/cloudformation/ci.template.js @@ -7,13 +7,17 @@ module.exports = { Properties: { Policies: [ { - PolicyName: 'list', - PolicyDocument: { - Statement: [ + "PolicyName": "list", + "PolicyDocument": { + "Statement": [ { - Action: ['s3:ListBucket'], - Effect: 'Allow', - Resource: ['arn:aws:s3:::mapbox-gl-js'] + "Action": [ + "s3:ListBucket" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::mapbox-gl-js" + ] } ] } @@ -23,15 +27,15 @@ module.exports = { PolicyDocument: { Statement: [ { - Action: [ - 's3:GetObject', - 's3:GetObjectAcl', - 's3:PutObject', - 's3:PutObjectAcl' + "Action": [ + "s3:GetObject", + "s3:GetObjectAcl", + "s3:PutObject", + "s3:PutObjectAcl" ], - Effect: 'Allow', - Resource: [ - 'arn:aws:s3:::mapbox-gl-js/plugins/mapbox-gl-draw/*' + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::mapbox-gl-js/plugins/mapbox-gl-draw/*" ] } ] diff --git a/debug/access_token.js b/debug/access_token.js index d039d0fd..48c3f841 100644 --- a/debug/access_token.js +++ b/debug/access_token.js @@ -2,7 +2,7 @@ export function getAccessToken() { const accessToken = process.env.MapboxAccessToken || process.env.MAPBOX_ACCESS_TOKEN || - new URLSearchParams(location.search).get('access_token') || + (new URLSearchParams(location.search).get('access_token')) || localStorage.getItem('accessToken'); localStorage.setItem('accessToken', accessToken); diff --git a/debug/index.html b/debug/index.html index 319b8531..72f6d3dc 100644 --- a/debug/index.html +++ b/debug/index.html @@ -42,9 +42,10 @@ + - @@ -56,10 +57,10 @@ import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder'; import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css'; - import MapboxDraw from '../index'; + import MapboxDraw from '../index.js'; import '../dist/mapbox-gl-draw.css'; - import {getAccessToken} from './access_token_generated'; + import {getAccessToken} from './access_token_generated.js'; mapboxgl.accessToken = getAccessToken(); @@ -67,7 +68,6 @@ container: 'map', zoom: 1, center: [0, 0], - hash: true }); map.addControl(new MapboxGeocoder({ @@ -83,8 +83,6 @@ map.addControl(Draw, 'bottom-right'); map.on('load', () => { - map.setConfigProperty('basemap', 'theme', 'monochrome'); - // Add Draw to the map if it is inactive const addButton = document.getElementById('addBtn'); addButton.onclick = function () { @@ -101,6 +99,15 @@ map.removeControl(Draw); }; + // Toggle the style between dark and streets + const flipStyleButton = document.getElementById('flipStyleBtn'); + let currentStyle = 'streets-v9'; + flipStyleButton.onclick = function () { + const style = currentStyle === 'streets-v9' ? 'dark-v9' : 'streets-v9'; + map.setStyle(`mapbox://styles/mapbox/${style}`); + currentStyle = style; + }; + // toggle double click zoom const doubleClickZoom = document.getElementById('doubleClickZoom'); let doubleClickZoomOn = true; diff --git a/docs/API.md b/docs/API.md index 18ce5d1b..1010f0ed 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,5 +1,4 @@ -API Reference ---- +# API Reference To use Draw diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 8a4d384a..d35152c6 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -1,5 +1,4 @@ -Examples ---- +# Examples ## Styling diff --git a/docs/MODES.md b/docs/MODES.md index 3273e197..c48633c2 100644 --- a/docs/MODES.md +++ b/docs/MODES.md @@ -1,5 +1,4 @@ -Creating modes for Mapbox Draw ---- +# Creating modes for Mapbox Draw In Mapbox Draw, modes are used to group sets of user interactions into one behavior. Internally Draw has the `draw_polygon` mode, which controls a bunch of interactions for drawing a polygon. Draw also has the `simple_select` mode which controls interactions when zero, one or many features are selected including transitioning to `direct_select` mode when a user's interactions imply that they want to do detailed edits of a single feature. From d23d156aee0ac793675edc312cb8834f3ad2d118 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 13:46:41 -0400 Subject: [PATCH 26/59] Bad conditional --- src/feature_types/line_string.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index d9118652..420cf85d 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -32,10 +32,8 @@ class LineString extends Feature { updateCoordinate(path: string, lng: number, lat: number): void { const id = parseInt(path, 10); - if (this.coordinates[id]) { - this.coordinates[id] = [lng, lat]; - this.changed(); - } + this.coordinates[id] = [lng, lat]; + this.changed(); } changed(): void {} From 05cf5847fb7351e99bd063a7060bb328d1c8c5c4 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 14:24:24 -0400 Subject: [PATCH 27/59] Walk back on eslint stuff --- .eslintrc | 39 + package-lock.json | 1732 +++++++++++++++++++++++++++++++++++---------- package.json | 4 +- 3 files changed, 1402 insertions(+), 373 deletions(-) diff --git a/.eslintrc b/.eslintrc index 58422b7e..e0d07dbc 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,42 @@ { + "extends": [ + "mourner", + "plugin:import/recommended" + ], "parser": "@typescript-eslint/parser", + "plugins": [ + "import" + ], + "globals": { + "document": true + }, + "rules": { + "no-duplicate-imports": "off", + "import/no-duplicates": "error", + "import/no-commonjs": "error", + + "indent": [2,2], + "array-bracket-spacing": "off", + "block-scoped-var": "error", + "consistent-return": "off", + "global-require": "off", + "key-spacing": "off", + "no-eq-null": "off", + "no-new": "off", + "no-var": "error", + "no-warning-comments": "error", + "object-curly-spacing": "off", + "prefer-arrow-callback": "error", + "prefer-const": "error", + "prefer-template": "error", + "quotes": "off", + "space-before-function-paren": "off", + "template-curly-spacing": "error", + "camelcase": 0, + "no-console": ["error", { "allow": ["warn", "error"] }] + }, + "env": { + "es6": true, + "browser": true + } } diff --git a/package-lock.json b/package-lock.json index adf34bf8..f9547d2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,8 @@ "@types/geojson": "^7946.0.16", "@typescript-eslint/parser": "^8.26.0", "eslint": "8.57.1", + "eslint-config-mourner": "^4.0.2", + "eslint-plugin-import": "^2.31.0", "husky": "^9.1.7", "lint-staged": "^15.4.3", "mapbox-gl": "^3.10.0", @@ -1319,6 +1321,12 @@ "win32" ] }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -1375,6 +1383,72 @@ "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", "dev": true }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.13.0.tgz", + "integrity": "sha512-GPPDK4+fcbsQD58a3abbng2Dx+jBoxM5cnYjBM4T24WFZRZdlNSKvR19TxP8CPevzMOodQ9QVzNeqWvMXzfJRA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -1496,6 +1570,12 @@ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -1800,11 +1880,125 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-equal": { "version": "1.0.0", "dev": true, "license": "MIT" }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -1830,15 +2024,28 @@ "node": ">=0.8" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "dev": true, "license": "MIT" }, "node_modules/available-typed-arrays": { - "version": "1.0.5", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, - "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -2007,15 +2214,15 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, - "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -2024,10 +2231,31 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/call-bind/node_modules/function-bind": { - "version": "1.1.2", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, - "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2288,6 +2516,57 @@ "node": ">=0.10" } }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -2438,6 +2717,32 @@ "node": ">=0.3.1" } }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/earcut": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", @@ -2488,13 +2793,76 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-define-property": { - "version": "1.0.0", + "node_modules/es-abstract": { + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4" + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -2507,14 +2875,54 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-to-primitive": { - "version": "1.2.1", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, - "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -2684,8 +3092,116 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-scope": { - "version": "7.2.2", + "node_modules/eslint-config-mourner": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-mourner/-/eslint-config-mourner-4.0.2.tgz", + "integrity": "sha512-gaXR2jyDbu51PhUNQXuLZmyHYgFztdLfAz7EtfdmBXw0Ok97H6/39hKb1nLBwQa+8+QHXCCgqG8Sviu/Z5GSzQ==", + "dev": true, + "dependencies": { + "@eslint/js": "^9.6.0", + "@stylistic/eslint-plugin-js": "^2.3.0", + "globals": "^15.8.0" + } + }, + "node_modules/eslint-config-mourner/node_modules/@eslint/js": { + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", + "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3099,11 +3615,18 @@ "license": "ISC" }, "node_modules/for-each": { - "version": "0.3.3", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, - "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/forever-agent": { @@ -3146,14 +3669,39 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT" + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functions-have-names": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3184,15 +3732,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, - "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -3201,12 +3755,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-intrinsic/node_modules/function-bind": { - "version": "1.1.2", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/get-stream": { @@ -3225,12 +3784,14 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -3282,12 +3843,41 @@ "node": ">=10.13.0" } }, - "node_modules/gopd": { - "version": "1.0.1", + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3362,21 +3952,14 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-bigints": { - "version": "1.0.2", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, - "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3390,20 +3973,25 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, - "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -3412,9 +4000,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3423,11 +4012,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -3447,14 +4037,6 @@ "node": ">= 0.4" } }, - "node_modules/hasown/node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "dev": true, @@ -3617,6 +4199,20 @@ "dev": true, "license": "ISC" }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "dev": true, @@ -3632,29 +4228,70 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "dev": true, "license": "MIT" }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { - "version": "1.0.4", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, - "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3664,9 +4301,10 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3689,12 +4327,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { - "version": "1.0.5", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, - "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3711,6 +4368,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", @@ -3748,16 +4420,11 @@ "node": ">=0.10.0" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3765,6 +4432,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3775,11 +4448,13 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, - "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3815,12 +4490,15 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -3829,12 +4507,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3853,11 +4547,13 @@ } }, "node_modules/is-string": { - "version": "1.0.7", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, - "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3867,11 +4563,29 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, - "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -3885,17 +4599,55 @@ "dev": true, "license": "MIT" }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { - "version": "1.0.2", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "dev": true, @@ -3999,6 +4751,18 @@ "dev": true, "license": "ISC" }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsprim": { "version": "1.4.2", "dev": true, @@ -4398,6 +5162,15 @@ "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", "dev": true }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/memorystream": { "version": "0.3.1", "dev": true, @@ -4871,9 +5644,10 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4890,13 +5664,16 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -4906,6 +5683,56 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/once": { "version": "1.4.0", "dev": true, @@ -4964,6 +5791,23 @@ "node": ">= 0.8.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -5140,6 +5984,15 @@ "node": ">=4" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", @@ -5396,6 +6249,48 @@ "node": ">=4" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/request": { "version": "2.88.2", "dev": true, @@ -5610,6 +6505,25 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "dev": true, @@ -5629,6 +6543,39 @@ ], "license": "MIT" }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "dev": true, @@ -5639,6 +6586,15 @@ "dev": true, "license": "ISC" }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/serialize-to-js": { "version": "3.1.2", "dev": true, @@ -5663,23 +6619,33 @@ "node": ">= 0.4" } }, - "node_modules/set-function-length/node_modules/function-bind": { - "version": "1.1.2", + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/set-function-length/node_modules/has-property-descriptors": { - "version": "1.0.2", + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, - "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0" + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.4" } }, "node_modules/shebang-command": { @@ -5707,13 +6673,72 @@ "license": "MIT" }, "node_modules/side-channel": { - "version": "1.0.4", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5928,34 +6953,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.padend/node_modules/es-abstract": { - "version": "1.20.1", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5964,15 +6974,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.padend/node_modules/function.prototype.name": { - "version": "1.1.5", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -5981,27 +6992,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.padend/node_modules/internal-slot": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.padend/node_modules/regexp.prototype.flags": { - "version": "1.4.3", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -6010,32 +7009,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.padend/node_modules/string.prototype.trimend": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.padend/node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "dev": true, @@ -6233,6 +7206,18 @@ "typescript": ">=4.8.4" } }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6287,6 +7272,80 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", @@ -6310,14 +7369,18 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.2", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6358,151 +7421,6 @@ "which-typed-array": "^1.1.2" } }, - "node_modules/util/node_modules/es-abstract": { - "version": "1.20.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util/node_modules/function.prototype.name": { - "version": "1.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util/node_modules/internal-slot": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/util/node_modules/is-typed-array": { - "version": "1.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util/node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util/node_modules/string.prototype.trimend": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util/node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util/node_modules/which-typed-array": { - "version": "1.1.8", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/uuid": { "version": "8.0.0", "dev": true, @@ -6699,15 +7617,85 @@ } }, "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, - "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" diff --git a/package.json b/package.json index b3a5696b..19b2e10b 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,8 @@ "@types/geojson": "^7946.0.16", "@typescript-eslint/parser": "^8.26.0", "eslint": "8.57.1", + "eslint-config-mourner": "^4.0.2", + "eslint-plugin-import": "^2.31.0", "husky": "^9.1.7", "lint-staged": "^15.4.3", "mapbox-gl": "^3.10.0", @@ -90,7 +92,7 @@ "dist/mapbox-gl-draw*" ], "lint-staged": { - "**/*.{js,ts}": [ + "**/*.{ts}": [ "eslint", "prettier --write" ] From 3b48ac1f1aeb677c881b7ef1eaafa2e452e8c690 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 15:19:52 -0400 Subject: [PATCH 28/59] eslint changes --- .eslintrc | 4 - package-lock.json | 178 +++++++++--------------------------- package.json | 5 +- src/lib/common_selectors.ts | 10 +- 4 files changed, 48 insertions(+), 149 deletions(-) diff --git a/.eslintrc b/.eslintrc index e0d07dbc..70133296 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,8 +1,4 @@ { - "extends": [ - "mourner", - "plugin:import/recommended" - ], "parser": "@typescript-eslint/parser", "plugins": [ "import" diff --git a/package-lock.json b/package-lock.json index f9547d2f..057927a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,8 +28,7 @@ "@turf/centroid": "^7.0.0", "@types/geojson": "^7946.0.16", "@typescript-eslint/parser": "^8.26.0", - "eslint": "8.57.1", - "eslint-config-mourner": "^4.0.2", + "eslint": "^8.57.1", "eslint-plugin-import": "^2.31.0", "husky": "^9.1.7", "lint-staged": "^15.4.3", @@ -533,9 +532,10 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.8.1", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, - "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -587,15 +587,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -1383,72 +1374,6 @@ "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", "dev": true }, - "node_modules/@stylistic/eslint-plugin-js": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.13.0.tgz", - "integrity": "sha512-GPPDK4+fcbsQD58a3abbng2Dx+jBoxM5cnYjBM4T24WFZRZdlNSKvR19TxP8CPevzMOodQ9QVzNeqWvMXzfJRA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -1650,15 +1575,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz", - "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz", + "integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/typescript-estree": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4" }, "engines": { @@ -1674,13 +1599,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", - "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", + "integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0" + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1691,9 +1616,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz", - "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz", + "integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1704,13 +1629,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", - "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz", + "integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1766,12 +1691,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", - "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz", + "integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -3041,6 +2966,7 @@ "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -3092,26 +3018,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-mourner": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-mourner/-/eslint-config-mourner-4.0.2.tgz", - "integrity": "sha512-gaXR2jyDbu51PhUNQXuLZmyHYgFztdLfAz7EtfdmBXw0Ok97H6/39hKb1nLBwQa+8+QHXCCgqG8Sviu/Z5GSzQ==", - "dev": true, - "dependencies": { - "@eslint/js": "^9.6.0", - "@stylistic/eslint-plugin-js": "^2.3.0", - "globals": "^15.8.0" - } - }, - "node_modules/eslint-config-mourner/node_modules/@eslint/js": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", - "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -3226,6 +3132,15 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -3843,18 +3758,6 @@ "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/globalthis": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", @@ -4138,9 +4041,10 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.2.0", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } diff --git a/package.json b/package.json index 19b2e10b..76ffc063 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", - "lint": "eslint index.ts bench test", + "lint": "eslint src/**/*.ts test/**/*.ts", "pretest": "npm run lint", "test": "node --test --import ./test/mock-browser.js", "coverage": "node --test --import ./test/mock-browser.js --experimental-test-coverage", @@ -63,8 +63,7 @@ "@turf/centroid": "^7.0.0", "@types/geojson": "^7946.0.16", "@typescript-eslint/parser": "^8.26.0", - "eslint": "8.57.1", - "eslint-config-mourner": "^4.0.2", + "eslint": "^8.57.1", "eslint-plugin-import": "^2.31.0", "husky": "^9.1.7", "lint-staged": "^15.4.3", diff --git a/src/lib/common_selectors.ts b/src/lib/common_selectors.ts index 9841519b..d0d790ad 100644 --- a/src/lib/common_selectors.ts +++ b/src/lib/common_selectors.ts @@ -4,11 +4,11 @@ import { MapMouseEvent, MapTouchEvent } from '../types/types'; type E = MapMouseEvent | MapTouchEvent; export function isOfMetaType(type: string) { return function (e: E) { - const featureTarget = e.featureTarget; - if (!featureTarget) return false; - if (!featureTarget.properties) return false; - return featureTarget.properties.meta === type; - }; + const featureTarget = e.featureTarget; + if (!featureTarget) return false; + if (!featureTarget.properties) return false; + return featureTarget.properties.meta === type; +}; } export function isShiftMousedown(e: MapMouseEvent) { From 1c2bc4c2712cb6890d06fec21f2173fa1d6eafb0 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 17:19:57 -0400 Subject: [PATCH 29/59] Consistify direct select with object+property of other modes --- src/modes/direct_select.ts | 475 +++++++++++++++++++------------------ 1 file changed, 240 insertions(+), 235 deletions(-) diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 77ac1ffa..d2b16391 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,8 +11,7 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { CTX, DrawCustomMode } from '../types/types'; -import type { MapMouseEvent } from 'mapbox-gl'; +import type { CTX, DrawCustomMode, MapMouseEvent } from '../types/types'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); @@ -23,267 +22,273 @@ interface DirectSelectMode extends DrawCustomMode { fireActionable(state: CTX): void; clickNoTarget(state: CTX, e: MapMouseEvent): void; startDragging(state: CTX, e: MapMouseEvent): void; + stopDragging(state: CTX): void; + onVertex(state: CTX, e: MapMouseEvent): void; + onMidpoint(state: CTX, e: MapMouseEvent): void; } -const DirectSelect: DirectSelectMode = {}; - -// INTERNAL FUNCTIONS - -DirectSelect.fireUpdate = function () { - this.fire(Constants.events.UPDATE, { - action: Constants.updateActions.CHANGE_COORDINATES, - features: this.getSelected().map(f => f.toGeoJSON()) - }); -}; - -DirectSelect.fireActionable = function (state) { - this.setActionableState({ - combineFeatures: false, - uncombineFeatures: false, - trash: state.selectedCoordPaths.length > 0 - }); -}; +const DirectSelect: DirectSelectMode = { + + // INTERNAL FUNCTIONS + fireUpdate: function () { + this.fire(Constants.events.UPDATE, { + action: Constants.updateActions.CHANGE_COORDINATES, + features: this.getSelected().map(f => f.toGeoJSON()) + }); + }, + + fireActionable: function (state) { + this.setActionableState({ + combineFeatures: false, + uncombineFeatures: false, + trash: state.selectedCoordPaths.length > 0 + }); + }, + + startDragging: function (state, e) { + if (state.initialDragPanState == null) { + state.initialDragPanState = this.map.dragPan.isEnabled(); + } -DirectSelect.startDragging = function (state, e) { - if (state.initialDragPanState == null) { - state.initialDragPanState = this.map.dragPan.isEnabled(); - } + this.map.dragPan.disable(); + state.canDragMove = true; + state.dragMoveLocation = e.lngLat; + }, - this.map.dragPan.disable(); - state.canDragMove = true; - state.dragMoveLocation = e.lngLat; -}; + stopDragging: function (state) { + if (state.canDragMove && state.initialDragPanState === true) { + this.map.dragPan.enable(); + } -DirectSelect.stopDragging = function (state) { - if (state.canDragMove && state.initialDragPanState === true) { - this.map.dragPan.enable(); - } + state.initialDragPanState = null; + state.dragMoving = false; + state.canDragMove = false; + state.dragMoveLocation = null; + }, + + onVertex: function (state, e) { + this.startDragging(state, e); + const about = e.featureTarget.properties; + const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); + if (!isShiftDown(e) && selectedIndex === -1) { + state.selectedCoordPaths = [about.coord_path]; + } else if (isShiftDown(e) && selectedIndex === -1) { + state.selectedCoordPaths.push(about.coord_path); + } - state.initialDragPanState = null; - state.dragMoving = false; - state.canDragMove = false; - state.dragMoveLocation = null; -}; + const selectedCoordinates = this.pathsToCoordinates( + state.featureId, + state.selectedCoordPaths + ); + this.setSelectedCoordinates(selectedCoordinates); + }, -DirectSelect.onVertex = function (state, e) { - this.startDragging(state, e); - const about = e.featureTarget.properties; - const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); - if (!isShiftDown(e) && selectedIndex === -1) { + onMidpoint: function (state, e) { + this.startDragging(state, e); + const about = e.featureTarget.properties; + state.feature.addCoordinate(about.coord_path, about.lng, about.lat); + this.fireUpdate(); state.selectedCoordPaths = [about.coord_path]; - } else if (isShiftDown(e) && selectedIndex === -1) { - state.selectedCoordPaths.push(about.coord_path); - } + }, - const selectedCoordinates = this.pathsToCoordinates( - state.featureId, - state.selectedCoordPaths - ); - this.setSelectedCoordinates(selectedCoordinates); -}; - -DirectSelect.onMidpoint = function (state, e) { - this.startDragging(state, e); - const about = e.featureTarget.properties; - state.feature.addCoordinate(about.coord_path, about.lng, about.lat); - this.fireUpdate(); - state.selectedCoordPaths = [about.coord_path]; -}; + pathsToCoordinates: function (featureId, paths) { + return paths.map(coord_path => ({ feature_id: featureId, coord_path })); + }, -DirectSelect.pathsToCoordinates = function (featureId, paths) { - return paths.map(coord_path => ({ feature_id: featureId, coord_path })); -}; - -DirectSelect.onFeature = function (state, e) { - if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); - else this.stopDragging(state); -}; + onFeature: function (state, e) { + if (state.selectedCoordPaths.length === 0) this.startDragging(state, e); + else this.stopDragging(state); + }, -DirectSelect.dragFeature = function (state, e, delta) { - moveFeatures(this.getSelected(), delta); - state.dragMoveLocation = e.lngLat; -}; + dragFeature: function (state, e, delta) { + moveFeatures(this.getSelected(), delta); + state.dragMoveLocation = e.lngLat; + }, -DirectSelect.dragVertex = function (state, e, delta) { - const selectedCoords = state.selectedCoordPaths.map(coord_path => - state.feature.getCoordinate(coord_path) - ); - const selectedCoordPoints = selectedCoords.map(coords => ({ - type: Constants.geojsonTypes.FEATURE, - properties: {}, - geometry: { - type: Constants.geojsonTypes.POINT, - coordinates: coords - } - })); - - const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); - for (let i = 0; i < selectedCoords.length; i++) { - const coord = selectedCoords[i]; - state.feature.updateCoordinate( - state.selectedCoordPaths[i], - coord[0] + constrainedDelta.lng, - coord[1] + constrainedDelta.lat + dragVertex: function (state, e, delta) { + const selectedCoords = state.selectedCoordPaths.map(coord_path => + state.feature.getCoordinate(coord_path) ); - } -}; - -DirectSelect.clickNoTarget = function () { - this.changeMode(Constants.modes.SIMPLE_SELECT); -}; - -DirectSelect.clickInactive = function () { - this.changeMode(Constants.modes.SIMPLE_SELECT); -} - -DirectSelect.clickActiveFeature = function (state) { - state.selectedCoordPaths = []; - this.clearSelectedCoordinates(); - state.feature.changed(); -}; - -// EXTERNAL FUNCTIONS - -DirectSelect.onSetup = function (opts) { - const featureId = opts.featureId; - const feature = this.getFeature(featureId); - - if (!feature) { - throw new Error('You must provide a featureId to enter direct_select mode'); - } - - if (feature.type === Constants.geojsonTypes.POINT) { - throw new TypeError("direct_select mode doesn't handle point features"); - } - - const state = { - featureId, - feature, - dragMoveLocation: opts.startPos || null, - dragMoving: false, - canDragMove: false, - selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] - }; - - this.setSelectedCoordinates( - this.pathsToCoordinates(featureId, state.selectedCoordPaths) - ); - this.setSelected(featureId); - doubleClickZoom.disable(this); - - this.setActionableState({ - trash: true - }); - - return state; -}; - -DirectSelect.onStop = function () { - doubleClickZoom.enable(this); - this.clearSelectedCoordinates(); -}; + const selectedCoordPoints = selectedCoords.map(coords => ({ + type: Constants.geojsonTypes.FEATURE, + properties: {}, + geometry: { + type: Constants.geojsonTypes.POINT, + coordinates: coords + } + })); + + const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); + for (let i = 0; i < selectedCoords.length; i++) { + const coord = selectedCoords[i]; + state.feature.updateCoordinate( + state.selectedCoordPaths[i], + coord[0] + constrainedDelta.lng, + coord[1] + constrainedDelta.lat + ); + } + }, -DirectSelect.onTrash = function (state) { - // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them - // in reverse order so that we can remove by index safely. - state.selectedCoordPaths - .sort((a, b) => b.localeCompare(a, 'en', { numeric: true })) - .forEach(id => state.feature.removeCoordinate(id)); - this.fireUpdate(); - state.selectedCoordPaths = []; - this.clearSelectedCoordinates(); - this.fireActionable(state); - if (state.feature.isValid() === false) { - this.deleteFeature([state.featureId]); - this.changeMode(Constants.modes.SIMPLE_SELECT, {}); - } -}; + clickNoTarget: function () { + this.changeMode(Constants.modes.SIMPLE_SELECT); + }, -DirectSelect.onMouseMove = function (state, e) { - // On mousemove that is not a drag, stop vertex movement. - const isFeature = isActiveFeature(e); - const onVertex = isVertex(e); - const isMidPoint = isMidpoint(e); - const noCoords = state.selectedCoordPaths.length === 0; - if (isFeature && noCoords) - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else if (onVertex && !noCoords) - this.updateUIClasses({ mouse: Constants.cursors.MOVE }); - else this.updateUIClasses({ mouse: Constants.cursors.NONE }); - - const isDraggableItem = onVertex || isFeature || isMidPoint; - if (isDraggableItem && state.dragMoving) this.fireUpdate(); - - this.stopDragging(state); - - // Skip render - return true; -}; + clickInactive: function () { + this.changeMode(Constants.modes.SIMPLE_SELECT); + }, -DirectSelect.onMouseOut = function (state) { - // As soon as you mouse leaves the canvas, update the feature - if (state.dragMoving) this.fireUpdate(); + clickActiveFeature: function (state) { + state.selectedCoordPaths = []; + this.clearSelectedCoordinates(); + state.feature.changed(); + }, - // Skip render - return true; -}; + // EXTERNAL FUNCTIONS + onSetup: function (opts) { + const featureId = opts.featureId; + const feature = this.getFeature(featureId); -DirectSelect.onTouchStart = DirectSelect.onMouseDown = function (state, e) { - if (isVertex(e)) return this.onVertex(state, e); - if (isActiveFeature(e)) return this.onFeature(state, e); - if (isMidpoint(e)) return this.onMidpoint(state, e); -}; + if (!feature) { + throw new Error('You must provide a featureId to enter direct_select mode'); + } -DirectSelect.onDrag = function (state, e) { - if (state.canDragMove !== true) return; - state.dragMoving = true; - e.originalEvent.stopPropagation(); + if (feature.type === Constants.geojsonTypes.POINT) { + throw new TypeError("direct_select mode doesn't handle point features"); + } - const delta = { - lng: e.lngLat.lng - state.dragMoveLocation.lng, - lat: e.lngLat.lat - state.dragMoveLocation.lat - }; - if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta); - else this.dragFeature(state, e, delta); + const state = { + featureId, + feature, + dragMoveLocation: opts.startPos || null, + dragMoving: false, + canDragMove: false, + selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] + }; + + this.setSelectedCoordinates( + this.pathsToCoordinates(featureId, state.selectedCoordPaths) + ); + this.setSelected(featureId); + doubleClickZoom.disable(this); - state.dragMoveLocation = e.lngLat; -}; + this.setActionableState({ + trash: true + }); -DirectSelect.onClick = function (state, e) { - if (noTarget(e)) return this.clickNoTarget(state, e); - if (isActiveFeature(e)) return this.clickActiveFeature(state, e); - if (isInactiveFeature(e)) return this.clickInactive(state, e); - this.stopDragging(state); -}; + return state; + }, -DirectSelect.onTap = function (state, e) { - if (noTarget(e)) return this.clickNoTarget(state, e); - if (isActiveFeature(e)) return this.clickActiveFeature(state, e); - if (isInactiveFeature(e)) return this.clickInactive(state, e); -}; + onStop: function () { + doubleClickZoom.enable(this); + this.clearSelectedCoordinates(); + }, -DirectSelect.onTouchEnd = DirectSelect.onMouseUp = function (state) { - if (state.dragMoving) { + onTrash: function (state) { + // Uses number-aware sorting to make sure '9' < '10'. Comparison is reversed because we want them + // in reverse order so that we can remove by index safely. + state.selectedCoordPaths + .sort((a, b) => b.localeCompare(a, 'en', { numeric: true })) + .forEach(id => state.feature.removeCoordinate(id)); this.fireUpdate(); - } - this.stopDragging(state); -}; + state.selectedCoordPaths = []; + this.clearSelectedCoordinates(); + this.fireActionable(state); + if (state.feature.isValid() === false) { + this.deleteFeature([state.featureId]); + this.changeMode(Constants.modes.SIMPLE_SELECT, {}); + } + }, + + onMouseMove: function (state, e) { + // On mousemove that is not a drag, stop vertex movement. + const isFeature = isActiveFeature(e); + const onVertex = isVertex(e); + const isMidPoint = isMidpoint(e); + const noCoords = state.selectedCoordPaths.length === 0; + if (isFeature && noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else if (onVertex && !noCoords) + this.updateUIClasses({ mouse: Constants.cursors.MOVE }); + else this.updateUIClasses({ mouse: Constants.cursors.NONE }); + + const isDraggableItem = onVertex || isFeature || isMidPoint; + if (isDraggableItem && state.dragMoving) this.fireUpdate(); + + this.stopDragging(state); + + // Skip render + return true; + }, + + onMouseOut: function (state) { + // As soon as you mouse leaves the canvas, update the feature + if (state.dragMoving) this.fireUpdate(); + + // Skip render + return true; + }, + + _start: function (state, e) { + if (isVertex(e)) return this.onVertex(state, e); + if (isActiveFeature(e)) return this.onFeature(state, e); + if (isMidpoint(e)) return this.onMidpoint(state, e); + }, + + TouchStart: function (state, e) { return this._start(state, e); }, + onMouseDown: function (state, e) { return this._start(state, e); }, + + onDrag: function (state, e) { + if (state.canDragMove !== true) return; + state.dragMoving = true; + e.originalEvent.stopPropagation(); + + const delta = { + lng: e.lngLat.lng - state.dragMoveLocation.lng, + lat: e.lngLat.lat - state.dragMoveLocation.lat + }; + if (state.selectedCoordPaths.length > 0) this.dragVertex(state, e, delta); + else this.dragFeature(state, e, delta); + + state.dragMoveLocation = e.lngLat; + }, + + _select: function (state, e) { + if (noTarget(e)) return this.clickNoTarget(state, e); + if (isActiveFeature(e)) return this.clickActiveFeature(state, e); + if (isInactiveFeature(e)) return this.clickInactive(state, e); + this.stopDragging(state); + }, + + onTap: function (state, e) { return this._select(state, e); }, + onClick: function (state, e) { return this._select(state, e); }, + + _end: function (state) { + if (state.dragMoving) { + this.fireUpdate(); + } + this.stopDragging(state); + }, + + onMouseUp: function (state) { return this._end(state); }, + onTouchEnd: function (state) { return this._end(state); }, + + toDisplayFeatures: function (state: CTX, geojson, push) { + if (state.featureId === geojson.properties.id) { + geojson.properties.active = Constants.activeStates.ACTIVE; + push(geojson); + createSupplementaryPoints(geojson, { + map: this.map, + midpoints: true, + selectedPaths: state.selectedCoordPaths + }).forEach(push); + } else { + geojson.properties.active = Constants.activeStates.INACTIVE; + push(geojson); + } -DirectSelect.toDisplayFeatures = function (state: DrawCTX, geojson, push) { - if (state.featureId === geojson.properties.id) { - geojson.properties.active = Constants.activeStates.ACTIVE; - push(geojson); - createSupplementaryPoints(geojson, { - map: this.map, - midpoints: true, - selectedPaths: state.selectedCoordPaths - }).forEach(push); - } else { - geojson.properties.active = Constants.activeStates.INACTIVE; - push(geojson); + this.fireActionable(state); } - this.fireActionable(state); }; export default DirectSelect; From 64cd9dfe11ef55cff5a6cd5c23b389b78f1d01c6 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 17:29:24 -0400 Subject: [PATCH 30/59] Mode state interface --- src/modes/direct_select.ts | 19 +++++++++++-------- src/types/types.ts | 10 ++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index d2b16391..89b189d4 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,7 +11,7 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { CTX, DrawCustomMode, MapMouseEvent } from '../types/types'; +import type { ModeState, DrawCustomMode, MapMouseEvent } from '../types/types'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); @@ -19,12 +19,12 @@ const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); interface DirectSelectMode extends DrawCustomMode { fireUpdate(): void; clickInactive(): void; - fireActionable(state: CTX): void; - clickNoTarget(state: CTX, e: MapMouseEvent): void; - startDragging(state: CTX, e: MapMouseEvent): void; - stopDragging(state: CTX): void; - onVertex(state: CTX, e: MapMouseEvent): void; - onMidpoint(state: CTX, e: MapMouseEvent): void; + fireActionable(state: ModeState): void; + clickNoTarget(state: ModeState, e: MapMouseEvent): void; + startDragging(state: ModeState, e: MapMouseEvent): void; + stopDragging(state: ModeState): void; + onVertex(state: ModeState, e: MapMouseEvent): void; + onMidpoint(state: ModeState, e: MapMouseEvent): void; } const DirectSelect: DirectSelectMode = { @@ -84,6 +84,9 @@ const DirectSelect: DirectSelectMode = { }, onMidpoint: function (state, e) { + + console.log('STATE LOOKS LIKE THIS', state); + this.startDragging(state, e); const about = e.featureTarget.properties; state.feature.addCoordinate(about.coord_path, about.lng, about.lat); @@ -272,7 +275,7 @@ const DirectSelect: DirectSelectMode = { onMouseUp: function (state) { return this._end(state); }, onTouchEnd: function (state) { return this._end(state); }, - toDisplayFeatures: function (state: CTX, geojson, push) { + toDisplayFeatures: function (state: ModeState, geojson, push) { if (state.featureId === geojson.properties.id) { geojson.properties.active = Constants.activeStates.ACTIVE; push(geojson); diff --git a/src/types/types.ts b/src/types/types.ts index d326c620..bc41e5d7 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -223,6 +223,16 @@ interface DrawPolygon extends DrawFeatureBase { removeCoordinate(path: string): void; } +export interface ModeState { + featureId: string; + canDragMove: boolean; + dragMoveLocation: { lng: number; lat: number; } | undefined + dragMoving: boolean; + feature: DrawFeature; + initialDragPanState?: boolean; + selectedCoordPaths: []; +} + export type DrawFeature = | DrawPoint | DrawLineString From dd3b5d2d2f4cb1a1d32f27064bf419f9aa09b1d0 Mon Sep 17 00:00:00 2001 From: tristen Date: Fri, 14 Mar 2025 23:46:52 -0400 Subject: [PATCH 31/59] More typings for direct_select --- src/modes/direct_select.ts | 44 ++++++++++++++++----------- src/modes/mode_interface_accessors.ts | 2 +- src/types/types.ts | 24 ++++++++------- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 89b189d4..8f6dc076 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,20 +11,30 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { ModeState, DrawCustomMode, MapMouseEvent } from '../types/types'; +import type { DirectSelectState, DrawCustomMode, MapMouseEvent, MapTouchEvent, DrawCoords } from '../types/types'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); +type Event = MapMouseEvent | MapTouchEvent; + interface DirectSelectMode extends DrawCustomMode { fireUpdate(): void; clickInactive(): void; - fireActionable(state: ModeState): void; - clickNoTarget(state: ModeState, e: MapMouseEvent): void; - startDragging(state: ModeState, e: MapMouseEvent): void; - stopDragging(state: ModeState): void; - onVertex(state: ModeState, e: MapMouseEvent): void; - onMidpoint(state: ModeState, e: MapMouseEvent): void; + fireActionable(state: DirectSelectState): void; + clickNoTarget(state: DirectSelectState, e: Event): void; + startDragging(state: DirectSelectState, e: Event): void; + stopDragging(state: DirectSelectState): void; + onVertex(state: DirectSelectState, e: Event): void; + onMidpoint(state: DirectSelectState, e: Event): void; + onFeature(state: DirectSelectState, e: Event): void; + dragFeature(state: DirectSelectState, e: Event, delta: { lng: number, lat: number }): void; + dragVertex(state: DirectSelectState, e: Event, delta: { lng: number, lat: number }): void; + clickActiveFeature(state: DirectSelectState): void; + pathsToCoordinates(featureId: string, paths: []): DrawCoords; + _start(state: DirectSelectState, e: Event): void; + _select(state: DirectSelectState, e: Event): void; + _end(state: DirectSelectState): void; } const DirectSelect: DirectSelectMode = { @@ -68,12 +78,13 @@ const DirectSelect: DirectSelectMode = { onVertex: function (state, e) { this.startDragging(state, e); - const about = e.featureTarget.properties; - const selectedIndex = state.selectedCoordPaths.indexOf(about.coord_path); - if (!isShiftDown(e) && selectedIndex === -1) { - state.selectedCoordPaths = [about.coord_path]; - } else if (isShiftDown(e) && selectedIndex === -1) { - state.selectedCoordPaths.push(about.coord_path); + const { coord_path } = e.featureTarget.properties; + + const selectedIndex = state.selectedCoordPaths.indexOf(coord_path); + if (!isShiftDown(e as MapMouseEvent) && selectedIndex === -1) { + state.selectedCoordPaths = [coord_path]; + } else if (isShiftDown(e as MapMouseEvent) && selectedIndex === -1) { + state.selectedCoordPaths.push(coord_path); } const selectedCoordinates = this.pathsToCoordinates( @@ -84,9 +95,6 @@ const DirectSelect: DirectSelectMode = { }, onMidpoint: function (state, e) { - - console.log('STATE LOOKS LIKE THIS', state); - this.startDragging(state, e); const about = e.featureTarget.properties; state.feature.addCoordinate(about.coord_path, about.lng, about.lat); @@ -237,7 +245,7 @@ const DirectSelect: DirectSelectMode = { if (isMidpoint(e)) return this.onMidpoint(state, e); }, - TouchStart: function (state, e) { return this._start(state, e); }, + onTouchStart: function (state, e) { return this._start(state, e); }, onMouseDown: function (state, e) { return this._start(state, e); }, onDrag: function (state, e) { @@ -275,7 +283,7 @@ const DirectSelect: DirectSelectMode = { onMouseUp: function (state) { return this._end(state); }, onTouchEnd: function (state) { return this._end(state); }, - toDisplayFeatures: function (state: ModeState, geojson, push) { + toDisplayFeatures: function (state, geojson, push) { if (state.featureId === geojson.properties.id) { geojson.properties.active = Constants.activeStates.ACTIVE; push(geojson); diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index 733c808d..58466430 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -71,7 +71,7 @@ export default class ModeInterface { this._ctx.store.deselect(id); } - deleteFeature(id: string, opts: Record = {}): void { + deleteFeature(id: string | string[], opts: Record = {}): void { this._ctx.store.delete(id, opts); } diff --git a/src/types/types.ts b/src/types/types.ts index bc41e5d7..16ec44d1 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -59,6 +59,8 @@ export type XY = { x: number; y: number }; export type Coords = Array<[number, number]>; +export type DrawCoords = Array<{ coord_path: string; feature_id: string }> + export interface Entry { point: XY; time: number; @@ -159,9 +161,9 @@ interface DrawControls { } interface DrawActionableState { - trash: boolean; - combineFeatures: boolean; - uncombineFeatures: boolean; + trash?: boolean; + combineFeatures?: boolean; + uncombineFeatures?: boolean; } interface DrawFeatureBase { @@ -223,14 +225,14 @@ interface DrawPolygon extends DrawFeatureBase { removeCoordinate(path: string): void; } -export interface ModeState { +export interface DirectSelectState { featureId: string; canDragMove: boolean; dragMoveLocation: { lng: number; lat: number; } | undefined dragMoving: boolean; - feature: DrawFeature; + feature: DrawPolygon; initialDragPanState?: boolean; - selectedCoordPaths: []; + selectedCoordPaths: number[]; } export type DrawFeature = @@ -309,7 +311,7 @@ export interface DrawCustomModeThis { drawConfig: DrawOptions; setSelected(features?: DrawFeature[]): void; setSelectedCoordinates( - coords: Array<{ coord_path: string; feature_id: string }> + coords: DrawCoords ): void; getSelected(): DrawFeature[]; getSelectedIds(): string[]; @@ -396,8 +398,8 @@ export interface DrawCustomMode toDisplayFeatures( this: DrawCustomModeThis & this, state: CustomModeState, - geojson: GeoJSON, - display: (geojson: GeoJSON) => void + geojson: StrictFeature, + display: (geojson: StrictFeature) => void ): void; } @@ -655,7 +657,7 @@ interface DrawStore { featureChanged(id: string, options?: DrawStoreOptions): boolean; setSelected(features?: DrawFeature[]): void; setSelectedCoordinates( - coords: Array<{ coord_path: string; feature_id: string }> + coords: DrawCoords ): void; getSelectedCoordinates(): Coords[]; getSelected(): DrawFeature[]; @@ -665,7 +667,7 @@ interface DrawStore { getFeature(id: string): DrawFeature; select(id: string): void; deselect(features: string | string[]): void; - delete(id: string, opts: Record): void; + delete(id: string | string[], opts: Record): void; deleteFeature(id: string, opts?: unknown): void; add(feature: DrawFeature, opts: Record): void; addFeature(feature: DrawFeature, opts: Record): void; From 06ebad26c42fe0c1966e1f7862a60070a38c9eb3 Mon Sep 17 00:00:00 2001 From: tristen Date: Sat, 15 Mar 2025 10:13:45 -0400 Subject: [PATCH 32/59] Organize, use ModeCTX directly --- src/modes/direct_select.ts | 11 +++++++---- src/types/types.ts | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 8f6dc076..f97a4d1a 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,14 +11,14 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { DirectSelectState, DrawCustomMode, MapMouseEvent, MapTouchEvent, DrawCoords } from '../types/types'; +import type { DirectSelectState, ModeCTX, MapMouseEvent, MapTouchEvent, DrawCoords, StrictFeature } from '../types/types'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); type Event = MapMouseEvent | MapTouchEvent; -interface DirectSelectMode extends DrawCustomMode { +interface DirectSelectMode extends ModeCTX { fireUpdate(): void; clickInactive(): void; fireActionable(state: DirectSelectState): void; @@ -31,7 +31,7 @@ interface DirectSelectMode extends DrawCustomMode { dragFeature(state: DirectSelectState, e: Event, delta: { lng: number, lat: number }): void; dragVertex(state: DirectSelectState, e: Event, delta: { lng: number, lat: number }): void; clickActiveFeature(state: DirectSelectState): void; - pathsToCoordinates(featureId: string, paths: []): DrawCoords; + pathsToCoordinates(featureId: string, paths: number[]): DrawCoords; _start(state: DirectSelectState, e: Event): void; _select(state: DirectSelectState, e: Event): void; _end(state: DirectSelectState): void; @@ -127,7 +127,7 @@ const DirectSelect: DirectSelectMode = { type: Constants.geojsonTypes.POINT, coordinates: coords } - })); + })) as Array; const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta); for (let i = 0; i < selectedCoords.length; i++) { @@ -176,10 +176,13 @@ const DirectSelect: DirectSelectMode = { selectedCoordPaths: opts.coordPath ? [opts.coordPath] : [] }; + this.setSelectedCoordinates( this.pathsToCoordinates(featureId, state.selectedCoordPaths) ); this.setSelected(featureId); + + console.log('does this have map?', this); doubleClickZoom.disable(this); this.setActionableState({ diff --git a/src/types/types.ts b/src/types/types.ts index 16ec44d1..f20c0135 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,14 +1,3 @@ -import type { - BBox, - Feature, - FeatureCollection, - GeoJSON, - GeoJsonTypes, - Geometry, - Point, - Position -} from 'geojson'; - import { classes, sources, @@ -23,6 +12,17 @@ import { interactions } from '../constants'; +import type { + BBox, + Feature, + FeatureCollection, + GeoJSON, + GeoJsonTypes, + Geometry, + Point, + Position +} from 'geojson'; + import type { CircleLayerSpecification, ControlPosition, @@ -112,8 +112,8 @@ interface DrawFeatureBase { incomingCoords: this['setCoordinates']; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; - getCoordinate(path: string): Position; - updateCoordinate(path: string, lng: number, lat: number): void; + getCoordinate(path: number): Position; + updateCoordinate(path: number, lng: number, lat: number): void; setProperty(property: string, value: any): void; toGeoJSON(): GeoJSON; } From 5daaa4a7cf6b3801286e78b974acca69edae007a Mon Sep 17 00:00:00 2001 From: tristen Date: Sat, 15 Mar 2025 10:42:21 -0400 Subject: [PATCH 33/59] Simplify --- src/lib/double_click_zoom.ts | 6 ++---- src/modes/direct_select.ts | 8 +++----- src/types/types.ts | 8 ++------ 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/lib/double_click_zoom.ts b/src/lib/double_click_zoom.ts index 167ae9d3..b41704a8 100644 --- a/src/lib/double_click_zoom.ts +++ b/src/lib/double_click_zoom.ts @@ -1,7 +1,5 @@ -import type { ModeCTX } from '../types/types'; - export const doubleClickZoom = { - enable: (ctx: ModeCTX) => { + enable: (ctx) => { setTimeout(() => { // First check we've got a map and some context. if ( @@ -17,7 +15,7 @@ export const doubleClickZoom = { ctx.map.doubleClickZoom.enable(); }, 0); }, - disable: (ctx: ModeCTX) => { + disable: (ctx) => { setTimeout(() => { if (!ctx.map || !ctx.map.doubleClickZoom) return; // Always disable here, as it's necessary in some cases. diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index f97a4d1a..61b491bf 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -11,14 +11,14 @@ import { doubleClickZoom } from '../lib/double_click_zoom'; import * as Constants from '../constants'; import moveFeatures from '../lib/move_features'; -import type { DirectSelectState, ModeCTX, MapMouseEvent, MapTouchEvent, DrawCoords, StrictFeature } from '../types/types'; +import type { DirectSelectState, DrawCustomMode, MapMouseEvent, MapTouchEvent, DrawCoords, StrictFeature } from '../types/types'; const isVertex = isOfMetaType(Constants.meta.VERTEX); const isMidpoint = isOfMetaType(Constants.meta.MIDPOINT); type Event = MapMouseEvent | MapTouchEvent; -interface DirectSelectMode extends ModeCTX { +interface DirectSelectMode extends DrawCustomMode { fireUpdate(): void; clickInactive(): void; fireActionable(state: DirectSelectState): void; @@ -31,7 +31,7 @@ interface DirectSelectMode extends ModeCTX { dragFeature(state: DirectSelectState, e: Event, delta: { lng: number, lat: number }): void; dragVertex(state: DirectSelectState, e: Event, delta: { lng: number, lat: number }): void; clickActiveFeature(state: DirectSelectState): void; - pathsToCoordinates(featureId: string, paths: number[]): DrawCoords; + pathsToCoordinates(featureId: string, paths: string[]): DrawCoords; _start(state: DirectSelectState, e: Event): void; _select(state: DirectSelectState, e: Event): void; _end(state: DirectSelectState): void; @@ -181,8 +181,6 @@ const DirectSelect: DirectSelectMode = { this.pathsToCoordinates(featureId, state.selectedCoordPaths) ); this.setSelected(featureId); - - console.log('does this have map?', this); doubleClickZoom.disable(this); this.setActionableState({ diff --git a/src/types/types.ts b/src/types/types.ts index f20c0135..e411cf33 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -232,7 +232,7 @@ export interface DirectSelectState { dragMoving: boolean; feature: DrawPolygon; initialDragPanState?: boolean; - selectedCoordPaths: number[]; + selectedCoordPaths: string[]; } export type DrawFeature = @@ -308,6 +308,7 @@ interface DrawActionableEvent extends DrawEvent { export interface DrawCustomModeThis { map: Map; + _ctx: CTX; drawConfig: DrawOptions; setSelected(features?: DrawFeature[]): void; setSelectedCoordinates( @@ -411,11 +412,6 @@ interface Modes { direct_select: DrawCustomMode; } -export interface ModeCTX extends DrawCustomMode { - map: Map; - _ctx: CTX; -} - // Convert these to use imports from constants interface Constants { readonly modes: (typeof modes)[keyof typeof modes]; From c6ec967792c72c3eb4339d436f4c7bd446a5491c Mon Sep 17 00:00:00 2001 From: tristen Date: Sat, 15 Mar 2025 10:53:56 -0400 Subject: [PATCH 34/59] String is also accepted --- src/modes/direct_select.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 61b491bf..4145f434 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -206,7 +206,7 @@ const DirectSelect: DirectSelectMode = { this.clearSelectedCoordinates(); this.fireActionable(state); if (state.feature.isValid() === false) { - this.deleteFeature([state.featureId]); + this.deleteFeature(state.featureId); this.changeMode(Constants.modes.SIMPLE_SELECT, {}); } }, From 341d3ac84f9ee9580a0508a3e711b3e01c51b69f Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 10:30:19 -0400 Subject: [PATCH 35/59] Fixes to store --- src/store.ts | 40 +++++++++++++++++++++------------------- src/types/types.ts | 2 +- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/store.ts b/src/store.ts index 32308e68..0b60858d 100644 --- a/src/store.ts +++ b/src/store.ts @@ -2,18 +2,16 @@ import { toDenseArray } from './lib/to_dense_array'; import StringSet from './lib/string_set'; import render from './render'; import * as Constants from './constants'; -import type { CTX, StrictFeature, Coords, DrawStoreOptions } from './types/types'; - -type MapConfig = Record; +import type { CTX, DrawFeature, DrawCoords, DrawStoreOptions } from './types/types'; export default class Store { - private _features: Record = {}; + private _features: Record = {}; private _featureIds = new StringSet(); private _selectedFeatureIds = new StringSet(); - private _selectedCoordinates: Coords[] = []; + private _selectedCoordinates: DrawCoords = []; private _changedFeatureIds = new StringSet(); private _emitSelectionChange = false; - private _mapInitialConfig: MapConfig = {}; + private _mapInitialConfig: Record = {}; private ctx: CTX; private renderRequest: number | null = null; @@ -32,7 +30,9 @@ export default class Store { if (this._emitSelectionChange) { this.ctx.events.fire(Constants.events.SELECTION_CHANGE, { - features: this.getSelected().map(feature => feature.toGeoJSON()), + features: this.getSelected().map(feature => { + return feature.toGeoJSON() + }), points: this.getSelectedCoordinates().map(coordinate => ({ type: Constants.geojsonTypes.FEATURE, properties: {}, @@ -66,7 +66,7 @@ export default class Store { return this; } - featureCreated(featureId: string, options: DrawStoreOptions = {}): this { + featureCreated(featureId, options: DrawStoreOptions = {}): this { this._changedFeatureIds.add(featureId); if (!options.silent) { const feature = this.get(featureId); @@ -86,7 +86,7 @@ export default class Store { return this; } - getChangedIds(): string[] { + getChangedIds() { return this._changedFeatureIds.values(); } @@ -95,11 +95,11 @@ export default class Store { return this; } - getAllIds(): string[] { + getAllIds() { return this._featureIds.values(); } - add(feature: StrictFeature, options: DrawStoreOptions = {}): this { + add(feature: DrawFeature, options: DrawStoreOptions = {}): this { this._features[feature.id] = feature; this._featureIds.add(feature.id); this.featureCreated(feature.id, { silent: options.silent }); @@ -107,7 +107,7 @@ export default class Store { } delete(featureIds: string | string[], options: DrawStoreOptions = {}): this { - const deletedFeatures: StrictFeature[] = []; + const deletedFeatures: DrawFeature[] = []; toDenseArray(featureIds).forEach(id => { if (!this._featureIds.has(id)) return; this._featureIds.delete(id); @@ -127,27 +127,29 @@ export default class Store { return this; } - get(id: string): StrictFeature { + get(id: string) { return this._features[id]; } - getAll(): StrictFeature[] { + getAll() { return Object.values(this._features); } - getSelectedIds(): string[] { + getSelectedIds() { return this._selectedFeatureIds.values(); } - getSelected(): StrictFeature[] { - return this.getSelectedIds().map(id => this.get(id)); + getSelected() { + return this.getSelectedIds().map(id => this.get(id as string)); } - getSelectedCoordinates(): Coords[] { - return this._selectedCoordinates.map(coordinate => { + getSelectedCoordinates() { + const coordinates = this._selectedCoordinates.map(coordinate => { const feature = this.get(coordinate.feature_id); return { coordinates: feature.getCoordinate(coordinate.coord_path) }; }); + + return coordinates; } select(featureIds: string[], options: DrawStoreOptions = {}): this { diff --git a/src/types/types.ts b/src/types/types.ts index e411cf33..79d22537 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -183,7 +183,7 @@ interface DrawFeatureBase { toGeoJSON(): GeoJSON; } -interface DrawMultiFeature< +export interface DrawMultiFeature< Type extends 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' > extends Omit< DrawFeatureBase< From aa98282ce44d7c913b4f3730895d0ff1536a59c8 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 10:40:09 -0400 Subject: [PATCH 36/59] More on store --- src/store.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/store.ts b/src/store.ts index 0b60858d..b9643982 100644 --- a/src/store.ts +++ b/src/store.ts @@ -107,7 +107,7 @@ export default class Store { } delete(featureIds: string | string[], options: DrawStoreOptions = {}): this { - const deletedFeatures: DrawFeature[] = []; + const deletedFeatures = []; toDenseArray(featureIds).forEach(id => { if (!this._featureIds.has(id)) return; this._featureIds.delete(id); @@ -162,7 +162,7 @@ export default class Store { return this; } - deselect(featureIds: string[], options: DrawStoreOptions = {}): this { + deselect(featureIds: (string | number)[], options: DrawStoreOptions = {}): this { toDenseArray(featureIds).forEach(id => { if (!this._selectedFeatureIds.has(id)) return; this._selectedFeatureIds.delete(id); @@ -174,10 +174,10 @@ export default class Store { } setSelected(featureIds: string[], options: DrawStoreOptions = {}): this { - featureIds = toDenseArray(featureIds); + featureIds = toDenseArray(featureIds) as string[]; // Deselect any features not in the new selection - this.deselect(this._selectedFeatureIds.values().filter(id => featureIds.indexOf(id) === -1), { silent: options.silent }); + this.deselect(this._selectedFeatureIds.values().filter(id => featureIds.indexOf(id as string) === -1), { silent: options.silent }); // Select any features in the new selection that were not already selected this.select(featureIds.filter(id => !this._selectedFeatureIds.has(id)), { silent: options.silent }); From 34798cf3097d1ab00de1906a78de68e203c4d000 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 15:51:44 -0400 Subject: [PATCH 37/59] Work on api --- src/api.ts | 38 +++++++++++++-------------- src/events.ts | 2 +- src/modes/mode_interface_accessors.ts | 2 +- src/store.ts | 9 +++++++ src/types/types.ts | 10 ++++--- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/api.ts b/src/api.ts index 18dd63f0..3d97e712 100644 --- a/src/api.ts +++ b/src/api.ts @@ -31,16 +31,16 @@ export default function (ctx: CTX, api: Draw) { ? !!ctx.options.suppressAPIEvents : true; - api.getFeatureIdsAt = function (point) { + api.getFeatureIdsAt = (point) => { const features = featuresAt.click({ point }, null, ctx); return features.map(feature => feature.properties.id); }; - api.getSelectedIds = function () { + api.getSelectedIds = () => { return ctx.store.getSelectedIds(); }; - api.getSelected = function () { + api.getSelected = () => { return { type: Constants.geojsonTypes.FEATURE_COLLECTION, features: ctx.store @@ -50,7 +50,7 @@ export default function (ctx: CTX, api: Draw) { }; }; - api.getSelectedPoints = function () { + api.getSelectedPoints = () => { return { type: Constants.geojsonTypes.FEATURE_COLLECTION, features: ctx.store.getSelectedCoordinates().map(coordinate => ({ @@ -64,7 +64,7 @@ export default function (ctx: CTX, api: Draw) { }; }; - api.set = function (featureCollection) { + api.set = (featureCollection) => { if ( featureCollection.type === undefined || featureCollection.type !== Constants.geojsonTypes.FEATURE_COLLECTION || @@ -86,7 +86,7 @@ export default function (ctx: CTX, api: Draw) { return newIds; }; - api.add = function (geojson) { + api.add = (geojson) => { const featureCollection = JSON.parse(JSON.stringify(normalize(geojson))); const ids = featureCollection.features.map(feature => { @@ -131,21 +131,21 @@ export default function (ctx: CTX, api: Draw) { return ids; }; - api.get = function (id) { + api.get = (id) => { const feature = ctx.store.get(id); if (feature) { return feature.toGeoJSON(); } }; - api.getAll = function () { + api.getAll = () => { return { type: Constants.geojsonTypes.FEATURE_COLLECTION, features: ctx.store.getAll().map(feature => feature.toGeoJSON()) }; }; - api.delete = function (featureIds) { + api.delete = (featureIds) => { ctx.store.delete(featureIds, { silent }); // If we were in direct select mode and our selected feature no longer exists // (because it was deleted), we need to get out of that mode. @@ -163,7 +163,7 @@ export default function (ctx: CTX, api: Draw) { return api; }; - api.deleteAll = function () { + api.deleteAll = () => { ctx.store.delete(ctx.store.getAllIds(), { silent }); // If we were in direct select mode, now our selected feature no longer exists, // so escape that mode. @@ -178,7 +178,7 @@ export default function (ctx: CTX, api: Draw) { return api; }; - api.changeMode = function (mode, modeOptions = {}) { + api.changeMode = (mode, modeOptions: { featureIds?: string[], featureId?: string } = {}) => { // Avoid changing modes just to re-select what's already selected if ( mode === Constants.modes.SIMPLE_SELECT && @@ -210,26 +210,26 @@ export default function (ctx: CTX, api: Draw) { return api; }; - api.getMode = function () { - return ctx.events.getMode(); + api.getMode = () => { + return ctx.events.getMode() as string; }; - api.trash = function () { + api.trash = () => { ctx.events.trash({ silent }); return api; }; - api.combineFeatures = function () { - ctx.events.combineFeatures({ silent }); + api.combineFeatures = () => { + ctx.events.combineFeatures(); return api; }; - api.uncombineFeatures = function () { - ctx.events.uncombineFeatures({ silent }); + api.uncombineFeatures = () => { + ctx.events.uncombineFeatures(); return api; }; - api.setFeatureProperty = function (featureId, property, value) { + api.setFeatureProperty = (featureId, property, value) => { ctx.store.setFeatureProperty(featureId, property, value, { silent }); return api; }; diff --git a/src/events.ts b/src/events.ts index 2d90ae09..41b98d42 100644 --- a/src/events.ts +++ b/src/events.ts @@ -258,7 +258,7 @@ export default function(ctx: CTX) { ctx.container.removeEventListener('keyup', events.keyup); } }, - trash(options) { + trash(options?: { silent: boolean }) { currentMode.trash(options); }, combineFeatures() { diff --git a/src/modes/mode_interface_accessors.ts b/src/modes/mode_interface_accessors.ts index 58466430..483f89f6 100644 --- a/src/modes/mode_interface_accessors.ts +++ b/src/modes/mode_interface_accessors.ts @@ -29,7 +29,7 @@ export default class ModeInterface { this._ctx = ctx; } - setSelected(features: DrawFeature[]): void { + setSelected(features: string[]): void { this._ctx.store.setSelected(features); } diff --git a/src/store.ts b/src/store.ts index b9643982..c3615bf7 100644 --- a/src/store.ts +++ b/src/store.ts @@ -236,6 +236,15 @@ export default class Store { } }; + setFeatureProperty(featureId, property, value, options: DrawStoreOptions = {}) { + this.get(featureId).setProperty(property, value); + + this.featureChanged(featureId, { + silent: options.silent, + action: Constants.updateActions.CHANGE_PROPERTIES + }); + }; + private refreshSelectedCoordinates(options: DrawStoreOptions = {}): void { const newSelectedCoordinates = this._selectedCoordinates.filter(point => this._selectedFeatureIds.has(point.feature_id)); if (this._selectedCoordinates.length !== newSelectedCoordinates.length && !options.silent) { diff --git a/src/types/types.ts b/src/types/types.ts index 79d22537..d4382546 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -263,7 +263,7 @@ interface DrawCreateEvent extends DrawEvent { } interface DrawDeleteEvent extends DrawEvent { - // Array of GeoJSON objects representing the features that were deleted + // Array of GeoJSON objects representing the features that were delete, featureId?: stringd features: Feature[]; type: 'draw.delete'; } @@ -651,7 +651,7 @@ interface DrawStore { restoreMapConfig(): Record; getInitialConfigValue(interaction: string): boolean; featureChanged(id: string, options?: DrawStoreOptions): boolean; - setSelected(features?: DrawFeature[]): void; + setSelected(features?: string[], options?: { silent: boolean }): void; setSelectedCoordinates( coords: DrawCoords ): void; @@ -679,11 +679,13 @@ interface DrawStore { bbox: BBox, bufferType: 'click' | 'tap' ): DrawFeature[]; - newFeature(geojson: GeoJSON): DrawFeature; + newFeature(geojson: StrictFeatureCollection): DrawFeature; isInstanceOf(type: string, feature: object): boolean; doRender(id: string): void; getAllIds(): Array + getAll(): DrawFeature[]; createRenderBatch(): () => void; + setFeatureProperty(featureId: string, property: string, value: any, options?: { silent: boolean }): this; } interface DrawSetup { @@ -723,7 +725,7 @@ export declare class Draw implements IControl { delete(ids: string | string[]): this; deleteAll(): this; set(featureCollection: StrictFeatureCollection): string[]; - trash(): DrawEvents['trash']; + trash(): this; combineFeatures(): this; uncombineFeatures(): this; getMode(): (Modes & {}) | string; From fe4d933bb6ec33548fd22d2b4665489276b9ae2d Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 16:36:18 -0400 Subject: [PATCH 38/59] More typing --- src/api.ts | 21 +++++++++++---------- src/lib/features_at.ts | 2 +- src/types/types.ts | 8 ++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/api.ts b/src/api.ts index 3d97e712..6d434305 100644 --- a/src/api.ts +++ b/src/api.ts @@ -11,7 +11,7 @@ import LineString from './feature_types/line_string'; import Point from './feature_types/point'; import MultiFeature from './feature_types/multi_feature'; -import type { CTX, Draw } from './types/types'; +import type { CTX, Draw, StrictFeature, MapMouseEvent } from './types/types'; const featureTypes = { Polygon, @@ -32,7 +32,8 @@ export default function (ctx: CTX, api: Draw) { : true; api.getFeatureIdsAt = (point) => { - const features = featuresAt.click({ point }, null, ctx); + const event = { point } as MapMouseEvent; + const features = featuresAt.click(event, null, ctx); return features.map(feature => feature.properties.id); }; @@ -42,17 +43,17 @@ export default function (ctx: CTX, api: Draw) { api.getSelected = () => { return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, + type: Constants.geojsonTypes.FEATURE_COLLECTION as 'FeatureCollection', features: ctx.store .getSelectedIds() .map(id => ctx.store.get(id)) - .map(feature => feature.toGeoJSON()) + .map(feature => feature.toGeoJSON()) as StrictFeature[] }; }; api.getSelectedPoints = () => { return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, + type: Constants.geojsonTypes.FEATURE_COLLECTION as 'FeatureCollection', features: ctx.store.getSelectedCoordinates().map(coordinate => ({ type: Constants.geojsonTypes.FEATURE, properties: {}, @@ -60,7 +61,7 @@ export default function (ctx: CTX, api: Draw) { type: Constants.geojsonTypes.POINT, coordinates: coordinate.coordinates } - })) + })) as StrictFeature[] }; }; @@ -113,7 +114,7 @@ export default function (ctx: CTX, api: Draw) { const originalProperties = internalFeature.properties; internalFeature.properties = feature.properties; if (!isEqual(originalProperties, feature.properties)) { - ctx.store.featureChanged(internalFeature.id, { silent }); + ctx.store.featureChanged(internalFeature.id as string, { silent }); } if ( !isEqual( @@ -134,14 +135,14 @@ export default function (ctx: CTX, api: Draw) { api.get = (id) => { const feature = ctx.store.get(id); if (feature) { - return feature.toGeoJSON(); + return feature.toGeoJSON() as StrictFeature; } }; api.getAll = () => { return { - type: Constants.geojsonTypes.FEATURE_COLLECTION, - features: ctx.store.getAll().map(feature => feature.toGeoJSON()) + type: Constants.geojsonTypes.FEATURE_COLLECTION as 'FeatureCollection', + features: ctx.store.getAll().map(feature => feature.toGeoJSON()) as StrictFeature[] }; }; diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index 70ca70ff..01e7876a 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -4,7 +4,7 @@ import * as Constants from '../constants'; import StringSet from './string_set'; import type { BBox } from 'geojson'; -import type { CTX, DrawStyleLayer, MapMouseEvent, MapTouchEvent } from '../types/types'; +import type { CTX, MapMouseEvent, MapTouchEvent } from '../types/types'; type E = MapMouseEvent | MapTouchEvent; diff --git a/src/types/types.ts b/src/types/types.ts index d4382546..26653eab 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -102,7 +102,6 @@ interface DrawPolygon extends DrawFeatureBase { } interface DrawFeatureBase { - readonly properties: Readonly; readonly coordinates: Coordinates; readonly id: NonNullable; readonly type: GeoJsonTypes; @@ -115,6 +114,7 @@ interface DrawFeatureBase { getCoordinate(path: number): Position; updateCoordinate(path: number, lng: number, lat: number): void; setProperty(property: string, value: any): void; + properties: Readonly; toGeoJSON(): GeoJSON; } @@ -167,7 +167,6 @@ interface DrawActionableState { } interface DrawFeatureBase { - readonly properties: Readonly; readonly coordinates: Coordinates; readonly id: NonNullable; readonly type: GeoJsonTypes; @@ -180,6 +179,7 @@ interface DrawFeatureBase { getCoordinate(path: string): Position; updateCoordinate(path: string, lng: number, lat: number): void; setProperty(property: string, value: any): void; + properties: Readonly; toGeoJSON(): GeoJSON; } @@ -712,11 +712,11 @@ export declare class Draw implements IControl { static modes: Modes; static constants: Constants; static lib: Lib; - modes: DrawModes; + modes: typeof modes; getDefaultPosition: () => ControlPosition; constructor(options?: DrawOptions); add(geojson: Feature | StrictFeatureCollection | Geometry): string[]; - get(featureId: string): Feature | undefined; + get(featureId: string): StrictFeature | undefined; getFeatureIdsAt(point: { x: number; y: number }): string[]; getSelectedIds(): string[]; getSelected(): StrictFeatureCollection; From 4755a90c5f244e8108e37073fd953d8d0485ffb6 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 16:46:31 -0400 Subject: [PATCH 39/59] Finish api --- src/feature_types/feature.ts | 2 +- src/types/types.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index f09cbfc1..8b91c4ca 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -22,7 +22,7 @@ class Feature { this.ctx.store.featureChanged(this.id); } - incomingCoords(coords: any): void { + incomingCoords(coords: number[][]): void { this.setCoordinates(coords); } diff --git a/src/types/types.ts b/src/types/types.ts index 26653eab..305e22e6 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -108,7 +108,7 @@ interface DrawFeatureBase { changed(): void; isValid(): boolean; - incomingCoords: this['setCoordinates']; + incomingCoords(coords: number[][]): void; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; getCoordinate(path: number): Position; @@ -173,7 +173,6 @@ interface DrawFeatureBase { changed(): void; isValid(): boolean; - incomingCoords: this['setCoordinates']; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; getCoordinate(path: string): Position; @@ -655,7 +654,7 @@ interface DrawStore { setSelectedCoordinates( coords: DrawCoords ): void; - getSelectedCoordinates(): Coords[]; + getSelectedCoordinates(): { coordinates: Coords[] }[] getSelected(): DrawFeature[]; getSelectedIds(): string[]; isSelected(id: string): boolean; From 7276daa8355cf373d84108867d3befbd4173a313 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 17:09:15 -0400 Subject: [PATCH 40/59] Add ts-node loader and drop js extensions in test files --- package-lock.json | 174 ++++++++++++++++++++++- package.json | 7 +- test/common_selectors.test.js | 2 +- test/constrain_feature_movement.test.js | 4 +- test/create_supplementary_points.test.js | 4 +- test/create_vertex.test.js | 2 +- test/draw_line_string.test.js | 18 +-- test/draw_point.test.js | 16 +-- test/draw_polygon.test.js | 18 +-- test/euclidean_distance.test.js | 2 +- test/feature.test.js | 8 +- test/interaction_events.test.js | 6 +- test/is_click.test.js | 4 +- test/is_event_at_coordinates.test.js | 2 +- test/is_tap.test.js | 4 +- test/map_event_to_bounding_box.test.js | 2 +- test/mode_handler.test.js | 6 +- test/mouse_event_point.test.js | 2 +- test/move_features.test.js | 12 +- test/multi_feature.test.js | 14 +- test/sort_features.test.js | 2 +- test/store.test.js | 8 +- test/string_set.test.js | 2 +- test/ui.test.js | 2 +- test/utils/create_feature.js | 4 +- test/utils/draw_geometry.js | 6 +- 26 files changed, 248 insertions(+), 83 deletions(-) diff --git a/package-lock.json b/package-lock.json index 057927a4..a1d0a63d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "rollup": "^4.19.1", "sinon": "^19.0.2", "synthetic-dom-events": "0.3.0", + "ts-node": "^10.9.2", "typescript": "^5.8.2", "vite": "^6.0.2", "vite-plugin-tsconfig-paths": "^1.4.1" @@ -92,6 +93,28 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", @@ -640,8 +663,6 @@ "version": "3.1.2", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=6.0.0" } @@ -670,9 +691,7 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -1386,6 +1405,30 @@ "node": ">=10" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@turf/bbox-clip": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-7.2.0.tgz", @@ -1748,6 +1791,30 @@ "acorn": "^4.0.4" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk/node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -1800,6 +1867,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "dev": true, @@ -2399,6 +2472,12 @@ "dev": true, "license": "MIT" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "dev": true, @@ -5012,6 +5091,12 @@ "dev": true, "license": "MIT" }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -7110,6 +7195,70 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -7333,6 +7482,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "dev": true, @@ -7734,6 +7889,15 @@ "node": ">=10" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "dev": true, diff --git a/package.json b/package.json index 76ffc063..4dfa4458 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,10 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", - "lint": "eslint src/**/*.ts test/**/*.ts", + "lint": "eslint src/**/*.ts", "pretest": "npm run lint", - "test": "node --test --import ./test/mock-browser.js", - "coverage": "node --test --import ./test/mock-browser.js --experimental-test-coverage", + "test": "node --loader ts-node/esm --test --import ./test/mock-browser.js", + "coverage": "node --loader ts-node/esm --test --import ./test/mock-browser.js --experimental-test-coverage", "build-token": "node build/generate-access-token-script.js", "build": "rollup -c", "build-min": "rollup -c --environment MINIFY:true", @@ -74,6 +74,7 @@ "rollup": "^4.19.1", "sinon": "^19.0.2", "synthetic-dom-events": "0.3.0", + "ts-node": "^10.9.2", "typescript": "^5.8.2", "vite": "^6.0.2", "vite-plugin-tsconfig-paths": "^1.4.1" diff --git a/test/common_selectors.test.js b/test/common_selectors.test.js index 6816459a..91519db3 100644 --- a/test/common_selectors.test.js +++ b/test/common_selectors.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import * as commonSelectors from '../src/lib/common_selectors.js'; +import * as commonSelectors from '../src/lib/common_selectors'; test('commonSelectors.isOfMetaType', () => { const isFoo = commonSelectors.isOfMetaType('foo'); diff --git a/test/constrain_feature_movement.test.js b/test/constrain_feature_movement.test.js index 6545d294..68599d1d 100644 --- a/test/constrain_feature_movement.test.js +++ b/test/constrain_feature_movement.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import getGeoJSON from './utils/get_geojson.js'; -import constrainFeatureMovement from '../src/lib/constrain_feature_movement.js'; +import getGeoJSON from './utils/get_geojson'; +import constrainFeatureMovement from '../src/lib/constrain_feature_movement'; test('constrainFeatureMovement point, no constraint', () => { const point = getGeoJSON('point'); diff --git a/test/create_supplementary_points.test.js b/test/create_supplementary_points.test.js index 37458713..b467572d 100644 --- a/test/create_supplementary_points.test.js +++ b/test/create_supplementary_points.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import createMap from './utils/create_map.js'; -import { createSupplementaryPoints } from '../src/lib/create_supplementary_points.js'; +import createMap from './utils/create_map'; +import { createSupplementaryPoints } from '../src/lib/create_supplementary_points'; test('createSupplementaryPoints with a point', () => { const point = { diff --git a/test/create_vertex.test.js b/test/create_vertex.test.js index 9b839ead..996ed8cd 100644 --- a/test/create_vertex.test.js +++ b/test/create_vertex.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import { createVertex } from '../src/lib/create_vertex.js'; +import { createVertex } from '../src/lib/create_vertex'; test('createVertex', () => { assert.deepEqual(createVertex('foo', [1, 2], '3.4.5', true), { diff --git a/test/draw_line_string.test.js b/test/draw_line_string.test.js index f8057ff3..f92d8d21 100644 --- a/test/draw_line_string.test.js +++ b/test/draw_line_string.test.js @@ -4,14 +4,14 @@ import MapboxDraw from '../index'; import mouseClick from './utils/mouse_click'; import touchTap from './utils/touch_tap'; import createMap from './utils/create_map'; -import makeMouseEvent from './utils/make_mouse_event.js'; -import makeTouchEvent from './utils/make_touch_event.js'; -import drawLineStringModeObject from '../src/modes/draw_line_string.js'; -import LineString from '../src/feature_types/line_string.js'; -import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; -import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; -import { objectToMode } from '../src/modes/object_to_mode.js'; -import { setupAfterNextRender } from './utils/after_next_render.js'; +import makeMouseEvent from './utils/make_mouse_event'; +import makeTouchEvent from './utils/make_touch_event'; +import drawLineStringModeObject from '../src/modes/draw_line_string'; +import LineString from '../src/feature_types/line_string'; +import createMockDrawModeContext from './utils/create_mock_draw_mode_context'; +import createMockLifecycleContext from './utils/create_mock_lifecycle_context'; +import { objectToMode } from '../src/modes/object_to_mode'; +import { setupAfterNextRender } from './utils/after_next_render'; const drawLineStringMode = objectToMode(drawLineStringModeObject); @@ -21,7 +21,7 @@ import { startLineStringEvent, startPolygonEvent, escapeEvent -} from './utils/key_events.js'; +} from './utils/key_events'; test('draw_line_string mode initialization', () => { const context = createMockDrawModeContext(); diff --git a/test/draw_point.test.js b/test/draw_point.test.js index 2d88a5b0..1fbfb5df 100644 --- a/test/draw_point.test.js +++ b/test/draw_point.test.js @@ -4,14 +4,14 @@ import MapboxDraw from '../index'; import mouseClick from './utils/mouse_click'; import touchTap from './utils/touch_tap'; import createMap from './utils/create_map'; -import makeMouseEvent from './utils/make_mouse_event.js'; -import makeTouchEvent from './utils/make_touch_event.js'; -import drawPointModeObject from '../src/modes/draw_point.js'; -import Point from '../src/feature_types/point.js'; -import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; -import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; -import { escapeEvent, enterEvent } from './utils/key_events.js'; -import { objectToMode } from '../src/modes/object_to_mode.js'; +import makeMouseEvent from './utils/make_mouse_event'; +import makeTouchEvent from './utils/make_touch_event'; +import drawPointModeObject from '../src/modes/draw_point'; +import Point from '../src/feature_types/point'; +import createMockDrawModeContext from './utils/create_mock_draw_mode_context'; +import createMockLifecycleContext from './utils/create_mock_lifecycle_context'; +import { escapeEvent, enterEvent } from './utils/key_events'; +import { objectToMode } from '../src/modes/object_to_mode'; const drawPointMode = objectToMode(drawPointModeObject); test('draw_point mode initialization', () => { diff --git a/test/draw_polygon.test.js b/test/draw_polygon.test.js index e72c42d4..2ca09acd 100644 --- a/test/draw_polygon.test.js +++ b/test/draw_polygon.test.js @@ -4,14 +4,14 @@ import MapboxDraw from '../index'; import createMap from './utils/create_map'; import mouseClick from './utils/mouse_click'; import touchTap from './utils/touch_tap'; -import makeMouseEvent from './utils/make_mouse_event.js'; -import makeTouchEvent from './utils/make_touch_event.js'; -import drawPolygonModeObject from '../src/modes/draw_polygon.js'; -import Polygon from '../src/feature_types/polygon.js'; -import createMockDrawModeContext from './utils/create_mock_draw_mode_context.js'; -import createMockLifecycleContext from './utils/create_mock_lifecycle_context.js'; -import { setupAfterNextRender } from './utils/after_next_render.js'; -import { objectToMode } from '../src/modes/object_to_mode.js'; +import makeMouseEvent from './utils/make_mouse_event'; +import makeTouchEvent from './utils/make_touch_event'; +import drawPolygonModeObject from '../src/modes/draw_polygon'; +import Polygon from '../src/feature_types/polygon'; +import createMockDrawModeContext from './utils/create_mock_draw_mode_context'; +import createMockLifecycleContext from './utils/create_mock_lifecycle_context'; +import { setupAfterNextRender } from './utils/after_next_render'; +import { objectToMode } from '../src/modes/object_to_mode'; const drawPolygonMode = objectToMode(drawPolygonModeObject); import { @@ -20,7 +20,7 @@ import { startLineStringEvent, startPolygonEvent, escapeEvent -} from './utils/key_events.js'; +} from './utils/key_events'; test('draw_polygon mode initialization', () => { const context = createMockDrawModeContext(); diff --git a/test/euclidean_distance.test.js b/test/euclidean_distance.test.js index 4fb7ea86..21e6a86e 100644 --- a/test/euclidean_distance.test.js +++ b/test/euclidean_distance.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import euclideanDistance from '../src/lib/euclidean_distance.js'; +import euclideanDistance from '../src/lib/euclidean_distance'; test('euclideanDistance', () => { assert.equal( diff --git a/test/feature.test.js b/test/feature.test.js index b4055783..38423eb1 100644 --- a/test/feature.test.js +++ b/test/feature.test.js @@ -2,10 +2,10 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; -import Feature from '../src/feature_types/feature.js'; -import createFeature from './utils/create_feature.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; -import createMockCtx from './utils/create_mock_feature_context.js'; +import Feature from '../src/feature_types/feature'; +import createFeature from './utils/create_feature'; +import getPublicMemberKeys from './utils/get_public_member_keys'; +import createMockCtx from './utils/create_mock_feature_context'; test('Feature contrusctor and API', () => { const featureGeoJson = createFeature('line'); diff --git a/test/interaction_events.test.js b/test/interaction_events.test.js index e2e81e9c..d91fe545 100644 --- a/test/interaction_events.test.js +++ b/test/interaction_events.test.js @@ -6,10 +6,10 @@ import { spy } from 'sinon'; import MapboxDraw from '../index'; import click from './utils/mouse_click'; import createMap from './utils/create_map'; -import { setupAfterNextRender } from './utils/after_next_render.js'; -import makeMouseEvent from './utils/make_mouse_event.js'; +import { setupAfterNextRender } from './utils/after_next_render'; +import makeMouseEvent from './utils/make_mouse_event'; -import { backspaceEvent, enterEvent, escapeEvent } from './utils/key_events.js'; +import { backspaceEvent, enterEvent, escapeEvent } from './utils/key_events'; test('ensure user interactions fire right events', async t => { const container = document.createElement('div'); diff --git a/test/is_click.test.js b/test/is_click.test.js index fb3a167c..1f7302b7 100644 --- a/test/is_click.test.js +++ b/test/is_click.test.js @@ -1,10 +1,10 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import { isClick } from '../src/lib/is_click.js'; +import { isClick } from '../src/lib/is_click'; // By adding these values as options and stating them in the test, // we can know the calculation works from the tests, but tweak -// the actual constants in `is_click.js` without having to +// the actual constants in `is_click` without having to // rewrite tests. const testOptions = { fineTolerance: 4, diff --git a/test/is_event_at_coordinates.test.js b/test/is_event_at_coordinates.test.js index 0abefbaf..8e568d20 100644 --- a/test/is_event_at_coordinates.test.js +++ b/test/is_event_at_coordinates.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import { isEventAtCoordinates } from '../src/lib/is_event_at_coordinates.js'; +import { isEventAtCoordinates } from '../src/lib/is_event_at_coordinates'; test('isEventAtCoordinates', () => { assert.ok( diff --git a/test/is_tap.test.js b/test/is_tap.test.js index 0764d2cc..49b0b073 100644 --- a/test/is_tap.test.js +++ b/test/is_tap.test.js @@ -1,10 +1,10 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import { isTap } from '../src/lib/is_tap.js'; +import { isTap } from '../src/lib/is_tap'; // By adding these values as options and stating them in the test, // we can know the calculation works from the tests, but tweak -// the actual constants in `is_tap.js` without having to +// the actual constants in `is_tap` without having to // rewrite tests. const testOptions = { tolerance: 25, diff --git a/test/map_event_to_bounding_box.test.js b/test/map_event_to_bounding_box.test.js index cf193ec1..2bbe289c 100644 --- a/test/map_event_to_bounding_box.test.js +++ b/test/map_event_to_bounding_box.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import mapEventToBoundingBox from '../src/lib/map_event_to_bounding_box.js'; +import mapEventToBoundingBox from '../src/lib/map_event_to_bounding_box'; test('mapEventToBoundingBox', () => { assert.deepEqual( diff --git a/test/mode_handler.test.js b/test/mode_handler.test.js index 1a2ad307..b620d9af 100644 --- a/test/mode_handler.test.js +++ b/test/mode_handler.test.js @@ -1,9 +1,9 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; -import modeHandler from '../src/lib/mode_handler.js'; -import createMockModeHandlerContext from './utils/create_mock_mode_handler_context.js'; -import createMockMode from './utils/create_mock_mode.js'; +import modeHandler from '../src/lib/mode_handler'; +import createMockModeHandlerContext from './utils/create_mock_mode_handler_context'; +import createMockMode from './utils/create_mock_mode'; test('returned API', () => { const mh = modeHandler(createMockMode(), createMockModeHandlerContext()); diff --git a/test/mouse_event_point.test.js b/test/mouse_event_point.test.js index a4ab1e1e..24fea507 100644 --- a/test/mouse_event_point.test.js +++ b/test/mouse_event_point.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import Point from '@mapbox/point-geometry'; -import mouseEventPoint from '../src/lib/mouse_event_point.js'; +import mouseEventPoint from '../src/lib/mouse_event_point'; test('mouseEventPoint', () => { const mockContainer = { diff --git a/test/move_features.test.js b/test/move_features.test.js index 82f14859..620a376e 100644 --- a/test/move_features.test.js +++ b/test/move_features.test.js @@ -1,11 +1,11 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import getGeoJSON from './utils/get_geojson.js'; -import createMockFeatureContext from './utils/create_mock_feature_context.js'; -import Point from '../src/feature_types/point.js'; -import LineString from '../src/feature_types/line_string.js'; -import Polygon from '../src/feature_types/polygon.js'; -import moveFeatures from '../src/lib/move_features.js'; +import getGeoJSON from './utils/get_geojson'; +import createMockFeatureContext from './utils/create_mock_feature_context'; +import Point from '../src/feature_types/point'; +import LineString from '../src/feature_types/line_string'; +import Polygon from '../src/feature_types/polygon'; +import moveFeatures from '../src/lib/move_features'; const mockFeatureContext = createMockFeatureContext(); diff --git a/test/multi_feature.test.js b/test/multi_feature.test.js index b49dfee9..d2096fea 100644 --- a/test/multi_feature.test.js +++ b/test/multi_feature.test.js @@ -1,13 +1,13 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; -import Feature from '../src/feature_types/feature.js'; -import Point from '../src/feature_types/point.js'; -import Polygon from '../src/feature_types/polygon.js'; -import LineString from '../src/feature_types/line_string.js'; -import MultiFeature from '../src/feature_types/multi_feature.js'; -import createMockCtx from './utils/create_mock_feature_context.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; +import Feature from '../src/feature_types/feature'; +import Point from '../src/feature_types/point'; +import Polygon from '../src/feature_types/polygon'; +import LineString from '../src/feature_types/line_string'; +import MultiFeature from '../src/feature_types/multi_feature'; +import createMockCtx from './utils/create_mock_feature_context'; +import getPublicMemberKeys from './utils/get_public_member_keys'; test('MultiPoint via MultiFeature', () => { assert.ok(MultiFeature.prototype instanceof Feature, 'inherits from Feature'); diff --git a/test/sort_features.test.js b/test/sort_features.test.js index 98d17e08..79b92309 100644 --- a/test/sort_features.test.js +++ b/test/sort_features.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import sortFeatures from '../src/lib/sort_features.js'; +import sortFeatures from '../src/lib/sort_features'; test('sortFeatures', () => { const features = [ diff --git a/test/store.test.js b/test/store.test.js index 9066318d..cba8d3e5 100644 --- a/test/store.test.js +++ b/test/store.test.js @@ -2,10 +2,10 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; -import Store from '../src/store.js'; -import createFeature from './utils/create_feature.js'; -import getPublicMemberKeys from './utils/get_public_member_keys.js'; -import createMap from './utils/create_map.js'; +import Store from '../src/store'; +import createFeature from './utils/create_feature'; +import getPublicMemberKeys from './utils/get_public_member_keys'; +import createMap from './utils/create_map'; function createStore() { const ctx = { diff --git a/test/string_set.test.js b/test/string_set.test.js index 830a612d..97342183 100644 --- a/test/string_set.test.js +++ b/test/string_set.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import StringSet from '../src/lib/string_set.js'; +import StringSet from '../src/lib/string_set'; test('StringSet constructor and API', () => { const set = new StringSet(); diff --git a/test/ui.test.js b/test/ui.test.js index 2906f9ee..a050a02f 100644 --- a/test/ui.test.js +++ b/test/ui.test.js @@ -2,7 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; -import ui from '../src/ui.js'; +import ui from '../src/ui'; function createMockContext({ position, controls } = {}) { const container = document.createElement('div'); diff --git a/test/utils/create_feature.js b/test/utils/create_feature.js index 59864671..d87e474e 100644 --- a/test/utils/create_feature.js +++ b/test/utils/create_feature.js @@ -1,5 +1,5 @@ -import { generateID } from '../../src/lib/id.js'; -import getGeoJSON from './get_geojson.js'; +import { generateID } from '../../src/lib/id'; +import getGeoJSON from './get_geojson'; const usedIds = new Set(); diff --git a/test/utils/draw_geometry.js b/test/utils/draw_geometry.js index a83fd23a..7622e8b0 100644 --- a/test/utils/draw_geometry.js +++ b/test/utils/draw_geometry.js @@ -1,6 +1,6 @@ -import click from './mouse_click.js'; -import { setupAfterNextRender } from './after_next_render.js'; -import makeMouseEvent from './make_mouse_event.js'; +import click from './mouse_click'; +import { setupAfterNextRender } from './after_next_render'; +import makeMouseEvent from './make_mouse_event'; /** * Draws a feature on a map. From 8560abb1dafb6e70162653e689f5cc364b0e2540 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 17:25:49 -0400 Subject: [PATCH 41/59] Convert the rest of lib to named exports --- src/lib/features_at.ts | 4 ++-- src/lib/index.ts | 6 +++--- src/lib/map_event_to_bounding_box.ts | 6 ++---- src/lib/mouse_event_point.ts | 6 ++---- src/lib/move_features.ts | 2 +- src/lib/sort_features.ts | 6 ++---- src/modes/direct_select.ts | 2 +- src/modes/simple_select.ts | 4 ++-- test/map_event_to_bounding_box.test.js | 2 +- test/mouse_event_point.test.js | 2 +- test/move_features.test.js | 2 +- test/sort_features.test.js | 2 +- tsconfig.json | 3 +-- 13 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index 01e7876a..74af2ab0 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -1,5 +1,5 @@ -import sortFeatures from './sort_features'; -import mapEventToBoundingBox from './map_event_to_bounding_box'; +import { sortFeatures } from './sort_features'; +import { mapEventToBoundingBox } from './map_event_to_bounding_box'; import * as Constants from '../constants'; import StringSet from './string_set'; diff --git a/src/lib/index.ts b/src/lib/index.ts index e5de82c8..a37cdcbb 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -10,10 +10,10 @@ import { getFeatureAtAndSetCursors } from './get_features_at_and_set_cursor'; import { isClick } from './is_click'; import { isEventAtCoordinates } from './is_event_at_coordinates'; import { isTap } from './is_tap'; -import mapEventToBoundingBox from './map_event_to_bounding_box'; +import { sortFeatures } from './sort_features'; +import { mapEventToBoundingBox } from './map_event_to_bounding_box'; import ModeHandler from './mode_handler'; -import moveFeatures from './move_features'; -import sortFeatures from './sort_features'; +import { moveFeatures } from './move_features'; import StringSet from './string_set'; import { stringSetsAreEqual } from './string_sets_are_equal'; import theme from './theme'; diff --git a/src/lib/map_event_to_bounding_box.ts b/src/lib/map_event_to_bounding_box.ts index dca019d2..25f52cb5 100644 --- a/src/lib/map_event_to_bounding_box.ts +++ b/src/lib/map_event_to_bounding_box.ts @@ -1,14 +1,12 @@ import type { Position } from 'geojson'; import type { MapMouseEvent, MapTouchEvent } from '../types/types'; -function mapEventToBoundingBox( +export const mapEventToBoundingBox = ( mapEvent: MapMouseEvent | MapTouchEvent, buffer: number = 0 -): Position[] { +): Position[] => { return [ [mapEvent.point.x - buffer, mapEvent.point.y - buffer], [mapEvent.point.x + buffer, mapEvent.point.y + buffer] ]; } - -export default mapEventToBoundingBox; diff --git a/src/lib/mouse_event_point.ts b/src/lib/mouse_event_point.ts index 3b1311c0..fc3a8f1e 100644 --- a/src/lib/mouse_event_point.ts +++ b/src/lib/mouse_event_point.ts @@ -1,15 +1,13 @@ import Point from '@mapbox/point-geometry'; import type { PointLike } from 'mapbox-gl'; -function mouseEventPoint( +export const mouseEventPoint = ( mouseEvent: MouseEvent, container: HTMLElement -): PointLike { +): PointLike => { const rect = container.getBoundingClientRect(); return new Point( mouseEvent.clientX - rect.left - (container.clientLeft || 0), mouseEvent.clientY - rect.top - (container.clientTop || 0) ); } - -export default mouseEventPoint; diff --git a/src/lib/move_features.ts b/src/lib/move_features.ts index ffe4d9c2..48abea86 100644 --- a/src/lib/move_features.ts +++ b/src/lib/move_features.ts @@ -1,7 +1,7 @@ import { constrainFeatureMovement } from './constrain_feature_movement'; import * as Constants from '../constants'; -export default function (features, delta) { +export const moveFeatures = (features, delta) => { const constrainedDelta = constrainFeatureMovement( features.map(feature => feature.toGeoJSON()), delta diff --git a/src/lib/sort_features.ts b/src/lib/sort_features.ts index ce071e55..0510a559 100644 --- a/src/lib/sort_features.ts +++ b/src/lib/sort_features.ts @@ -16,7 +16,7 @@ interface DrawFeature extends Feature { area?: number; } -function comparator(a: DrawFeature, b: DrawFeature) { +const comparator = (a: DrawFeature, b: DrawFeature) => { const score = FEATURE_SORT_RANKS[a.geometry.type] - FEATURE_SORT_RANKS[b.geometry.type]; @@ -33,7 +33,7 @@ function comparator(a: DrawFeature, b: DrawFeature) { } // Sort in the order above, then sort polygons by area ascending. -function sortFeatures(features: Array) { +export const sortFeatures = (features: Array) => { return features .map(feature => { if (feature.geometry.type === Constants.geojsonTypes.POLYGON) { @@ -51,5 +51,3 @@ function sortFeatures(features: Array) { return feature; }); } - -export default sortFeatures; diff --git a/src/modes/direct_select.ts b/src/modes/direct_select.ts index 4145f434..a53d4d20 100644 --- a/src/modes/direct_select.ts +++ b/src/modes/direct_select.ts @@ -8,8 +8,8 @@ import { import { createSupplementaryPoints } from '../lib/create_supplementary_points'; import { constrainFeatureMovement } from '../lib/constrain_feature_movement'; import { doubleClickZoom } from '../lib/double_click_zoom'; +import { moveFeatures } from '../lib/move_features'; import * as Constants from '../constants'; -import moveFeatures from '../lib/move_features'; import type { DirectSelectState, DrawCustomMode, MapMouseEvent, MapTouchEvent, DrawCoords, StrictFeature } from '../types/types'; diff --git a/src/modes/simple_select.ts b/src/modes/simple_select.ts index 4cca80b4..00d800b2 100644 --- a/src/modes/simple_select.ts +++ b/src/modes/simple_select.ts @@ -1,9 +1,9 @@ import * as CommonSelectors from '../lib/common_selectors'; -import mouseEventPoint from '../lib/mouse_event_point'; +import { mouseEventPoint } from '../lib/mouse_event_point'; import { createSupplementaryPoints } from '../lib/create_supplementary_points'; import StringSet from '../lib/string_set'; import { doubleClickZoom } from '../lib/double_click_zoom'; -import moveFeatures from '../lib/move_features'; +import { moveFeatures } from '../lib/move_features'; import * as Constants from '../constants'; const SimpleSelect = { diff --git a/test/map_event_to_bounding_box.test.js b/test/map_event_to_bounding_box.test.js index 2bbe289c..1bb44b3c 100644 --- a/test/map_event_to_bounding_box.test.js +++ b/test/map_event_to_bounding_box.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import mapEventToBoundingBox from '../src/lib/map_event_to_bounding_box'; +import { mapEventToBoundingBox } from '../src/lib/map_event_to_bounding_box'; test('mapEventToBoundingBox', () => { assert.deepEqual( diff --git a/test/mouse_event_point.test.js b/test/mouse_event_point.test.js index 24fea507..a1844192 100644 --- a/test/mouse_event_point.test.js +++ b/test/mouse_event_point.test.js @@ -1,7 +1,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import Point from '@mapbox/point-geometry'; -import mouseEventPoint from '../src/lib/mouse_event_point'; +import { mouseEventPoint } from '../src/lib/mouse_event_point'; test('mouseEventPoint', () => { const mockContainer = { diff --git a/test/move_features.test.js b/test/move_features.test.js index 620a376e..fc9412ac 100644 --- a/test/move_features.test.js +++ b/test/move_features.test.js @@ -5,7 +5,7 @@ import createMockFeatureContext from './utils/create_mock_feature_context'; import Point from '../src/feature_types/point'; import LineString from '../src/feature_types/line_string'; import Polygon from '../src/feature_types/polygon'; -import moveFeatures from '../src/lib/move_features'; +import { moveFeatures } from '../src/lib/move_features'; const mockFeatureContext = createMockFeatureContext(); diff --git a/test/sort_features.test.js b/test/sort_features.test.js index 79b92309..c939ff6f 100644 --- a/test/sort_features.test.js +++ b/test/sort_features.test.js @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import sortFeatures from '../src/lib/sort_features'; +import { sortFeatures } from '../src/lib/sort_features'; test('sortFeatures', () => { const features = [ diff --git a/tsconfig.json b/tsconfig.json index b121e998..963f5e8c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ }, "include": [ "./src/**/*", - "./test/**/*", - "./bench/**/*" + "./test/**/*" ] } From 77877c4ace73f094a0ba046c32ab6b2ce497c632 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 18:02:01 -0400 Subject: [PATCH 42/59] Move test files to typescript --- .gitignore | 1 - package.json | 4 ++-- src/types/types.ts | 8 -------- test/{api.test.js => api.test.ts} | 1 + ...{common_selectors.test.js => common_selectors.test.ts} | 1 + ...ovement.test.js => constrain_feature_movement.test.ts} | 1 + ...points.test.js => create_supplementary_points.test.ts} | 1 + test/{create_vertex.test.js => create_vertex.test.ts} | 1 + test/{direct_select.test.js => direct_select.test.ts} | 1 + ...{draw_line_string.test.js => draw_line_string.test.ts} | 1 + test/{draw_point.test.js => draw_point.test.ts} | 1 + test/{draw_polygon.test.js => draw_polygon.test.ts} | 1 + ...lidean_distance.test.js => euclidean_distance.test.ts} | 1 + test/{feature.test.js => feature.test.ts} | 1 + test/{features_at.test.js => features_at.test.ts} | 1 + ...eraction_events.test.js => interaction_events.test.ts} | 1 + test/{is_click.test.js => is_click.test.ts} | 1 + ...oordinates.test.js => is_event_at_coordinates.test.ts} | 1 + test/{is_tap.test.js => is_tap.test.ts} | 1 + test/{line_string.test.js => line_string.test.ts} | 1 + ...ding_box.test.js => map_event_to_bounding_box.test.ts} | 1 + test/{mock-browser.js => mock-browser.ts} | 0 test/{mode_handler.test.js => mode_handler.test.ts} | 1 + ...ouse_event_point.test.js => mouse_event_point.test.ts} | 1 + test/{move_features.test.js => move_features.test.ts} | 1 + test/{multi_feature.test.js => multi_feature.test.ts} | 1 + test/{options.test.js => options.test.ts} | 1 + test/{point.test.js => point.test.ts} | 1 + test/{polygon.test.js => polygon.test.ts} | 1 + test/{simple_select.test.js => simple_select.test.ts} | 1 + test/{sort_features.test.js => sort_features.test.ts} | 1 + test/{static.test.js => static.test.ts} | 1 + test/{store.test.js => store.test.ts} | 1 + test/{string_set.test.js => string_set.test.ts} | 1 + test/{ui.test.js => ui.test.ts} | 1 + test/utils/{after_next_render.js => after_next_render.ts} | 0 test/utils/{create_feature.js => create_feature.ts} | 0 test/utils/{create_map.js => create_map.ts} | 0 ...w_mode_context.js => create_mock_draw_mode_context.ts} | 0 ..._feature_context.js => create_mock_feature_context.ts} | 0 ...ecycle_context.js => create_mock_lifecycle_context.ts} | 0 test/utils/{create_mock_mode.js => create_mock_mode.ts} | 0 ...ler_context.js => create_mock_mode_handler_context.ts} | 0 test/utils/{draw_geometry.js => draw_geometry.ts} | 0 test/utils/{get_geojson.js => get_geojson.ts} | 0 ...et_public_member_keys.js => get_public_member_keys.ts} | 0 test/utils/{key_events.js => key_events.ts} | 0 test/utils/{make_mouse_event.js => make_mouse_event.ts} | 0 test/utils/{make_touch_event.js => make_touch_event.ts} | 0 test/utils/{mouse_click.js => mouse_click.ts} | 0 test/utils/{touch_tap.js => touch_tap.ts} | 0 tsconfig.json | 4 +++- 52 files changed, 36 insertions(+), 12 deletions(-) rename test/{api.test.js => api.test.ts} (99%) rename test/{common_selectors.test.js => common_selectors.test.ts} (99%) rename test/{constrain_feature_movement.test.js => constrain_feature_movement.test.ts} (99%) rename test/{create_supplementary_points.test.js => create_supplementary_points.test.ts} (99%) rename test/{create_vertex.test.js => create_vertex.test.ts} (96%) rename test/{direct_select.test.js => direct_select.test.ts} (99%) rename test/{draw_line_string.test.js => draw_line_string.test.ts} (99%) rename test/{draw_point.test.js => draw_point.test.ts} (99%) rename test/{draw_polygon.test.js => draw_polygon.test.ts} (99%) rename test/{euclidean_distance.test.js => euclidean_distance.test.ts} (93%) rename test/{feature.test.js => feature.test.ts} (99%) rename test/{features_at.test.js => features_at.test.ts} (99%) rename test/{interaction_events.test.js => interaction_events.test.ts} (99%) rename test/{is_click.test.js => is_click.test.ts} (99%) rename test/{is_event_at_coordinates.test.js => is_event_at_coordinates.test.ts} (96%) rename test/{is_tap.test.js => is_tap.test.ts} (98%) rename test/{line_string.test.js => line_string.test.ts} (99%) rename test/{map_event_to_bounding_box.test.js => map_event_to_bounding_box.test.ts} (96%) rename test/{mock-browser.js => mock-browser.ts} (100%) rename test/{mode_handler.test.js => mode_handler.test.ts} (99%) rename test/{mouse_event_point.test.js => mouse_event_point.test.ts} (96%) rename test/{move_features.test.js => move_features.test.ts} (99%) rename test/{multi_feature.test.js => multi_feature.test.ts} (99%) rename test/{options.test.js => options.test.ts} (99%) rename test/{point.test.js => point.test.ts} (99%) rename test/{polygon.test.js => polygon.test.ts} (99%) rename test/{simple_select.test.js => simple_select.test.ts} (99%) rename test/{sort_features.test.js => sort_features.test.ts} (98%) rename test/{static.test.js => static.test.ts} (99%) rename test/{store.test.js => store.test.ts} (99%) rename test/{string_set.test.js => string_set.test.ts} (99%) rename test/{ui.test.js => ui.test.ts} (99%) rename test/utils/{after_next_render.js => after_next_render.ts} (100%) rename test/utils/{create_feature.js => create_feature.ts} (100%) rename test/utils/{create_map.js => create_map.ts} (100%) rename test/utils/{create_mock_draw_mode_context.js => create_mock_draw_mode_context.ts} (100%) rename test/utils/{create_mock_feature_context.js => create_mock_feature_context.ts} (100%) rename test/utils/{create_mock_lifecycle_context.js => create_mock_lifecycle_context.ts} (100%) rename test/utils/{create_mock_mode.js => create_mock_mode.ts} (100%) rename test/utils/{create_mock_mode_handler_context.js => create_mock_mode_handler_context.ts} (100%) rename test/utils/{draw_geometry.js => draw_geometry.ts} (100%) rename test/utils/{get_geojson.js => get_geojson.ts} (100%) rename test/utils/{get_public_member_keys.js => get_public_member_keys.ts} (100%) rename test/utils/{key_events.js => key_events.ts} (100%) rename test/utils/{make_mouse_event.js => make_mouse_event.ts} (100%) rename test/utils/{make_touch_event.js => make_touch_event.ts} (100%) rename test/utils/{mouse_click.js => mouse_click.ts} (100%) rename test/utils/{touch_tap.js => touch_tap.ts} (100%) diff --git a/.gitignore b/.gitignore index 95ab04dc..55540ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,4 @@ dist/mapbox-gl-draw-unminified.js.map dist/bench.js dist/bench.js.map coverage/ -.nyc_output/ debug/access_token_generated.js diff --git a/package.json b/package.json index 4dfa4458..8f7653ef 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", "lint": "eslint src/**/*.ts", "pretest": "npm run lint", - "test": "node --loader ts-node/esm --test --import ./test/mock-browser.js", - "coverage": "node --loader ts-node/esm --test --import ./test/mock-browser.js --experimental-test-coverage", + "test": "node --loader ts-node/esm --test test/*.test.ts", + "coverage": "node --loader ts-node/esm --test test/*.test.ts --experimental-test-coverage", "build-token": "node build/generate-access-token-script.js", "build": "rollup -c", "build-min": "rollup -c --environment MINIFY:true", diff --git a/src/types/types.ts b/src/types/types.ts index 305e22e6..decd1485 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -74,14 +74,6 @@ interface Modes { direct_select: DrawCustomMode; } -export interface SelectedDrawModeFeature { - id: string; - type: string; - ctx: CTX; - properties: Record - coordinates: Array<[number, number]> -} - interface DrawPoint extends DrawFeatureBase { readonly type: 'Point'; getCoordinate(): Position; diff --git a/test/api.test.js b/test/api.test.ts similarity index 99% rename from test/api.test.js rename to test/api.test.ts index fb6c76d5..b4805803 100644 --- a/test/api.test.js +++ b/test/api.test.ts @@ -1,4 +1,5 @@ /* eslint no-shadow:[0] */ +import './mock-browser'; import { test, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/common_selectors.test.js b/test/common_selectors.test.ts similarity index 99% rename from test/common_selectors.test.js rename to test/common_selectors.test.ts index 91519db3..c6d2389b 100644 --- a/test/common_selectors.test.js +++ b/test/common_selectors.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; diff --git a/test/constrain_feature_movement.test.js b/test/constrain_feature_movement.test.ts similarity index 99% rename from test/constrain_feature_movement.test.js rename to test/constrain_feature_movement.test.ts index 68599d1d..e83e83fc 100644 --- a/test/constrain_feature_movement.test.js +++ b/test/constrain_feature_movement.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import getGeoJSON from './utils/get_geojson'; diff --git a/test/create_supplementary_points.test.js b/test/create_supplementary_points.test.ts similarity index 99% rename from test/create_supplementary_points.test.js rename to test/create_supplementary_points.test.ts index b467572d..42877f00 100644 --- a/test/create_supplementary_points.test.js +++ b/test/create_supplementary_points.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import createMap from './utils/create_map'; diff --git a/test/create_vertex.test.js b/test/create_vertex.test.ts similarity index 96% rename from test/create_vertex.test.js rename to test/create_vertex.test.ts index 996ed8cd..a8cbe9b3 100644 --- a/test/create_vertex.test.js +++ b/test/create_vertex.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { createVertex } from '../src/lib/create_vertex'; diff --git a/test/direct_select.test.js b/test/direct_select.test.ts similarity index 99% rename from test/direct_select.test.js rename to test/direct_select.test.ts index a6185fb2..ebf6a207 100644 --- a/test/direct_select.test.js +++ b/test/direct_select.test.ts @@ -1,4 +1,5 @@ /* eslint no-shadow:[0] */ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import turfCentroid from '@turf/centroid'; diff --git a/test/draw_line_string.test.js b/test/draw_line_string.test.ts similarity index 99% rename from test/draw_line_string.test.js rename to test/draw_line_string.test.ts index f92d8d21..c9956371 100644 --- a/test/draw_line_string.test.js +++ b/test/draw_line_string.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import MapboxDraw from '../index'; diff --git a/test/draw_point.test.js b/test/draw_point.test.ts similarity index 99% rename from test/draw_point.test.js rename to test/draw_point.test.ts index 1fbfb5df..4a4894e6 100644 --- a/test/draw_point.test.js +++ b/test/draw_point.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import MapboxDraw from '../index'; diff --git a/test/draw_polygon.test.js b/test/draw_polygon.test.ts similarity index 99% rename from test/draw_polygon.test.js rename to test/draw_polygon.test.ts index 2ca09acd..e29bfe18 100644 --- a/test/draw_polygon.test.js +++ b/test/draw_polygon.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import MapboxDraw from '../index'; diff --git a/test/euclidean_distance.test.js b/test/euclidean_distance.test.ts similarity index 93% rename from test/euclidean_distance.test.js rename to test/euclidean_distance.test.ts index 21e6a86e..bcce0342 100644 --- a/test/euclidean_distance.test.js +++ b/test/euclidean_distance.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import euclideanDistance from '../src/lib/euclidean_distance'; diff --git a/test/feature.test.js b/test/feature.test.ts similarity index 99% rename from test/feature.test.js rename to test/feature.test.ts index 38423eb1..934e43f7 100644 --- a/test/feature.test.js +++ b/test/feature.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; diff --git a/test/features_at.test.js b/test/features_at.test.ts similarity index 99% rename from test/features_at.test.js rename to test/features_at.test.ts index 8a68095a..113a7d6f 100644 --- a/test/features_at.test.js +++ b/test/features_at.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import * as featuresAt from '../src/lib/features_at'; diff --git a/test/interaction_events.test.js b/test/interaction_events.test.ts similarity index 99% rename from test/interaction_events.test.js rename to test/interaction_events.test.ts index d91fe545..1c4d7237 100644 --- a/test/interaction_events.test.js +++ b/test/interaction_events.test.ts @@ -1,5 +1,6 @@ // These tests ensure that user interactions fire the right events +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/is_click.test.js b/test/is_click.test.ts similarity index 99% rename from test/is_click.test.js rename to test/is_click.test.ts index 1f7302b7..6bd0a124 100644 --- a/test/is_click.test.js +++ b/test/is_click.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { isClick } from '../src/lib/is_click'; diff --git a/test/is_event_at_coordinates.test.js b/test/is_event_at_coordinates.test.ts similarity index 96% rename from test/is_event_at_coordinates.test.js rename to test/is_event_at_coordinates.test.ts index 8e568d20..4fb6d1db 100644 --- a/test/is_event_at_coordinates.test.js +++ b/test/is_event_at_coordinates.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { isEventAtCoordinates } from '../src/lib/is_event_at_coordinates'; diff --git a/test/is_tap.test.js b/test/is_tap.test.ts similarity index 98% rename from test/is_tap.test.js rename to test/is_tap.test.ts index 49b0b073..50f7cfa7 100644 --- a/test/is_tap.test.js +++ b/test/is_tap.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { isTap } from '../src/lib/is_tap'; diff --git a/test/line_string.test.js b/test/line_string.test.ts similarity index 99% rename from test/line_string.test.js rename to test/line_string.test.ts index eba49ce7..88a7ebea 100644 --- a/test/line_string.test.js +++ b/test/line_string.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/map_event_to_bounding_box.test.js b/test/map_event_to_bounding_box.test.ts similarity index 96% rename from test/map_event_to_bounding_box.test.js rename to test/map_event_to_bounding_box.test.ts index 1bb44b3c..91ce232b 100644 --- a/test/map_event_to_bounding_box.test.js +++ b/test/map_event_to_bounding_box.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { mapEventToBoundingBox } from '../src/lib/map_event_to_bounding_box'; diff --git a/test/mock-browser.js b/test/mock-browser.ts similarity index 100% rename from test/mock-browser.js rename to test/mock-browser.ts diff --git a/test/mode_handler.test.js b/test/mode_handler.test.ts similarity index 99% rename from test/mode_handler.test.js rename to test/mode_handler.test.ts index b620d9af..9ad53fee 100644 --- a/test/mode_handler.test.js +++ b/test/mode_handler.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/mouse_event_point.test.js b/test/mouse_event_point.test.ts similarity index 96% rename from test/mouse_event_point.test.js rename to test/mouse_event_point.test.ts index a1844192..639ddc7d 100644 --- a/test/mouse_event_point.test.js +++ b/test/mouse_event_point.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import Point from '@mapbox/point-geometry'; diff --git a/test/move_features.test.js b/test/move_features.test.ts similarity index 99% rename from test/move_features.test.js rename to test/move_features.test.ts index fc9412ac..e6da7adf 100644 --- a/test/move_features.test.js +++ b/test/move_features.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import getGeoJSON from './utils/get_geojson'; diff --git a/test/multi_feature.test.js b/test/multi_feature.test.ts similarity index 99% rename from test/multi_feature.test.js rename to test/multi_feature.test.ts index d2096fea..0d48e62c 100644 --- a/test/multi_feature.test.js +++ b/test/multi_feature.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/options.test.js b/test/options.test.ts similarity index 99% rename from test/options.test.js rename to test/options.test.ts index 7c976f94..c94e8e80 100644 --- a/test/options.test.js +++ b/test/options.test.ts @@ -1,4 +1,5 @@ /* eslint no-shadow:[0] */ +import './mock-browser'; import fs from 'fs'; import path from 'path'; import test from 'node:test'; diff --git a/test/point.test.js b/test/point.test.ts similarity index 99% rename from test/point.test.js rename to test/point.test.ts index 42b86525..60d5410b 100644 --- a/test/point.test.js +++ b/test/point.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/polygon.test.js b/test/polygon.test.ts similarity index 99% rename from test/polygon.test.js rename to test/polygon.test.ts index 64d004a5..2c800769 100644 --- a/test/polygon.test.js +++ b/test/polygon.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/simple_select.test.js b/test/simple_select.test.ts similarity index 99% rename from test/simple_select.test.js rename to test/simple_select.test.ts index 8b757cff..87e5c214 100644 --- a/test/simple_select.test.js +++ b/test/simple_select.test.ts @@ -1,4 +1,5 @@ /* eslint no-shadow:[0] */ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import createSyntheticEvent from 'synthetic-dom-events'; diff --git a/test/sort_features.test.js b/test/sort_features.test.ts similarity index 98% rename from test/sort_features.test.js rename to test/sort_features.test.ts index c939ff6f..07f667d1 100644 --- a/test/sort_features.test.js +++ b/test/sort_features.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { sortFeatures } from '../src/lib/sort_features'; diff --git a/test/static.test.js b/test/static.test.ts similarity index 99% rename from test/static.test.js rename to test/static.test.ts index f9e8dc4e..3ffbf8fe 100644 --- a/test/static.test.js +++ b/test/static.test.ts @@ -1,4 +1,5 @@ /* eslint no-shadow:[0] */ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import StaticMode from '@mapbox/mapbox-gl-draw-static-mode'; diff --git a/test/store.test.js b/test/store.test.ts similarity index 99% rename from test/store.test.js rename to test/store.test.ts index cba8d3e5..6d273365 100644 --- a/test/store.test.js +++ b/test/store.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/string_set.test.js b/test/string_set.test.ts similarity index 99% rename from test/string_set.test.js rename to test/string_set.test.ts index 97342183..fd219435 100644 --- a/test/string_set.test.js +++ b/test/string_set.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import StringSet from '../src/lib/string_set'; diff --git a/test/ui.test.js b/test/ui.test.ts similarity index 99% rename from test/ui.test.js rename to test/ui.test.ts index a050a02f..2f4a42f5 100644 --- a/test/ui.test.js +++ b/test/ui.test.ts @@ -1,3 +1,4 @@ +import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/utils/after_next_render.js b/test/utils/after_next_render.ts similarity index 100% rename from test/utils/after_next_render.js rename to test/utils/after_next_render.ts diff --git a/test/utils/create_feature.js b/test/utils/create_feature.ts similarity index 100% rename from test/utils/create_feature.js rename to test/utils/create_feature.ts diff --git a/test/utils/create_map.js b/test/utils/create_map.ts similarity index 100% rename from test/utils/create_map.js rename to test/utils/create_map.ts diff --git a/test/utils/create_mock_draw_mode_context.js b/test/utils/create_mock_draw_mode_context.ts similarity index 100% rename from test/utils/create_mock_draw_mode_context.js rename to test/utils/create_mock_draw_mode_context.ts diff --git a/test/utils/create_mock_feature_context.js b/test/utils/create_mock_feature_context.ts similarity index 100% rename from test/utils/create_mock_feature_context.js rename to test/utils/create_mock_feature_context.ts diff --git a/test/utils/create_mock_lifecycle_context.js b/test/utils/create_mock_lifecycle_context.ts similarity index 100% rename from test/utils/create_mock_lifecycle_context.js rename to test/utils/create_mock_lifecycle_context.ts diff --git a/test/utils/create_mock_mode.js b/test/utils/create_mock_mode.ts similarity index 100% rename from test/utils/create_mock_mode.js rename to test/utils/create_mock_mode.ts diff --git a/test/utils/create_mock_mode_handler_context.js b/test/utils/create_mock_mode_handler_context.ts similarity index 100% rename from test/utils/create_mock_mode_handler_context.js rename to test/utils/create_mock_mode_handler_context.ts diff --git a/test/utils/draw_geometry.js b/test/utils/draw_geometry.ts similarity index 100% rename from test/utils/draw_geometry.js rename to test/utils/draw_geometry.ts diff --git a/test/utils/get_geojson.js b/test/utils/get_geojson.ts similarity index 100% rename from test/utils/get_geojson.js rename to test/utils/get_geojson.ts diff --git a/test/utils/get_public_member_keys.js b/test/utils/get_public_member_keys.ts similarity index 100% rename from test/utils/get_public_member_keys.js rename to test/utils/get_public_member_keys.ts diff --git a/test/utils/key_events.js b/test/utils/key_events.ts similarity index 100% rename from test/utils/key_events.js rename to test/utils/key_events.ts diff --git a/test/utils/make_mouse_event.js b/test/utils/make_mouse_event.ts similarity index 100% rename from test/utils/make_mouse_event.js rename to test/utils/make_mouse_event.ts diff --git a/test/utils/make_touch_event.js b/test/utils/make_touch_event.ts similarity index 100% rename from test/utils/make_touch_event.js rename to test/utils/make_touch_event.ts diff --git a/test/utils/mouse_click.js b/test/utils/mouse_click.ts similarity index 100% rename from test/utils/mouse_click.js rename to test/utils/mouse_click.ts diff --git a/test/utils/touch_tap.js b/test/utils/touch_tap.ts similarity index 100% rename from test/utils/touch_tap.js rename to test/utils/touch_tap.ts diff --git a/tsconfig.json b/tsconfig.json index 963f5e8c..3b4ac668 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,9 @@ "moduleResolution": "Node", "skipLibCheck": true, "esModuleInterop": true, - "noEmit": true + "allowJs": true, + "noEmit": true, + "types": ["node"] }, "include": [ "./src/**/*", From cebd5ab68ca83bdd4644ed0e6a2042ba641c677a Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 18:09:36 -0400 Subject: [PATCH 43/59] Simplify --- index.ts | 4 ++-- src/options.ts | 22 ++++------------------ 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/index.ts b/index.ts index 4740c73a..fc06aa7e 100644 --- a/index.ts +++ b/index.ts @@ -1,5 +1,5 @@ import runSetup from './src/setup'; -import setupOptions from './src/options'; +import { configureOptions } from './src/options'; import setupAPI from './src/api'; import * as modes from './src/modes/index'; import * as Constants from './src/constants'; @@ -7,7 +7,7 @@ import * as lib from './src/lib/index'; import type { DrawOptions, Draw } from './src/types/types'; const setupDraw = (options: DrawOptions, api: Draw) => { - options = setupOptions(options); + options = configureOptions(options); const ctx = { options diff --git a/src/options.ts b/src/options.ts index 4bba0e61..0454079f 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,6 +1,7 @@ import * as Constants from './constants'; import * as modes from './modes/index'; import styles from './lib/theme'; +import { DrawOptions } from './types/types'; type Controls = { point: boolean; @@ -12,22 +13,7 @@ type Controls = { [key: string]: boolean; }; -type Options = { - defaultMode?: string; - keybindings?: boolean; - touchEnabled?: boolean; - clickBuffer?: number; - touchBuffer?: number; - boxSelect?: boolean; - displayControlsDefault?: boolean; - styles?: any[]; - modes?: typeof modes; - controls?: Partial; - userProperties?: boolean; - suppressAPIEvents?: boolean; -}; - -const defaultOptions: Options = { +const defaultOptions = { defaultMode: Constants.modes.SIMPLE_SELECT, keybindings: true, touchEnabled: true, @@ -71,7 +57,7 @@ function addSources(styles: any[], sourceBucket: 'hot' | 'cold'): any[] { }); } -export default function configureOptions(options: Options = {}): Options { +export const configureOptions = (options: DrawOptions = {}): DrawOptions => { let withDefaults = { ...options }; if (!options.controls) { @@ -82,7 +68,7 @@ export default function configureOptions(options: Options = {}): Options { ? { ...hideControls, ...options.controls } : { ...showControls, ...options.controls }; - withDefaults = { ...defaultOptions, ...withDefaults }; + withDefaults = { ...defaultOptions, ...withDefaults } as DrawOptions; withDefaults.styles = addSources(withDefaults.styles || [], 'cold').concat( addSources(withDefaults.styles || [], 'hot') From 11fc1c4e3315ab3a1b6f859da6115179859ebfa3 Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 22:46:32 -0400 Subject: [PATCH 44/59] Some type coersion for tests --- index.ts | 2 +- src/lib/common_selectors.ts | 53 ++++++++++------------ src/store.ts | 4 +- src/types/types.ts | 2 + test/common_selectors.test.ts | 80 ++++++++++++++++----------------- test/sort_features.test.ts | 3 +- test/store.test.ts | 7 +-- test/string_set.test.ts | 2 - test/utils/after_next_render.ts | 6 ++- test/utils/create_map.ts | 76 ++++++++++++++++++++----------- test/utils/draw_geometry.ts | 6 +-- test/utils/key_events.ts | 7 +-- 12 files changed, 133 insertions(+), 115 deletions(-) diff --git a/index.ts b/index.ts index fc06aa7e..5c5bfec0 100644 --- a/index.ts +++ b/index.ts @@ -26,7 +26,7 @@ const setupDraw = (options: DrawOptions, api: Draw) => { return api; }; -function MapboxDraw(options: DrawOptions) { +function MapboxDraw(options?: DrawOptions) { setupDraw(options, this); } diff --git a/src/lib/common_selectors.ts b/src/lib/common_selectors.ts index d0d790ad..2135dd5d 100644 --- a/src/lib/common_selectors.ts +++ b/src/lib/common_selectors.ts @@ -3,30 +3,31 @@ import { MapMouseEvent, MapTouchEvent } from '../types/types'; type E = MapMouseEvent | MapTouchEvent; -export function isOfMetaType(type: string) { return function (e: E) { - const featureTarget = e.featureTarget; - if (!featureTarget) return false; - if (!featureTarget.properties) return false; - return featureTarget.properties.meta === type; +export const isOfMetaType = (type: string) => { + return (e: E) => { + const featureTarget = e.featureTarget; + if (!featureTarget) return false; + if (!featureTarget.properties) return false; + return featureTarget.properties.meta === type; + }; }; -} -export function isShiftMousedown(e: MapMouseEvent) { +export const isShiftMousedown = (e: MapMouseEvent) => { if (!e.originalEvent) return false; if (!e.originalEvent.shiftKey) return false; return e.originalEvent.button === 0; -} +}; -export function isActiveFeature(e: E) { +export const isActiveFeature = (e: E) => { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; return ( e.featureTarget.properties.active === Constants.activeStates.ACTIVE && e.featureTarget.properties.meta === Constants.meta.FEATURE ); -} +}; -export function isInactiveFeature(e: E) { +export const isInactiveFeature = (e: E) => { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; return ( @@ -35,36 +36,28 @@ export function isInactiveFeature(e: E) { ); } -export function noTarget(e: E) { +export const noTarget = (e: E) => { return e.featureTarget === undefined; -} +}; -export function isFeature(e: E) { +export const isFeature = (e: E) => { if (!e.featureTarget) return false; if (!e.featureTarget.properties) return false; return e.featureTarget.properties.meta === Constants.meta.FEATURE; -} +}; -export function isVertex(e: E) { +export const isVertex = (e: E) => { const featureTarget = e.featureTarget; if (!featureTarget) return false; if (!featureTarget.properties) return false; return featureTarget.properties.meta === Constants.meta.VERTEX; -} +}; -export function isShiftDown(e: MapMouseEvent) { +export const isShiftDown = (e: MapMouseEvent) => { if (!e.originalEvent) return false; return e.originalEvent.shiftKey === true; -} - -export function isEscapeKey(e: KeyboardEvent) { - return e.key === 'Escape'; -} - -export function isEnterKey(e: KeyboardEvent) { - return e.key === 'Enter'; -} +}; -export function isTrue() { - return true; -} +export const isEscapeKey = (e: KeyboardEvent) => e.key === 'Escape'; +export const isEnterKey = (e: KeyboardEvent) => e.key === 'Enter'; +export const isTrue = () => true; diff --git a/src/store.ts b/src/store.ts index c3615bf7..686f8378 100644 --- a/src/store.ts +++ b/src/store.ts @@ -12,11 +12,11 @@ export default class Store { private _changedFeatureIds = new StringSet(); private _emitSelectionChange = false; private _mapInitialConfig: Record = {}; - private ctx: CTX; - private renderRequest: number | null = null; sources = { hot: [], cold: [] }; isDirty = false; + ctx: CTX; + renderRequest: number | null = null; constructor(ctx: CTX) { this.ctx = ctx; diff --git a/src/types/types.ts b/src/types/types.ts index decd1485..a2b56c0d 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -704,6 +704,8 @@ export declare class Draw implements IControl { static constants: Constants; static lib: Lib; modes: typeof modes; + types: typeof types; + options: DrawOptions; getDefaultPosition: () => ControlPosition; constructor(options?: DrawOptions); add(geojson: Feature | StrictFeatureCollection | Geometry): string[]; diff --git a/test/common_selectors.test.ts b/test/common_selectors.test.ts index c6d2389b..bdfc35df 100644 --- a/test/common_selectors.test.ts +++ b/test/common_selectors.test.ts @@ -3,6 +3,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import * as commonSelectors from '../src/lib/common_selectors'; +import type { MapMouseEvent } from '../src/types/types'; test('commonSelectors.isOfMetaType', () => { const isFoo = commonSelectors.isOfMetaType('foo'); @@ -14,9 +15,9 @@ test('commonSelectors.isOfMetaType', () => { meta: 'foo' } } - }) + } as unknown as MapMouseEvent), ); - assert.equal(isFoo({}), false); + assert.equal(isFoo({} as unknown as MapMouseEvent), false); assert.equal( isFoo({ featureTarget: { @@ -24,7 +25,7 @@ test('commonSelectors.isOfMetaType', () => { meta: 'bar' } } - }), + } as unknown as MapMouseEvent), false ); }); @@ -36,7 +37,7 @@ test('commonSelectors.isShiftMousedown', () => { shiftKey: true, button: 0 } - }) + } as unknown as MapMouseEvent) ); assert.equal( @@ -45,7 +46,7 @@ test('commonSelectors.isShiftMousedown', () => { shiftKey: false, button: 0 } - }), + } as unknown as MapMouseEvent), false ); @@ -55,14 +56,14 @@ test('commonSelectors.isShiftMousedown', () => { shiftKey: true, button: 1 } - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isShiftMousedown({ nothing: false - }), + } as unknown as MapMouseEvent), false ); }); @@ -76,7 +77,7 @@ test('commonSelectors.isActiveFeature', () => { meta: 'feature' } } - }) + } as unknown as MapMouseEvent) ); assert.equal( @@ -94,7 +95,7 @@ test('commonSelectors.isActiveFeature', () => { meta: 'feature' } } - }), + } as unknown as MapMouseEvent), false ); @@ -106,7 +107,7 @@ test('commonSelectors.isActiveFeature', () => { meta: 'something' } } - }), + } as unknown as MapMouseEvent), false ); @@ -118,21 +119,21 @@ test('commonSelectors.isActiveFeature', () => { meta: 'Feature' } } - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isActiveFeature({ nothing: false - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isActiveFeature({ featureTarget: {} - }), + } as unknown as MapMouseEvent), false ); }); @@ -146,13 +147,13 @@ test('commonSelectors.isInactiveFeature', () => { meta: 'feature' } } - }) + } as unknown as MapMouseEvent) ); assert.equal( commonSelectors.isInactiveFeature({ foo: 'bar' - }), + } as unknown as MapMouseEvent), false ); @@ -164,7 +165,7 @@ test('commonSelectors.isInactiveFeature', () => { meta: 'feature' } } - }), + } as unknown as MapMouseEvent), false ); @@ -176,7 +177,7 @@ test('commonSelectors.isInactiveFeature', () => { meta: 'something' } } - }), + } as unknown as MapMouseEvent), false ); @@ -188,21 +189,21 @@ test('commonSelectors.isInactiveFeature', () => { meta: 'Feature' } } - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isInactiveFeature({ nothing: false - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isInactiveFeature({ featureTarget: {} - }), + } as unknown as MapMouseEvent), false ); }); @@ -211,26 +212,26 @@ test('commonSelectors.noTarget', () => { assert.ok( commonSelectors.noTarget({ something: 1 - }) + } as unknown as MapMouseEvent) ); assert.ok( commonSelectors.noTarget({ FeatureTarget: 1 - }) + } as unknown as MapMouseEvent) ); assert.equal( commonSelectors.noTarget({ featureTarget: {} - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.noTarget({ featureTarget: null - }), + } as unknown as MapMouseEvent), false ); }); @@ -243,13 +244,13 @@ test('commonSelectors.isFeature', () => { meta: 'feature' } } - }) + } as unknown as MapMouseEvent) ); assert.equal( commonSelectors.isFeature({ feee: 2 - }), + } as unknown as MapMouseEvent), false ); @@ -260,21 +261,21 @@ test('commonSelectors.isFeature', () => { meta: 'nonfeature' } } - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isFeature({ nothing: false - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isFeature({ featureTarget: {} - }), + } as unknown as MapMouseEvent), false ); }); @@ -285,7 +286,7 @@ test('commonSelectors.isShiftDown', () => { originalEvent: { shiftKey: true } - }) + } as unknown as MapMouseEvent) ); assert.equal( @@ -293,21 +294,21 @@ test('commonSelectors.isShiftDown', () => { originalEvent: { shiftKey: false } - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isShiftDown({ originalEvent: {} - }), + } as unknown as MapMouseEvent), false ); assert.equal( commonSelectors.isShiftDown({ nothing: true - }), + } as unknown as MapMouseEvent), false ); }); @@ -316,20 +317,20 @@ test('commonSelectors.isEscapeKey', () => { assert.ok( commonSelectors.isEscapeKey({ keyCode: 27 - }) + } as unknown as KeyboardEvent) ); assert.equal( commonSelectors.isEscapeKey({ keyCode: 13 - }), + } as unknown as KeyboardEvent), false ); assert.equal( commonSelectors.isEscapeKey({ originalEvent: {} - }), + } as unknown as KeyboardEvent), false ); }); @@ -338,25 +339,24 @@ test('commonSelectors.isEnterKey', () => { assert.ok( commonSelectors.isEnterKey({ keyCode: 13 - }) + } as unknown as KeyboardEvent) ); assert.equal( commonSelectors.isEnterKey({ keyCode: 27 - }), + } as unknown as KeyboardEvent), false ); assert.equal( commonSelectors.isEnterKey({ originalEvent: {} - }), + } as unknown as KeyboardEvent), false ); }); test('commonSelectors.true', () => { assert.ok(commonSelectors.isTrue()); - assert.ok(commonSelectors.isTrue(false)); }); diff --git a/test/sort_features.test.ts b/test/sort_features.test.ts index 07f667d1..00a8c321 100644 --- a/test/sort_features.test.ts +++ b/test/sort_features.test.ts @@ -2,6 +2,7 @@ import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { sortFeatures } from '../src/lib/sort_features'; +import {StrictFeature} from '../src/types/types'; test('sortFeatures', () => { const features = [ @@ -57,7 +58,7 @@ test('sortFeatures', () => { } ]; - assert.deepEqual(sortFeatures(features), [ + assert.deepEqual(sortFeatures(features as unknown as StrictFeature[]), [ { geometry: { type: 'Point' }, properties: { id: 3 } diff --git a/test/store.test.ts b/test/store.test.ts index 6d273365..b6433316 100644 --- a/test/store.test.ts +++ b/test/store.test.ts @@ -7,6 +7,7 @@ import Store from '../src/store'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; import createMap from './utils/create_map'; +import type { CTX } from '../src/types/types'; function createStore() { const ctx = { @@ -17,7 +18,7 @@ function createStore() { events: { fire: spy() } - }; + } as unknown as CTX; return new Store(ctx); } @@ -29,7 +30,7 @@ test('Store has correct properties', () => { test('Store constructor and public API', () => { const map = createMap(); - const ctx = { map }; + const ctx = { map } as unknown as CTX; const store = new Store(ctx); // instance members @@ -225,7 +226,7 @@ test('Store#featureChanged, Store#getChangedIds, Store#clearChangedIds', () => { test('Store#add, Store#get, Store#getAll', () => { const store = createStore(); - assert.equal(store.get(1), undefined); + assert.equal(store.get(1 as unknown as string), undefined); assert.deepEqual(store.getAll(), []); const point = createFeature('point'); const line = createFeature('line'); diff --git a/test/string_set.test.ts b/test/string_set.test.ts index fd219435..5979822f 100644 --- a/test/string_set.test.ts +++ b/test/string_set.test.ts @@ -63,8 +63,6 @@ test('StringSet#delete', () => { assert.deepEqual(set.values(), ['b', 2]); set.delete('a'); assert.deepEqual(set.values(), ['b', 2]); - set.delete(); - assert.deepEqual(set.values(), ['b', 2]); set.delete('b'); assert.deepEqual(set.values(), [2]); set.delete(2); diff --git a/test/utils/after_next_render.ts b/test/utils/after_next_render.ts index 165f2ab3..a0b625d8 100644 --- a/test/utils/after_next_render.ts +++ b/test/utils/after_next_render.ts @@ -1,6 +1,8 @@ +import type { Map } from "mapbox-gl"; + const TIMEOUT = 1000; -export function setupAfterNextRender(map) { +export const setupAfterNextRender = (map: Map) => { let render = 0; map.on('draw.render', () => { render++; @@ -21,7 +23,7 @@ export function setupAfterNextRender(map) { if (lastRender < render) { clearInterval(id); - resolve(); + resolve(true); } }); }); diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index 1c6f9c8e..6ab0051f 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -1,20 +1,39 @@ import { bboxClip } from '@turf/bbox-clip'; - import Evented from '../../bench/lib/evented'; import { interactions } from '../../src/constants'; +import type { StrictFeature } from '../../src/types/types'; + +type Source = { + data: { features: StrictFeature[] }; + setData?: (data: { features: StrictFeature[] }) => void; +}; + +type Layer = Record; + +type MapOptions = { + container?: HTMLElement; +} & Record; class MockMap extends Evented { - constructor(options = {}) { + sources: Record = {}; + style: { + _layers: Layer; + getLayer: (id: string) => Source | undefined; + addSource: (id: string, source: Source) => void; + removeSource: (id: string) => void; + }; + options: MapOptions; + + constructor(options: MapOptions = {}) { super(); - this.sources = {}; this.style = { _layers: {}, - getLayer: id => this.style._layers[id], - addSource: (id, source) => { + getLayer: (id: string) => this.style._layers[id], + addSource: (id: string, source: Source) => { this.style._layers[id] = source; }, - removeSource: id => { + removeSource: (id: string) => { delete this.style._layers[id]; } }; @@ -43,66 +62,70 @@ class MockMap extends Evented { }, 0); } - addControl(control) { + addControl(control: { onAdd: (map: MockMap) => void }) { control.onAdd(this); } - loaded() { + loaded(): boolean { return true; } - getLayer(id) { + getLayer(id: string): Source | undefined { return this.style.getLayer(id); } - getContainer() { + getContainer(): HTMLElement { return this.options.container; } - addSource(name, source) { + addSource(name: string, source: Source): void { this.style.addSource(name, source); this.sources[name] = source; } - removeSource(name) { + + removeSource(name: string): void { delete this.sources[name]; } - getSource(name) { + + getSource(name: string): Source | undefined { const source = this.sources[name]; - return { - ...source, - setData(data) { - source.data = data; - } - }; + return source + ? { + ...source, + setData(data: { features: StrictFeature[] }) { + source.data = data; + } + } + : undefined; } addLayer() {} - queryRenderedFeatures([p0, p1]) { + queryRenderedStrictFeatures([p0, p1]: [{ x: number; y: number } | Coordinates, { x: number; y: number } | Coordinates]): StrictFeature[] { if (!Array.isArray(p0)) p0 = [p0.x, p0.y]; if (!Array.isArray(p1)) p1 = [p1.x, p1.y]; const minX = Math.min(p0[0], p1[0]); const minY = Math.min(p0[1], p1[1]); const maxX = Math.max(p0[0], p1[0]); const maxY = Math.max(p0[1], p1[1]); - const bbox = [minX, minY, maxX, maxY]; - const features = []; + const bbox: [number, number, number, number] = [minX, minY, maxX, maxY]; + const features: StrictFeature[] = []; for (const source of Object.values(this.sources)) { for (const feature of source.data.features) { if (feature.geometry.type === 'Point') { - const [x, y] = feature.geometry.coordinates; + const [x, y] = feature.geometry.coordinates as Coordinates; if (x >= minX && x <= maxX && y >= minY && y <= maxY) features.push(feature); } else if (feature.geometry.type === 'MultiPoint') { - for (const [x, y] of feature.geometry.coordinates) { + for (const [x, y] of feature.geometry.coordinates as Coordinates[]) { if (x >= minX && x <= maxX && y >= minY && y <= maxY) { features.push(feature); break; } } } else { - const clipped = bboxClip(feature, bbox); + const clipped = bboxClip(feature as unknown as StrictFeature, bbox); if (clipped.geometry.coordinates.length) features.push(feature); } } @@ -111,6 +134,7 @@ class MockMap extends Evented { } } -export default function createMap(mapOptions) { +export default function createMap(mapOptions?: MapOptions): MockMap { return new MockMap(mapOptions); } + diff --git a/test/utils/draw_geometry.ts b/test/utils/draw_geometry.ts index 7622e8b0..721146fa 100644 --- a/test/utils/draw_geometry.ts +++ b/test/utils/draw_geometry.ts @@ -2,10 +2,6 @@ import click from './mouse_click'; import { setupAfterNextRender } from './after_next_render'; import makeMouseEvent from './make_mouse_event'; -/** - * Draws a feature on a map. - */ - const mapFeaturesToModes = { Polygon: 'draw_polygon', Point: 'draw_point', @@ -23,6 +19,6 @@ export async function drawGeometry(map, draw, type, coordinates) { for (const point of drawCoordinates) { click(map, makeMouseEvent(point[0], point[1], false)); - await afterNextRender(); + await afterNextRender(map); } } diff --git a/test/utils/key_events.ts b/test/utils/key_events.ts index df35df32..4273fde9 100644 --- a/test/utils/key_events.ts +++ b/test/utils/key_events.ts @@ -1,9 +1,10 @@ import createSyntheticEvent from 'synthetic-dom-events'; import * as Constants from '../../src/constants'; -const classList = [Constants.classes.CANVAS]; -classList.contains = function (cls) { - return classList.indexOf(cls) >= 0; +const classList = [Constants.classes.CANVAS] as any; + +classList.contains = function (cls: string) { + return this.includes(cls); }; export const enterEvent = createSyntheticEvent('keyup', { From b32aad71946245299aa1d4064f8121d81937ef9d Mon Sep 17 00:00:00 2001 From: tristen Date: Sun, 16 Mar 2025 23:30:09 -0400 Subject: [PATCH 45/59] More typings for tests --- test/common_selectors.test.ts | 2 +- test/constrain_feature_movement.test.ts | 2 +- test/euclidean_distance.test.ts | 2 +- test/is_event_at_coordinates.test.ts | 2 +- test/mouse_event_point.test.ts | 4 +- test/utils/create_map.ts | 54 +++++++++++++++++++------ 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/test/common_selectors.test.ts b/test/common_selectors.test.ts index bdfc35df..d50d69c6 100644 --- a/test/common_selectors.test.ts +++ b/test/common_selectors.test.ts @@ -83,7 +83,7 @@ test('commonSelectors.isActiveFeature', () => { assert.equal( commonSelectors.isActiveFeature({ foo: 'bar' - }), + } as unknown as MapMouseEvent), false ); diff --git a/test/constrain_feature_movement.test.ts b/test/constrain_feature_movement.test.ts index e83e83fc..bba99d48 100644 --- a/test/constrain_feature_movement.test.ts +++ b/test/constrain_feature_movement.test.ts @@ -2,7 +2,7 @@ import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import getGeoJSON from './utils/get_geojson'; -import constrainFeatureMovement from '../src/lib/constrain_feature_movement'; +import { constrainFeatureMovement } from '../src/lib/constrain_feature_movement'; test('constrainFeatureMovement point, no constraint', () => { const point = getGeoJSON('point'); diff --git a/test/euclidean_distance.test.ts b/test/euclidean_distance.test.ts index bcce0342..e4cde7ef 100644 --- a/test/euclidean_distance.test.ts +++ b/test/euclidean_distance.test.ts @@ -1,7 +1,7 @@ import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; -import euclideanDistance from '../src/lib/euclidean_distance'; +import { euclideanDistance } from '../src/lib/euclidean_distance'; test('euclideanDistance', () => { assert.equal( diff --git a/test/is_event_at_coordinates.test.ts b/test/is_event_at_coordinates.test.ts index 4fb6d1db..f4eece99 100644 --- a/test/is_event_at_coordinates.test.ts +++ b/test/is_event_at_coordinates.test.ts @@ -32,7 +32,7 @@ test('isEventAtCoordinates', () => { isEventAtCoordinates( { nothing: true - }, + } as unknown as { lngLat: { lng: number, lat: number } } , [3, 29] ), false diff --git a/test/mouse_event_point.test.ts b/test/mouse_event_point.test.ts index 639ddc7d..bade3ffa 100644 --- a/test/mouse_event_point.test.ts +++ b/test/mouse_event_point.test.ts @@ -14,12 +14,12 @@ test('mouseEventPoint', () => { top: 20 }; } - }; + } as HTMLElement; const mockEvent = { clientX: 15, clientY: 33 - }; + } as MouseEvent; const result = mouseEventPoint(mockEvent, mockContainer); assert.equal(result instanceof Point, true); diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index 6ab0051f..680736ae 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -14,6 +14,14 @@ type MapOptions = { container?: HTMLElement; } & Record; +// Define the structure of an interaction +type Interaction = { + enabled: boolean; + disable(): void; + enable(): void; + isEnabled(): boolean; +}; + class MockMap extends Evented { sources: Record = {}; style: { @@ -24,6 +32,15 @@ class MockMap extends Evented { }; options: MapOptions; + // Explicitly declare interactions for TypeScript + scrollZoom!: Interaction; + boxZoom!: Interaction; + dragRotate!: Interaction; + dragPan!: Interaction; + keyboard!: Interaction; + doubleClickZoom!: Interaction; + touchZoomRotate!: Interaction; + constructor(options: MapOptions = {}) { super(); @@ -42,19 +59,15 @@ class MockMap extends Evented { ...options }; + // Explicitly define each interaction + this.dragPan = this.createInteraction(); + this.doubleClickZoom = this.createInteraction(); + + // Dynamically add any other interactions for (const interaction of interactions) { - this[interaction] = { - enabled: true, - disable() { - this.enabled = false; - }, - enable() { - this.enabled = true; - }, - isEnabled() { - return this.enabled; - } - }; + if (!(interaction in this)) { + (this as any)[interaction] = this.createInteraction(); + } } setTimeout(() => { @@ -62,6 +75,22 @@ class MockMap extends Evented { }, 0); } + // Helper function to create interaction objects + private createInteraction(): Interaction { + return { + enabled: true, + disable() { + this.enabled = false; + }, + enable() { + this.enabled = true; + }, + isEnabled() { + return this.enabled; + } + }; + } + addControl(control: { onAdd: (map: MockMap) => void }) { control.onAdd(this); } @@ -137,4 +166,3 @@ class MockMap extends Evented { export default function createMap(mapOptions?: MapOptions): MockMap { return new MockMap(mapOptions); } - From 9b0ca098c2c5c925b2449da9c854eecfb4ffa201 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 00:08:31 -0400 Subject: [PATCH 46/59] More types more coercing for mocks --- src/types/types.ts | 6 ++-- test/create_supplementary_points.test.ts | 35 ++++++++++++++--------- test/map_event_to_bounding_box.test.ts | 7 +++-- test/options.test.ts | 4 +-- test/utils/create_map.ts | 14 ++++----- test/utils/create_mock_feature_context.ts | 7 +++-- 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index a2b56c0d..73512983 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -62,8 +62,8 @@ export type Coords = Array<[number, number]>; export type DrawCoords = Array<{ coord_path: string; feature_id: string }> export interface Entry { - point: XY; - time: number; + point?: XY; + time?: number; } interface Modes { @@ -630,7 +630,7 @@ export interface DrawStoreOptions { action?: string; } -interface DrawStore { +export interface DrawStore { ctx: CTX; isDirty: boolean; setDirty(): this; diff --git a/test/create_supplementary_points.test.ts b/test/create_supplementary_points.test.ts index 42877f00..39648cda 100644 --- a/test/create_supplementary_points.test.ts +++ b/test/create_supplementary_points.test.ts @@ -3,6 +3,8 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import createMap from './utils/create_map'; import { createSupplementaryPoints } from '../src/lib/create_supplementary_points'; +import type { StrictFeature } from '../src/types/types'; +import {Map} from 'mapbox-gl'; test('createSupplementaryPoints with a point', () => { const point = { @@ -14,7 +16,7 @@ test('createSupplementaryPoints with a point', () => { type: 'Point', coordinates: [10, 15] } - }; + } as unknown as StrictFeature; const result = createSupplementaryPoints(point); @@ -49,7 +51,7 @@ test('createSupplementaryPoints with a line, no midpoints', () => { [8, 8] ] } - }; + } as unknown as StrictFeature; const result = createSupplementaryPoints(line); @@ -118,7 +120,8 @@ test('createSupplementaryPoints with a polygon, no midpoints', () => { ] ] } - }; + } as unknown as StrictFeature; + const result = createSupplementaryPoints(polygon); assert.deepEqual( @@ -195,8 +198,9 @@ test('createSupplementaryPoints with line, midpoints, selected coordinate', () = [8, 8] ] } - }; - const map = createMap(); + } as unknown as StrictFeature; + + const map = createMap() as unknown as Map; const results = createSupplementaryPoints(line, { map, @@ -297,9 +301,9 @@ test('createSupplementaryPoints with polygon, midpoints, selection', () => { ] ] } - }; + } as unknown as StrictFeature; - const map = createMap(); + const map = createMap() as unknown as Map; const results = createSupplementaryPoints(polygon, { map, @@ -444,8 +448,9 @@ test('createSupplementaryPoints with MultiLineString, midpoints, selected coordi ] ] } - }; - const map = createMap(); + } as unknown as StrictFeature; + + const map = createMap() as unknown as Map; const results = createSupplementaryPoints(line, { map, @@ -605,10 +610,12 @@ test('createSupplementaryPoints with a line, not all midpoints rendered because [7, 87] ] } - }; + } as unknown as StrictFeature; + + const map = createMap() as unknown as Map; const result = createSupplementaryPoints(line, { - map: createMap(), + map, midpoints: true }); @@ -687,10 +694,12 @@ test('createSupplementaryPoints with a line, not all midpoints rendered because [7, -87] ] } - }; + } as unknown as StrictFeature; + + const map = createMap() as unknown as Map; const result = createSupplementaryPoints(line, { - map: createMap(), + map, midpoints: true }); diff --git a/test/map_event_to_bounding_box.test.ts b/test/map_event_to_bounding_box.test.ts index 91ce232b..828d2455 100644 --- a/test/map_event_to_bounding_box.test.ts +++ b/test/map_event_to_bounding_box.test.ts @@ -2,6 +2,7 @@ import './mock-browser'; import test from 'node:test'; import assert from 'node:assert/strict'; import { mapEventToBoundingBox } from '../src/lib/map_event_to_bounding_box'; +import type { MapMouseEvent } from '../src/types/types'; test('mapEventToBoundingBox', () => { assert.deepEqual( @@ -10,7 +11,7 @@ test('mapEventToBoundingBox', () => { x: 1, y: 2 } - }), + } as unknown as MapMouseEvent), [ [1, 2], [1, 2] @@ -24,7 +25,7 @@ test('mapEventToBoundingBox', () => { x: 1, y: 2 } - }, + } as unknown as MapMouseEvent, 1 ), [ @@ -40,7 +41,7 @@ test('mapEventToBoundingBox', () => { x: 10.3, y: 95674.234 } - }, + } as unknown as MapMouseEvent, 50.5 ), [ diff --git a/test/options.test.ts b/test/options.test.ts index c94e8e80..27d80e01 100644 --- a/test/options.test.ts +++ b/test/options.test.ts @@ -7,11 +7,11 @@ import assert from 'node:assert/strict'; import { fileURLToPath } from 'url'; import MapboxDraw from '../index'; -import { modes } from '../src/modes/index'; +import * as modes from '../src/modes/index'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const styleWithSourcesFixture = JSON.parse( - fs.readFileSync(path.join(__dirname, './fixtures/style_with_sources.json')) + fs.readFileSync(path.join(__dirname, './fixtures/style_with_sources.json'), 'utf8') ); test('Options test', async t => { diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index 680736ae..3eff957a 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -33,13 +33,13 @@ class MockMap extends Evented { options: MapOptions; // Explicitly declare interactions for TypeScript - scrollZoom!: Interaction; - boxZoom!: Interaction; - dragRotate!: Interaction; - dragPan!: Interaction; - keyboard!: Interaction; - doubleClickZoom!: Interaction; - touchZoomRotate!: Interaction; + scrollZoom: Interaction; + boxZoom: Interaction; + dragRotate: Interaction; + dragPan: Interaction; + keyboard: Interaction; + doubleClickZoom: Interaction; + touchZoomRotate: Interaction; constructor(options: MapOptions = {}) { super(); diff --git a/test/utils/create_mock_feature_context.ts b/test/utils/create_mock_feature_context.ts index 0fab06b7..d2421586 100644 --- a/test/utils/create_mock_feature_context.ts +++ b/test/utils/create_mock_feature_context.ts @@ -1,4 +1,5 @@ import { spy } from 'sinon'; +import type { CTX, DrawStore } from '../../src/types/types'; /** * Returns an mock ctx object with just those properties a Feature @@ -8,13 +9,13 @@ import { spy } from 'sinon'; */ export default function createMockFeatureContext( opts = { userProperties: false } -) { +): CTX { return { options: { userProperties: opts.userProperties }, store: { featureChanged: spy() - } - }; + } as unknown as DrawStore + } as unknown as CTX; } From a1e18d9cda69d67b7b774d562e0e73965d1f87b8 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 11:38:53 -0400 Subject: [PATCH 47/59] More typings for tests --- src/feature_types/line_string.ts | 16 ++++++++-------- src/feature_types/polygon.ts | 4 ++-- src/types/types.ts | 2 +- test/feature.test.ts | 4 +++- test/utils/after_next_render.ts | 6 ++---- test/utils/create_map.ts | 3 ++- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index 420cf85d..3a3eab54 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -12,26 +12,26 @@ class LineString extends Feature { return this.coordinates.length > 1; } - addCoordinate(path: string, lng: number, lat: number): void { + addCoordinate(path: string | number, lng: number, lat: number): void { this.changed(); - const id = parseInt(path, 10); + const id = parseInt(path as string, 10); this.coordinates.splice(id, 0, [lng, lat]); } - getCoordinate(path: string): Coordinate | undefined { - const id = parseInt(path, 10); + getCoordinate(path: string | number): Coordinate | undefined { + const id = parseInt(path as string, 10); return this.coordinates[id] ? [...(this.coordinates[id] as Coordinate)] : undefined; } - removeCoordinate(path: string): void { + removeCoordinate(path: string | number): void { this.changed(); - this.coordinates.splice(parseInt(path, 10), 1); + this.coordinates.splice(parseInt(path as string, 10), 1); } - updateCoordinate(path: string, lng: number, lat: number): void { - const id = parseInt(path, 10); + updateCoordinate(path: string | number, lng: number, lat: number): void { + const id = parseInt(path as string, 10); this.coordinates[id] = [lng, lat]; this.changed(); } diff --git a/src/feature_types/polygon.ts b/src/feature_types/polygon.ts index 1f9e35af..be65c9c8 100644 --- a/src/feature_types/polygon.ts +++ b/src/feature_types/polygon.ts @@ -17,13 +17,13 @@ class Polygon extends Feature { } // Expects valid geoJSON polygon geometry: first and last positions must be equivalent. - incomingCoords(coords: Coords): void { + incomingCoords(coords): void { this.coordinates = coords.map(ring => ring.slice(0, -1)); this.changed(); } // Does NOT expect valid geoJSON polygon geometry: first and last positions should not be equivalent. - setCoordinates(coords: Coords): void { + setCoordinates(coords: Coords[]): void { this.coordinates = coords; this.changed(); } diff --git a/src/types/types.ts b/src/types/types.ts index 73512983..bdef4200 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -100,7 +100,7 @@ interface DrawFeatureBase { changed(): void; isValid(): boolean; - incomingCoords(coords: number[][]): void; + incomingCoords(coords: Coords[]): void; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; getCoordinate(path: number): Position; diff --git a/test/feature.test.ts b/test/feature.test.ts index 934e43f7..7f81a411 100644 --- a/test/feature.test.ts +++ b/test/feature.test.ts @@ -7,6 +7,7 @@ import Feature from '../src/feature_types/feature'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; import createMockCtx from './utils/create_mock_feature_context'; +import type { StrictFeature } from '../src/types/types'; test('Feature contrusctor and API', () => { const featureGeoJson = createFeature('line'); @@ -77,7 +78,8 @@ test('Feature contrusctor and API', () => { type: 'Point', coordinates: [0, 0] } - }; + } as StrictFeature; + const featureWithDefaultsOnly = new Feature(ctx, simpleFeatureGeoJson); assert.deepEqual( featureWithDefaultsOnly.properties, diff --git a/test/utils/after_next_render.ts b/test/utils/after_next_render.ts index a0b625d8..7d12b2c2 100644 --- a/test/utils/after_next_render.ts +++ b/test/utils/after_next_render.ts @@ -1,8 +1,6 @@ -import type { Map } from "mapbox-gl"; - const TIMEOUT = 1000; -export const setupAfterNextRender = (map: Map) => { +export const setupAfterNextRender = (map) => { let render = 0; map.on('draw.render', () => { render++; @@ -12,7 +10,7 @@ export const setupAfterNextRender = (map: Map) => { const signal = AbortSignal.timeout(TIMEOUT); signal.addEventListener('abort', () => controller.abort()); - return function afterNextRender(msg) { + return function afterNextRender(msg = '') { return new Promise((resolve, reject) => { const lastRender = render; const id = setInterval(() => { diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index 3eff957a..0d4e26ad 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -9,6 +9,7 @@ type Source = { }; type Layer = Record; +type Coordinates = [number, number]; type MapOptions = { container?: HTMLElement; @@ -154,7 +155,7 @@ class MockMap extends Evented { } } } else { - const clipped = bboxClip(feature as unknown as StrictFeature, bbox); + const clipped = bboxClip(feature, bbox); if (clipped.geometry.coordinates.length) features.push(feature); } } From 7f1f5c5ffdcbc65e7192f17430e4d3770569a94b Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 14:02:41 -0400 Subject: [PATCH 48/59] Do some spy mocking --- src/lib/is_tap.ts | 5 ++++- test/direct_select.test.ts | 2 +- test/draw_line_string.test.ts | 25 ++++++++++++----------- test/draw_polygon.test.ts | 5 +++-- test/feature.test.ts | 6 +++--- test/features_at.test.ts | 4 ++-- test/simple_select.test.ts | 3 ++- test/static.test.ts | 2 +- test/store.test.ts | 9 ++++---- test/ui.test.ts | 23 +++++++++++++-------- test/utils/create_mock_feature_context.ts | 7 +++---- 11 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/lib/is_tap.ts b/src/lib/is_tap.ts index 6f08a1fe..2abcfa8c 100644 --- a/src/lib/is_tap.ts +++ b/src/lib/is_tap.ts @@ -6,12 +6,15 @@ interface Options { interval?: number; } +export const TAP_TOLERANCE = 25; +export const TAP_INTERVAL = 250; + export const isTap = ( start: Entry, end: Entry, options: Options = {} ): boolean => { - const { tolerance = 25, interval = 250 } = options; + const { tolerance = TAP_TOLERANCE, interval = TAP_INTERVAL } = options; start.point = start.point || end.point; start.time = start.time || end.time; diff --git a/test/direct_select.test.ts b/test/direct_select.test.ts index ebf6a207..f83ebb04 100644 --- a/test/direct_select.test.ts +++ b/test/direct_select.test.ts @@ -19,7 +19,7 @@ import * as Constants from '../src/constants'; test('direct_select', async t => { const mapContainer = document.createElement('div'); document.body.appendChild(mapContainer); - const map = createMap({ container: mapContainer }); + const map = createMap({ container: mapContainer }) as spy; const Draw = new MapboxDraw(); map.addControl(Draw); diff --git a/test/draw_line_string.test.ts b/test/draw_line_string.test.ts index c9956371..53482333 100644 --- a/test/draw_line_string.test.ts +++ b/test/draw_line_string.test.ts @@ -1,4 +1,5 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; import MapboxDraw from '../index'; @@ -25,8 +26,8 @@ import { } from './utils/key_events'; test('draw_line_string mode initialization', () => { - const context = createMockDrawModeContext(); - const mode = drawLineStringMode(context); + const context = createMockDrawModeContext() as spy; + const mode = drawLineStringMode((context)); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -49,7 +50,7 @@ test('draw_line_string mode initialization', () => { }); test('draw_line_string start', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -86,7 +87,7 @@ test('draw_line_string start', () => { }); test('draw_line_string stop with valid line', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -95,7 +96,7 @@ test('draw_line_string stop with valid line', () => { const line = context.store.get(context.store.getAllIds()[0]); line.isValid = () => true; - mode.stop.call(); + (mode.stop as spy).call(); assert.equal( context.ui.setActiveButton.callCount, 2, @@ -110,7 +111,7 @@ test('draw_line_string stop with valid line', () => { }); test('draw_line_string stop with invalid line', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -119,7 +120,7 @@ test('draw_line_string stop with invalid line', () => { const line = context.store.get(context.store.getAllIds()[0]); line.isValid = () => false; - mode.stop.call(); + (mode.stop as spy).call(); assert.equal( context.ui.setActiveButton.callCount, 2, @@ -141,7 +142,7 @@ test('draw_line_string stop with invalid line', () => { }); test('draw_line_string render active line with 0 coordinates', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -164,7 +165,7 @@ test('draw_line_string render active line with 0 coordinates', () => { }); test('draw_line_string render active line with 1 coordinate', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -187,7 +188,7 @@ test('draw_line_string render active line with 1 coordinate', () => { }); test('draw_line_string render active line with 2 coordinates', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -232,7 +233,7 @@ test('draw_line_string render active line with 2 coordinates', () => { }); test('draw_line_string render inactive feature', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as unknown as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -729,7 +730,7 @@ test('draw_line_string touch interaction', async t => { }); test('draw_line_string continue LineString', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as unknown as spy; const mode = drawLineStringMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); diff --git a/test/draw_polygon.test.ts b/test/draw_polygon.test.ts index e29bfe18..0b07a87a 100644 --- a/test/draw_polygon.test.ts +++ b/test/draw_polygon.test.ts @@ -1,4 +1,5 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; import MapboxDraw from '../index'; @@ -24,7 +25,7 @@ import { } from './utils/key_events'; test('draw_polygon mode initialization', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -48,7 +49,7 @@ test('draw_polygon mode initialization', () => { }); test('draw_polygon start', async () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const lifecycleContext = createMockLifecycleContext(); const mode = drawPolygonMode(context); diff --git a/test/feature.test.ts b/test/feature.test.ts index 7f81a411..3115efd3 100644 --- a/test/feature.test.ts +++ b/test/feature.test.ts @@ -94,15 +94,15 @@ test('Feature#changed', () => { const featureGeoJson = createFeature('point'); const feature = new Feature(ctx, featureGeoJson); - ctx.store.featureChanged.resetHistory(); + (ctx.store.featureChanged as spy).resetHistory(); feature.changed(); assert.equal( - ctx.store.featureChanged.callCount, + (ctx.store.featureChanged as spy).callCount, 1, 'called function on store' ); assert.deepEqual( - ctx.store.featureChanged.getCall(0).args[0], + (ctx.store.featureChanged as spy).getCall(0).args[0], featureGeoJson.id, 'with correct args' ); diff --git a/test/features_at.test.ts b/test/features_at.test.ts index 113a7d6f..881923ad 100644 --- a/test/features_at.test.ts +++ b/test/features_at.test.ts @@ -4,7 +4,7 @@ import assert from 'node:assert/strict'; import * as featuresAt from '../src/lib/features_at'; import styles from '../src/lib/theme'; import * as Constants from '../src/constants'; -import setupOptions from '../src/options'; +import { configureOptions } from '../src/options'; /** * Mock of the addLayers function in setup @@ -166,7 +166,7 @@ function createMockContext() { } }; - context.options = setupOptions(context.options); + context.options = configureOptions(context.options); addLayers(context); diff --git a/test/simple_select.test.ts b/test/simple_select.test.ts index 87e5c214..58d76c9b 100644 --- a/test/simple_select.test.ts +++ b/test/simple_select.test.ts @@ -19,7 +19,7 @@ test('simple_select', async t => { const context = createMockDrawModeContext(); const mapContainer = document.createElement('div'); document.body.appendChild(mapContainer); - const map = createMap({ container: mapContainer }); + const map = createMap({ container: mapContainer }) as spy; const Draw = new MapboxDraw(); map.addControl(Draw); @@ -144,6 +144,7 @@ test('simple_select', async t => { type: 'FeatureCollection', features }); + map.fire.resetHistory(); await afterNextRender(); diff --git a/test/static.test.ts b/test/static.test.ts index 3ffbf8fe..7a06b5c4 100644 --- a/test/static.test.ts +++ b/test/static.test.ts @@ -12,7 +12,7 @@ import getGeoJSON from './utils/get_geojson'; import createMap from './utils/create_map'; test('static', async t => { - const map = createMap(); + const map = createMap() as spy; const opts = { modes: { static: StaticMode diff --git a/test/store.test.ts b/test/store.test.ts index b6433316..7c6d2f43 100644 --- a/test/store.test.ts +++ b/test/store.test.ts @@ -1,13 +1,12 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; -import { spy } from 'sinon'; import Store from '../src/store'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; import createMap from './utils/create_map'; -import type { CTX } from '../src/types/types'; function createStore() { const ctx = { @@ -18,7 +17,7 @@ function createStore() { events: { fire: spy() } - } as unknown as CTX; + } as spy; return new Store(ctx); } @@ -30,7 +29,7 @@ test('Store has correct properties', () => { test('Store constructor and public API', () => { const map = createMap(); - const ctx = { map } as unknown as CTX; + const ctx = { map } as spy; const store = new Store(ctx); // instance members @@ -395,7 +394,7 @@ test('Store#storeAndRestoreMapConfig', () => { 'Disables doubleClickZoom on the map' ); const ctx = { map }; - const store = new Store(ctx); + const store = new Store(ctx as spy); store.storeMapConfig(); // Check we can get the initial state of it assert.equal( diff --git a/test/ui.test.ts b/test/ui.test.ts index 2f4a42f5..6a10f431 100644 --- a/test/ui.test.ts +++ b/test/ui.test.ts @@ -1,11 +1,18 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; -import { spy } from 'sinon'; import ui from '../src/ui'; -function createMockContext({ position, controls } = {}) { +type Options = { + position?: string; + controls?: unknown; +}; + +function createMockContext(options: Options = {}) { + const { position, controls } = options; + const container = document.createElement('div'); document.body.appendChild(container); @@ -44,7 +51,7 @@ function getButtons(div) { test('ui container classes', async t => { const { context, cleanup } = createMockContext(); - const testUi = ui(context); + const testUi = ui(context as spy); assert.equal( context.container.className, @@ -159,7 +166,7 @@ test('ui container classes', async t => { test('ui buttons with no options.controls', () => { const { context, cleanup } = createMockContext(); - const testUi = ui(context); + const testUi = ui(context as spy); const div = testUi.addButtons(); assert.deepEqual(getButtons(div), [], 'still no buttons'); @@ -175,7 +182,7 @@ test('ui buttons with one options.controls', () => { } }); /* eslint-enable */ - const testUi = ui(context); + const testUi = ui(context as spy); const div = testUi.addButtons(); const buttons = getButtons(div); @@ -200,7 +207,7 @@ test('ui buttons control group container inserted above attribution control, in }); const controlContainer = getControlContainer(); - const testUi = ui(context); + const testUi = ui(context as spy); assert.equal( controlContainer.getElementsByClassName('mapboxgl-ctrl-group').length, @@ -225,7 +232,7 @@ test('ui buttons with all options.controls, no attribution control', async t => } }); /* eslint-enable */ - const testUi = ui(context); + const testUi = ui(context as spy); const controlGroup = testUi.addButtons(); const buttons = getButtons(controlGroup); @@ -381,7 +388,7 @@ test('ui buttons with all options.controls, no attribution control', async t => 'changeMode not called' ); - testUi.setActiveButton(); + testUi.setActiveButton(''); assert.equal( lineButton.classList.contains('active'), diff --git a/test/utils/create_mock_feature_context.ts b/test/utils/create_mock_feature_context.ts index d2421586..c756213b 100644 --- a/test/utils/create_mock_feature_context.ts +++ b/test/utils/create_mock_feature_context.ts @@ -1,5 +1,4 @@ import { spy } from 'sinon'; -import type { CTX, DrawStore } from '../../src/types/types'; /** * Returns an mock ctx object with just those properties a Feature @@ -9,13 +8,13 @@ import type { CTX, DrawStore } from '../../src/types/types'; */ export default function createMockFeatureContext( opts = { userProperties: false } -): CTX { +): spy { return { options: { userProperties: opts.userProperties }, store: { featureChanged: spy() - } as unknown as DrawStore - } as unknown as CTX; + } + } as spy; } From 195b056cc6bd14591520929a241351d3162fea28 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 14:16:06 -0400 Subject: [PATCH 49/59] More spy coersion --- test/draw_line_string.test.ts | 16 +++++++++------- test/draw_point.test.ts | 25 ++++++++++++++----------- test/draw_polygon.test.ts | 30 ++++++++++++++++-------------- 3 files changed, 39 insertions(+), 32 deletions(-) diff --git a/test/draw_line_string.test.ts b/test/draw_line_string.test.ts index 53482333..fea38b6d 100644 --- a/test/draw_line_string.test.ts +++ b/test/draw_line_string.test.ts @@ -25,6 +25,8 @@ import { escapeEvent } from './utils/key_events'; +import type { StrictFeature } from '../src/types/types'; + test('draw_line_string mode initialization', () => { const context = createMockDrawModeContext() as spy; const mode = drawLineStringMode((context)); @@ -160,7 +162,7 @@ test('draw_line_string render active line with 0 coordinates', () => { coordinates: [] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 0, 'does not render'); }); @@ -183,7 +185,7 @@ test('draw_line_string render active line with 1 coordinate', () => { coordinates: [[0, 0]] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 0, 'does not render'); }); @@ -209,7 +211,7 @@ test('draw_line_string render active line with 2 coordinates', () => { ] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 2, 'does render'); assert.deepEqual( memo[1], @@ -249,7 +251,7 @@ test('draw_line_string render inactive feature', () => { coordinates: [0, 0] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 1, 'does render'); assert.deepEqual( memo[0], @@ -749,15 +751,15 @@ test('draw_line_string continue LineString', () => { coordinates: coordinates.slice(0) } }; - const line = new LineString(context, geojson); + const line = new LineString(context, geojson as StrictFeature); context.store.add(line); assert.throws( - () => drawLineStringMode(context, { featureId: 2 }).start(lifecycleContext), + () => drawLineStringMode(context, { featureId: 2 }).start.call(lifecycleContext), /featureId/, 'wrong feature id' ); assert.throws( - () => drawLineStringMode(context, { featureId: 1 }).start(lifecycleContext), + () => drawLineStringMode(context, { featureId: 1 }).start.call(lifecycleContext), /from.*property/, 'no "from" prop' ); diff --git a/test/draw_point.test.ts b/test/draw_point.test.ts index 4a4894e6..4d9a232f 100644 --- a/test/draw_point.test.ts +++ b/test/draw_point.test.ts @@ -1,4 +1,5 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; import MapboxDraw from '../index'; @@ -13,10 +14,12 @@ import createMockDrawModeContext from './utils/create_mock_draw_mode_context'; import createMockLifecycleContext from './utils/create_mock_lifecycle_context'; import { escapeEvent, enterEvent } from './utils/key_events'; import { objectToMode } from '../src/modes/object_to_mode'; -const drawPointMode = objectToMode(drawPointModeObject); +import type { StrictFeature } from '../src/types/types'; + +const drawPointMode = objectToMode(drawPointModeObject as spy); test('draw_point mode initialization', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const lifecycleContext = createMockLifecycleContext(); const mode = drawPointMode(context); mode.start.call(lifecycleContext); @@ -40,7 +43,7 @@ test('draw_point mode initialization', () => { }); test('draw_point start', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const lifecycleContext = createMockLifecycleContext(); const mode = drawPointMode(context); mode.start.call(lifecycleContext); @@ -75,7 +78,7 @@ test('draw_point start', () => { }); test('draw_point stop with point placed', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPointMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -85,7 +88,7 @@ test('draw_point stop with point placed', () => { const point = context.store.get(id); point.updateCoordinate(10, 20); - mode.stop.call(); + (mode.stop as spy).call(); assert.equal( context.ui.setActiveButton.callCount, 2, @@ -100,7 +103,7 @@ test('draw_point stop with point placed', () => { }); test('draw_point stop with no point placed', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPointMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -108,7 +111,7 @@ test('draw_point stop with no point placed', () => { const id = context.store.getAllIds()[0]; const point = context.store.get(id); - mode.stop.call(); + (mode.stop as spy).call(); assert.equal( context.ui.setActiveButton.callCount, @@ -129,7 +132,7 @@ test('draw_point stop with no point placed', () => { }); test('draw_point render the active point', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPointMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -148,12 +151,12 @@ test('draw_point render the active point', () => { coordinates: [10, 10] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 0, 'active point does not render'); }); test('draw_point render an inactive feature', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPointMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -172,7 +175,7 @@ test('draw_point render an inactive feature', () => { ] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 1, 'does render'); assert.deepEqual( memo[0], diff --git a/test/draw_polygon.test.ts b/test/draw_polygon.test.ts index 0b07a87a..58406ce4 100644 --- a/test/draw_polygon.test.ts +++ b/test/draw_polygon.test.ts @@ -24,6 +24,8 @@ import { escapeEvent } from './utils/key_events'; +import type { StrictFeature } from '../src/types/types'; + test('draw_polygon mode initialization', () => { const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); @@ -85,7 +87,7 @@ test('draw_polygon start', async () => { }); test('draw_polygon stop with valid polygon', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -94,7 +96,7 @@ test('draw_polygon stop with valid polygon', () => { const testPolygon = context.store.get(context.store.getAllIds()[0]); testPolygon.isValid = () => true; - mode.stop.call(); + (mode.stop as spy).call(); assert.equal( context.ui.setActiveButton.callCount, 2, @@ -109,7 +111,7 @@ test('draw_polygon stop with valid polygon', () => { }); test('draw_polygon stop with invalid polygon', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -118,7 +120,7 @@ test('draw_polygon stop with invalid polygon', () => { const testPolygon = context.store.get(context.store.getAllIds()[0]); testPolygon.isValid = () => false; - mode.stop.call(); + (mode.stop as spy).call(); assert.equal( context.ui.setActiveButton.callCount, 2, @@ -138,7 +140,7 @@ test('draw_polygon stop with invalid polygon', () => { }); test('draw_polygon render active polygon with no coordinates', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -155,12 +157,12 @@ test('draw_polygon render active polygon with no coordinates', () => { coordinates: [] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 0, 'does not render'); }); test('draw_polygon render active polygon with 1 coordinate (and closer)', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -182,12 +184,12 @@ test('draw_polygon render active polygon with 1 coordinate (and closer)', () => ] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 0, 'does not render'); }); test('draw_polygon render active polygon with 2 coordinates (and closer)', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -210,7 +212,7 @@ test('draw_polygon render active polygon with 2 coordinates (and closer)', () => ] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 2, 'does render'); assert.deepEqual( memo[1], @@ -234,7 +236,7 @@ test('draw_polygon render active polygon with 2 coordinates (and closer)', () => }); test('draw_polygon render active polygon with 3 coordinates (and closer)', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -259,7 +261,7 @@ test('draw_polygon render active polygon with 3 coordinates (and closer)', () => ] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 3, 'does render'); assert.deepEqual( memo[0], @@ -322,7 +324,7 @@ test('draw_polygon render active polygon with 3 coordinates (and closer)', () => }); test('draw_polygon render inactive feature', () => { - const context = createMockDrawModeContext(); + const context = createMockDrawModeContext() as spy; const mode = drawPolygonMode(context); const lifecycleContext = createMockLifecycleContext(); mode.start.call(lifecycleContext); @@ -341,7 +343,7 @@ test('draw_polygon render inactive feature', () => { ] } }; - mode.render(geojson, x => memo.push(x)); + mode.render(geojson as StrictFeature, x => memo.push(x)); assert.equal(memo.length, 1, 'does render'); assert.deepEqual( memo[0], From ac8d989d46a76717b254753ef92e17a173302bdf Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 16:14:13 -0400 Subject: [PATCH 50/59] Finish up the pass on tsc errors in tests --- index.ts | 3 ++- src/feature_types/feature.ts | 14 +++++++------- src/lib/features_at.ts | 7 +++---- src/types/types.ts | 2 +- test/api.test.ts | 4 +++- test/feature.test.ts | 3 +-- test/features_at.test.ts | 15 +++++++-------- test/interaction_events.test.ts | 4 ---- test/line_string.test.ts | 32 ++++++++++++++++---------------- test/mock-browser.ts | 5 +++-- test/simple_select.test.ts | 4 ++-- test/utils/create_map.ts | 3 ++- tsconfig.json | 13 ++++++------- 13 files changed, 53 insertions(+), 56 deletions(-) diff --git a/index.ts b/index.ts index 5c5bfec0..fd5f2e22 100644 --- a/index.ts +++ b/index.ts @@ -1,3 +1,4 @@ +import { spy } from 'sinon'; import runSetup from './src/setup'; import { configureOptions } from './src/options'; import setupAPI from './src/api'; @@ -11,7 +12,7 @@ const setupDraw = (options: DrawOptions, api: Draw) => { const ctx = { options - }; + } as spy; api = setupAPI(ctx, api); ctx.api = api; diff --git a/src/feature_types/feature.ts b/src/feature_types/feature.ts index 8b91c4ca..b819d7ed 100644 --- a/src/feature_types/feature.ts +++ b/src/feature_types/feature.ts @@ -5,7 +5,7 @@ import type { StrictFeature, CTX } from '../types/types'; class Feature { ctx: CTX; - properties: Record; + properties: Record; coordinates: any; id: string; type: Geometry['type']; @@ -22,20 +22,20 @@ class Feature { this.ctx.store.featureChanged(this.id); } - incomingCoords(coords: number[][]): void { + incomingCoords(coords: number[][] | number[]): void { this.setCoordinates(coords); } - setCoordinates(coords: any): void { + setCoordinates(coords: unknown): void { this.coordinates = coords; this.changed(); } - getCoordinates(): any { + getCoordinates() { return JSON.parse(JSON.stringify(this.coordinates)); } - setProperty(property: string, value: any): void { + setProperty(property: string, value: unknown): void { this.properties[property] = value; } @@ -51,8 +51,8 @@ class Feature { }; } - internal(mode: string): any { - const properties: Record = { + internal(mode: string) { + const properties: Record = { id: this.id, meta: Constants.meta.FEATURE, 'meta:type': this.type, diff --git a/src/lib/features_at.ts b/src/lib/features_at.ts index 74af2ab0..cca2ce8c 100644 --- a/src/lib/features_at.ts +++ b/src/lib/features_at.ts @@ -3,7 +3,6 @@ import { mapEventToBoundingBox } from './map_event_to_bounding_box'; import * as Constants from '../constants'; import StringSet from './string_set'; -import type { BBox } from 'geojson'; import type { CTX, MapMouseEvent, MapTouchEvent } from '../types/types'; type E = MapMouseEvent | MapTouchEvent; @@ -14,7 +13,7 @@ const META_TYPES = [ Constants.meta.VERTEX ]; -const featuresAt = (event: E, bbox: BBox, ctx: CTX, buffer: number) => { +const featuresAt = (event: E, bbox, ctx: CTX, buffer: number) => { if (ctx.map === null) return []; const box = event ? mapEventToBoundingBox(event, buffer) : bbox; @@ -44,11 +43,11 @@ const featuresAt = (event: E, bbox: BBox, ctx: CTX, buffer: number) => { return sortFeatures(uniqueFeatures); }; -function featuresAtClick(event: E, bbox: BBox, ctx: CTX) { +function featuresAtClick(event: E, bbox, ctx: CTX) { return featuresAt(event, bbox, ctx, ctx.options.clickBuffer); } -function featuresAtTouch(event: E, bbox: BBox, ctx: CTX) { +function featuresAtTouch(event: E, bbox, ctx: CTX) { return featuresAt(event, bbox, ctx, ctx.options.touchBuffer); } diff --git a/src/types/types.ts b/src/types/types.ts index bdef4200..8331a8fe 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -100,7 +100,7 @@ interface DrawFeatureBase { changed(): void; isValid(): boolean; - incomingCoords(coords: Coords[]): void; + incomingCoords(coords: number[][] | number[]): void; setCoordinates(coords: Coordinates): void; getCoordinates(): Coordinates; getCoordinate(path: number): Position; diff --git a/test/api.test.ts b/test/api.test.ts index b4805803..bba7ab20 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -1,6 +1,8 @@ /* eslint no-shadow:[0] */ import './mock-browser'; -import { test, beforeEach, afterEach } from 'node:test'; +import { test } from 'node:test'; +import beforeEach from 'node:test'; +import afterEach from 'node:test'; import assert from 'node:assert/strict'; import { spy } from 'sinon'; diff --git a/test/feature.test.ts b/test/feature.test.ts index 3115efd3..c4d71c80 100644 --- a/test/feature.test.ts +++ b/test/feature.test.ts @@ -1,8 +1,7 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; - -import { spy } from 'sinon'; import Feature from '../src/feature_types/feature'; import createFeature from './utils/create_feature'; import getPublicMemberKeys from './utils/get_public_member_keys'; diff --git a/test/features_at.test.ts b/test/features_at.test.ts index 881923ad..f01c2530 100644 --- a/test/features_at.test.ts +++ b/test/features_at.test.ts @@ -1,4 +1,5 @@ import './mock-browser'; +import { spy } from 'sinon'; import test from 'node:test'; import assert from 'node:assert/strict'; import * as featuresAt from '../src/lib/features_at'; @@ -117,10 +118,8 @@ function createMockContext() { const layer = _layers[layerId]; if (!layer) { // this layer is not in the style.layers array - throw new ErrorEvent( - new Error( - `The layer '${layerId}' does not exist in the map's style and cannot be queried for features.` - ) + throw new Error( + `The layer '${layerId}' does not exist in the map's style and cannot be queried for features.` ); } includedSources[layer.source] = true; @@ -166,7 +165,7 @@ function createMockContext() { } }; - context.options = configureOptions(context.options); + context.options = configureOptions(context.options as spy) as spy; addLayers(context); @@ -174,7 +173,7 @@ function createMockContext() { } test('featuresAt with click bounding box', () => { - const mockContext = createMockContext(); + const mockContext = createMockContext() as spy; const result = featuresAt.click( null, [ @@ -219,7 +218,7 @@ test('featuresAt with click bounding box', () => { }); test('featuresAt with touch bounding box', () => { - const mockContext = createMockContext(); + const mockContext = createMockContext() as spy; const result = featuresAt.touch( null, [ @@ -264,7 +263,7 @@ test('featuresAt with touch bounding box', () => { }); test('featuresAt should not include missing style layers', () => { - const mockContext = createMockContext(); + const mockContext = createMockContext() as spy; // mock of map's setStyle, which will remove all mapbox-gl-draw styles until the data event is fired, in which mapbox-gl-draw adds back in the styles. mockContext.map.setStyle({}); diff --git a/test/interaction_events.test.ts b/test/interaction_events.test.ts index 1c4d7237..7d75f8a1 100644 --- a/test/interaction_events.test.ts +++ b/test/interaction_events.test.ts @@ -1189,10 +1189,6 @@ test('ensure API fire right events', async t => { } }; - t.afterEach(() => { - fireSpy.resetHistory(); - }); - await t.test('Draw#add fires draw.create event', async () => { Draw.add(point); assert.strictEqual(fireSpy.lastCall.firstArg, 'draw.create'); diff --git a/test/line_string.test.ts b/test/line_string.test.ts index 88a7ebea..a8bac041 100644 --- a/test/line_string.test.ts +++ b/test/line_string.test.ts @@ -194,20 +194,20 @@ test('LineString integration', async () => { await map.on('load'); - drawGeometry(map, Draw, 'LineString', lineStringCoordinates, () => { - const feats = Draw.getAll().features; - assert.equal(1, feats.length, 'only one'); - assert.equal('LineString', feats[0].geometry.type, 'of the right type'); - assert.equal( - lineStringCoordinates[0].length, - feats[0].geometry.coordinates[0].length, - 'right number of points' - ); - assert.deepEqual( - [...lineStringCoordinates, [20, 40]], - feats[0].geometry.coordinates, - 'in the right spot' - ); - Draw.onRemove(); - }); + await drawGeometry(map, Draw, 'LineString', lineStringCoordinates); + + const feats = Draw.getAll().features; + assert.equal(1, feats.length, 'only one'); + assert.equal('LineString', feats[0].geometry.type, 'of the right type'); + assert.equal( + lineStringCoordinates[0].length, + feats[0].geometry.coordinates[0].length, + 'right number of points' + ); + assert.deepEqual( + [...lineStringCoordinates, [20, 40]], + feats[0].geometry.coordinates, + 'in the right spot' + ); + Draw.onRemove(); }); diff --git a/test/mock-browser.ts b/test/mock-browser.ts index 5d9bb3f8..fc65f682 100644 --- a/test/mock-browser.ts +++ b/test/mock-browser.ts @@ -1,12 +1,13 @@ +import { spy } from 'sinon'; import MockBrowser from 'mock-browser'; const mock = new MockBrowser.mocks.MockBrowser(); global.document = mock.getDocument(); -global.window = {}; +(global.window as spy) = {}; // Polyfill based on https://gist.github.com/paulirish/1579671 let lastTime = 0; -global.requestAnimationFrame = function (fn) { +(global as spy).requestAnimationFrame = fn => { const now = Date.now(); const nextTime = Math.max(lastTime + 16, now); setTimeout(() => fn((lastTime = nextTime)), nextTime - now); diff --git a/test/simple_select.test.ts b/test/simple_select.test.ts index 58d76c9b..d83e0cea 100644 --- a/test/simple_select.test.ts +++ b/test/simple_select.test.ts @@ -972,7 +972,7 @@ test('simple_select', async t => { 'should not get any selected features' ); assert.equal( - context.store._emitSelectionChange, + (context.store as spy)._emitSelectionChange, undefined, 'should not emit selection change' ); @@ -995,7 +995,7 @@ test('simple_select', async t => { 'should not get any selected features' ); assert.equal( - context.store._emitSelectionChange, + (context.store as spy)._emitSelectionChange, undefined, 'should not emit selection change' ); diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index 0d4e26ad..a25dfe42 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -2,6 +2,7 @@ import { bboxClip } from '@turf/bbox-clip'; import Evented from '../../bench/lib/evented'; import { interactions } from '../../src/constants'; import type { StrictFeature } from '../../src/types/types'; +import type { Polygon } from 'geojson'; type Source = { data: { features: StrictFeature[] }; @@ -155,7 +156,7 @@ class MockMap extends Evented { } } } else { - const clipped = bboxClip(feature, bbox); + const clipped = bboxClip(feature as unknown as Polygon, bbox); if (clipped.geometry.coordinates.length) features.push(feature); } } diff --git a/tsconfig.json b/tsconfig.json index 3b4ac668..4f4d9930 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,15 @@ { "compilerOptions": { - "module": "ESNext", - "target": "ESNext", - "moduleResolution": "Node", + "target": "esnext", + "module": "NodeNext", + "moduleResolution": "node", "skipLibCheck": true, "esModuleInterop": true, + "allowSyntheticDefaultImports": true, "allowJs": true, "noEmit": true, "types": ["node"] }, - "include": [ - "./src/**/*", - "./test/**/*" - ] + "include": ["src", "test"] } + From 041405cb2f64803afefcd051352de65923c1d37c Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 16:19:23 -0400 Subject: [PATCH 51/59] tsx is better? --- package-lock.json | 233 ++++++++++------------------------------------ package.json | 6 +- 2 files changed, 53 insertions(+), 186 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1d0a63d..c9437a80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "rollup": "^4.19.1", "sinon": "^19.0.2", "synthetic-dom-events": "0.3.0", - "ts-node": "^10.9.2", + "tsx": "^4.19.3", "typescript": "^5.8.2", "vite": "^6.0.2", "vite-plugin-tsconfig-paths": "^1.4.1" @@ -93,28 +93,6 @@ "node": ">=6.9.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", @@ -663,6 +641,8 @@ "version": "3.1.2", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=6.0.0" } @@ -691,7 +671,9 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -1405,30 +1387,6 @@ "node": ">=10" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, "node_modules/@turf/bbox-clip": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-7.2.0.tgz", @@ -1791,30 +1749,6 @@ "acorn": "^4.0.4" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk/node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "dev": true, @@ -1867,12 +1801,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "dev": true, @@ -2472,12 +2400,6 @@ "dev": true, "license": "MIT" }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "dev": true, @@ -3651,9 +3573,11 @@ "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.2", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "license": "MIT", + "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -3794,6 +3718,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", + "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/getpass": { "version": "0.1.7", "dev": true, @@ -5091,12 +5027,6 @@ "dev": true, "license": "MIT" }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -6353,6 +6283,15 @@ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", "dev": true }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", "dev": true, @@ -7195,70 +7134,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -7277,6 +7152,25 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, + "node_modules/tsx": { + "version": "4.19.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", + "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "dev": true, @@ -7482,12 +7376,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "dev": true, @@ -7602,18 +7490,6 @@ "vite": "*" } }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/vt-pbf": { "version": "3.1.3", "dev": true, @@ -7889,15 +7765,6 @@ "node": ">=10" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "dev": true, diff --git a/package.json b/package.json index 8f7653ef..8597d584 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", "lint": "eslint src/**/*.ts", "pretest": "npm run lint", - "test": "node --loader ts-node/esm --test test/*.test.ts", - "coverage": "node --loader ts-node/esm --test test/*.test.ts --experimental-test-coverage", + "test": "tsx test/*.test.ts", + "coverage": "tsx test/*.test.ts --experimental-test-coverage", "build-token": "node build/generate-access-token-script.js", "build": "rollup -c", "build-min": "rollup -c --environment MINIFY:true", @@ -74,7 +74,7 @@ "rollup": "^4.19.1", "sinon": "^19.0.2", "synthetic-dom-events": "0.3.0", - "ts-node": "^10.9.2", + "tsx": "^4.19.3", "typescript": "^5.8.2", "vite": "^6.0.2", "vite-plugin-tsconfig-paths": "^1.4.1" From 845a741f14b272dbc38a5926a535bd3586e6ce61 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 17:25:55 -0400 Subject: [PATCH 52/59] Fixes to TypeScript for tests --- README.md | 8 -------- package-lock.json | 17 +++++++++++++++-- package.json | 1 + test/api.test.ts | 6 ++---- test/utils/create_map.ts | 7 ++++++- tsconfig.json | 6 +++--- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e0282c74..fcaca506 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,6 @@ import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css' ``` -### Typescript - -Typescript definition files are available as part of the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/mapbox__mapbox-gl-draw) package. - -``` -npm install @types/mapbox__mapbox-gl-draw -``` - ### Example usage ```js diff --git a/package-lock.json b/package-lock.json index c9437a80..43139a26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@turf/bbox-clip": "^7.0.0", "@turf/centroid": "^7.0.0", "@types/geojson": "^7946.0.16", + "@types/node": "^22.13.10", "@typescript-eslint/parser": "^8.26.0", "eslint": "^8.57.1", "eslint-plugin-import": "^2.31.0", @@ -1535,9 +1536,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.7.14", + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", @@ -7333,6 +7339,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "node_modules/uri-js": { "version": "4.4.1", "dev": true, diff --git a/package.json b/package.json index 8597d584..f0f09940 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@turf/bbox-clip": "^7.0.0", "@turf/centroid": "^7.0.0", "@types/geojson": "^7946.0.16", + "@types/node": "^22.13.10", "@typescript-eslint/parser": "^8.26.0", "eslint": "^8.57.1", "eslint-plugin-import": "^2.31.0", diff --git a/test/api.test.ts b/test/api.test.ts index bba7ab20..69bcb58e 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -1,10 +1,8 @@ /* eslint no-shadow:[0] */ import './mock-browser'; -import { test } from 'node:test'; -import beforeEach from 'node:test'; -import afterEach from 'node:test'; -import assert from 'node:assert/strict'; +import { test, beforeEach, afterEach } from 'node:test'; import { spy } from 'sinon'; +import assert from 'node:assert/strict'; import * as Constants from '../src/constants'; import MapboxDraw from '../index'; diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index a25dfe42..ddee2ea5 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -62,8 +62,13 @@ class MockMap extends Evented { }; // Explicitly define each interaction + this.scrollZoom = this.createInteraction(); + this.boxZoom = this.createInteraction(); + this.dragRotate = this.createInteraction(); this.dragPan = this.createInteraction(); + this.keyboard = this.createInteraction(); this.doubleClickZoom = this.createInteraction(); + this.touchZoomRotate = this.createInteraction(); // Dynamically add any other interactions for (const interaction of interactions) { @@ -78,7 +83,7 @@ class MockMap extends Evented { } // Helper function to create interaction objects - private createInteraction(): Interaction { + createInteraction(): Interaction { return { enabled: true, disable() { diff --git a/tsconfig.json b/tsconfig.json index 4f4d9930..adbc111c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "esnext", - "module": "NodeNext", - "moduleResolution": "node", + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "Node", "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, From 31a70359c4faa7b11df5e7f2dec662f12341e274 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 17:33:14 -0400 Subject: [PATCH 53/59] Lint fixes suspiciously light --- package.json | 2 +- src/render.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f0f09940..bf9fabf5 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", - "lint": "eslint src/**/*.ts", + "lint": "eslint --cache **/*.ts", "pretest": "npm run lint", "test": "tsx test/*.test.ts", "coverage": "tsx test/*.test.ts --experimental-test-coverage", diff --git a/src/render.ts b/src/render.ts index fe775089..dfded13e 100644 --- a/src/render.ts +++ b/src/render.ts @@ -34,9 +34,9 @@ export default function render() { store.sources.cold = store.isDirty ? [] : store.sources.cold.filter(geojson => { - const id = geojson.properties.id || geojson.properties.parent; - return newHotIds.indexOf(id) === -1; - }); + const id = geojson.properties.id || geojson.properties.parent; + return newHotIds.indexOf(id) === -1; + }); const coldChanged = lastColdCount !== store.sources.cold.length || newColdIds.length > 0; From b54417b5b9b9fe45c20da58b472f7470bf9620b6 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 17:36:20 -0400 Subject: [PATCH 54/59] Bad typo --- test/utils/create_map.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/create_map.ts b/test/utils/create_map.ts index ddee2ea5..ebbcc284 100644 --- a/test/utils/create_map.ts +++ b/test/utils/create_map.ts @@ -137,7 +137,7 @@ class MockMap extends Evented { addLayer() {} - queryRenderedStrictFeatures([p0, p1]: [{ x: number; y: number } | Coordinates, { x: number; y: number } | Coordinates]): StrictFeature[] { + queryRenderedFeatures([p0, p1]: [{ x: number; y: number } | Coordinates, { x: number; y: number } | Coordinates]): StrictFeature[] { if (!Array.isArray(p0)) p0 = [p0.x, p0.y]; if (!Array.isArray(p1)) p1 = [p1.x, p1.y]; const minX = Math.min(p0[0], p1[0]); From 7257289066dea64ac24c5894e1c898c4730e080e Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 18:02:57 -0400 Subject: [PATCH 55/59] Need to confirm undefined here --- package.json | 2 +- test/api.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bf9fabf5..8942f2b5 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "docs": "run-s docs-modes-life-cycle docs-modes-get-and-set", "docs-modes-get-and-set": "documentation readme --readme-file ./docs/MODES.md -s \"Setters and Getters\" src/modes/mode_interface_accessors.ts --shallow", "docs-modes-life-cycle": "documentation readme --readme-file ./docs/MODES.md -s \"Life Cycle Functions\" src/modes/mode_interface.ts --shallow", - "lint": "eslint --cache **/*.ts", + "lint": "eslint **/*.ts", "pretest": "npm run lint", "test": "tsx test/*.test.ts", "coverage": "tsx test/*.test.ts --experimental-test-coverage", diff --git a/test/api.test.ts b/test/api.test.ts index 69bcb58e..5efb4cdd 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -393,9 +393,10 @@ test('Draw.changeMode and Draw.getMode with no pre-existing feature', () => { 'Polygon', 'and it is a polygon' ); + assert.deepEqual( Draw.getAll().features[0].geometry.coordinates, - [[null]], + [[undefined]], 'and it is empty' ); From 37b1e97d5872d6c4f2ea9d6613560892195a876a Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 18:22:11 -0400 Subject: [PATCH 56/59] Not a major version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 091aa4fe..b19abc87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mapbox/mapbox-gl-draw", - "version": "2.0.0", + "version": "1.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mapbox/mapbox-gl-draw", - "version": "2.0.0", + "version": "1.6.0", "license": "ISC", "dependencies": { "@mapbox/geojson-area": "^0.2.2", diff --git a/package.json b/package.json index 8942f2b5..f7d67ebf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mapbox/mapbox-gl-draw", - "version": "2.0.0", + "version": "1.6.0", "engines": { "node": "^18.0.0 || >=20.0.0" }, From bd51259f6e1c1f4c0e1428faff6dd2a505981ad3 Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 18:38:57 -0400 Subject: [PATCH 57/59] Fix rollup --- package-lock.json | 84 +++++++++++++++++++++++++++++++---------------- package.json | 1 + rollup.config.js | 19 ++++++++--- 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index b19abc87..d375f70b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-replace": "^6.0.1", + "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^12.1.2", "@turf/bbox-clip": "^7.0.0", "@turf/centroid": "^7.0.0", @@ -627,8 +628,6 @@ "version": "0.3.5", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -642,8 +641,6 @@ "version": "3.1.2", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=6.0.0" } @@ -652,8 +649,6 @@ "version": "1.2.1", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">=6.0.0" } @@ -662,8 +657,6 @@ "version": "0.3.6", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -672,16 +665,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -690,9 +679,7 @@ "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@mapbox/cloudfriend": { "version": "8.2.0", @@ -991,6 +978,29 @@ } } }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-typescript": { "version": "12.1.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz", @@ -2111,9 +2121,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/buffer/node_modules/isarray": { "version": "1.0.0", @@ -2383,9 +2391,7 @@ "node_modules/commander": { "version": "2.20.3", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/commondir": { "version": "1.0.1", @@ -6075,6 +6081,16 @@ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", "dev": true }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "dev": true, @@ -6531,6 +6547,16 @@ "semver": "bin/semver.js" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/serialize-to-js": { "version": "3.1.2", "dev": true, @@ -6738,11 +6764,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" + }, "node_modules/source-map": { "version": "0.6.1", "dev": true, "license": "BSD-3-Clause", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -6761,8 +6793,6 @@ "version": "0.5.21", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7053,8 +7083,6 @@ "version": "5.31.1", "dev": true, "license": "BSD-2-Clause", - "optional": true, - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -7072,8 +7100,6 @@ "version": "8.12.0", "dev": true, "license": "MIT", - "optional": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, diff --git a/package.json b/package.json index f7d67ebf..798b170d 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-replace": "^6.0.1", + "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^12.1.2", "@turf/bbox-clip": "^7.0.0", "@turf/centroid": "^7.0.0", diff --git a/rollup.config.js b/rollup.config.js index 6ef06f75..dc2b37dd 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,18 +1,27 @@ +import typescript from '@rollup/plugin-typescript'; +import terser from '@rollup/plugin-terser'; + const { MINIFY } = process.env; const minified = MINIFY === 'true'; const outputFile = minified ? 'dist/mapbox-gl-draw.js' : 'dist/mapbox-gl-draw-unminified.js'; -import typescript from '@rollup/plugin-typescript'; - export default { input: 'index.ts', output: { name: 'MapboxDraw', file: outputFile, - format: 'esm', // Ensure ESM output if using ES modules - sourcemap: true + format: 'esm', + sourcemap: true, + indent: false }, - plugins: [typescript()] + treeshake: true, + plugins: [ + typescript(), + minified ? terser({ + ecma: 2020, + module: true, + }) : false, + ] }; From dde51f27674c21f877073524d3ef847533963c2b Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 18:55:23 -0400 Subject: [PATCH 58/59] Drop `export` where it is not necessary --- src/types/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index 8331a8fe..bc4ec968 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -116,7 +116,7 @@ export interface DrawMapClasses { mouse?: Constants['cursors']; } -export interface DrawUI { +interface DrawUI { queueMapClasses: (options: DrawMapClasses) => void; setActiveButton: (id: string) => void; updateMapClasses: () => void; @@ -174,7 +174,7 @@ interface DrawFeatureBase { toGeoJSON(): GeoJSON; } -export interface DrawMultiFeature< +interface DrawMultiFeature< Type extends 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' > extends Omit< DrawFeatureBase< @@ -297,7 +297,7 @@ interface DrawActionableEvent extends DrawEvent { type: 'draw.actionable'; } -export interface DrawCustomModeThis { +interface DrawCustomModeThis { map: Map; _ctx: CTX; drawConfig: DrawOptions; @@ -432,7 +432,7 @@ interface StringSet { clear(): StringSet; } -export interface Lib { +interface Lib { CommonSelectors: { isOfMetaType: ( type: Constants['meta'][keyof Constants['meta']] From d180d1fccd5fc668c8fc16986bae901344f4cfaf Mon Sep 17 00:00:00 2001 From: tristen Date: Mon, 17 Mar 2025 21:36:16 -0400 Subject: [PATCH 59/59] Remove overriding method --- src/feature_types/line_string.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/feature_types/line_string.ts b/src/feature_types/line_string.ts index 3a3eab54..2f559f71 100644 --- a/src/feature_types/line_string.ts +++ b/src/feature_types/line_string.ts @@ -35,8 +35,6 @@ class LineString extends Feature { this.coordinates[id] = [lng, lat]; this.changed(); } - - changed(): void {} } export default LineString;