diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 24bf6273..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "env": { - "cypress/globals": true, - "node": true, - "browser": true, - "es6": true - }, - "extends": ["eslint-config-airbnb-base", "prettier"], - "parserOptions": { - "ecmaVersion": 2022 - }, - "plugins": ["cypress", "prettier"], - "rules": { - "prettier/prettier": "error" - } -} diff --git a/.husky/commit-msg b/.husky/commit-msg index 4c49ae6a..2785bc1d 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - yarn commitlint --edit $1 diff --git a/.husky/post-checkout b/.husky/post-checkout index 8807e035..297e57f8 100755 --- a/.husky/post-checkout +++ b/.husky/post-checkout @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - yarn install --frozen-lockfile diff --git a/.husky/post-merge b/.husky/post-merge index 8807e035..297e57f8 100755 --- a/.husky/post-merge +++ b/.husky/post-merge @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - yarn install --frozen-lockfile diff --git a/.husky/post-rebase b/.husky/post-rebase index 8807e035..297e57f8 100755 --- a/.husky/post-rebase +++ b/.husky/post-rebase @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - yarn install --frozen-lockfile diff --git a/.husky/pre-commit b/.husky/pre-commit index f61666c0..e377655a 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,3 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - if git grep -n -E \"5cc87b12d7c5370001c1d656\(5\)\"; then echo \"Remove private geOps API keys !!!!\"; diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 8c7aa784..2b0dc492 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,5 +1,6 @@ { "(src|__mocks__)/**/*.js": ["eslint --fix", "prettier --write"], + "cypress/e2e/**/*.js": ["eslint --fix", "prettier --write"], "package.json": ["yarn fixpack"], "src/**/*.{css,scss}": ["stylelint --fix"] } diff --git a/.prettierrc.json b/.prettierrc.json index 6e778b4f..0967ef42 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1 @@ -{ - "trailingComma": "all", - "singleQuote": true -} +{} diff --git a/cypress/e2e/control/cad.spec.js b/cypress/e2e/control/cad.spec.js index e36d95cd..fef6af75 100644 --- a/cypress/e2e/control/cad.spec.js +++ b/cypress/e2e/control/cad.spec.js @@ -8,56 +8,38 @@ const coordToFixed = (coordArray, decimals) => { return arr; }; -describe('CAD control', () => { +describe("CAD control", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); // Draw point (click on map canvas container at x: 500 and y: 500) cy.get('[title="Draw Point"]').click(); - cy.get('.ol-overlaycontainer').click(500, 500, FORCE); + cy.get(".ol-viewport").click(500, 500, FORCE); }); - it.only('should not snap new points when CAD deactivated', () => { - cy.window().then((win) => { - // Draw new point (click on map canvas container at x: 507 and y: 500) - cy.get('.ol-overlaycontainer') - .click(507, 500, FORCE) - .then(() => { - const newPoint = win.editLayer.getSource().getFeatures()[1]; - // New point should not have additional snapping distance in coordinate - expect( - JSON.stringify(newPoint.getGeometry().getCoordinates()), - ).to.equal( - JSON.stringify(win.map.getCoordinateFromPixel([507, 500])), - ); - }); - }); - }); + it("should snap new points to CAD point with CAD active", () => { + let win; + // Draw new point (click on map canvas container at x: 507 and y: 500) + cy.get(".ol-viewport").trigger("mousemove", 550, 500, FORCE); + cy.get(".ol-viewport").click(535, 500, FORCE); + + cy.window() + .then((win2) => { + win = win2; + }) + .then(() => { + const snapDistance = win.cad.properties.snapPointDist; + const newPoint = win.editLayer.getSource().getFeatures()[1]; - it('should snap new points to CAD point with CAD active', () => { - cy.window().then((win) => { - // Activate CAD control (click on toolbar) - cy.get('.ole-control-cad').click(); - // Draw new point (click on map canvas container at x: 507 and y: 500) - cy.get('.ol-overlaycontainer') - .click(507, 500, FORCE) - .then(() => { - const snapDistance = win.cad.properties.snapPointDist; - const newPoint = win.editLayer.getSource().getFeatures()[1]; - // New point should have added snapping distance (use toFixed to ignore micro differences) - expect( - JSON.stringify( - coordToFixed(newPoint.getGeometry().getCoordinates(), 5), - ), - ).to.equal( - JSON.stringify( - coordToFixed( - win.map.getCoordinateFromPixel([500 + snapDistance, 500]), - 5, - ), - ), - ); - }); - }); + // New point should have added snapping distance (use toFixed to ignore micro differences) + expect( + coordToFixed(newPoint.getGeometry().getCoordinates(), 5).toString(), + ).to.equal( + coordToFixed( + win.map.getCoordinateFromPixel([500 + snapDistance, 500]), + 5, + ).toString(), + ); + }); }); }); diff --git a/cypress/e2e/control/difference.spec.js b/cypress/e2e/control/difference.spec.js index 0c8edb22..809fec54 100644 --- a/cypress/e2e/control/difference.spec.js +++ b/cypress/e2e/control/difference.spec.js @@ -1,48 +1,39 @@ const FORCE = { force: true }; -describe('Difference control', () => { +describe("Difference control", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); // Draw polygon (click on map container, double click to finish drawing) cy.get('[title="Draw Polygon"]').click(); - cy.get('.ol-overlaycontainer').click(500, 200, FORCE); - cy.get('.ol-overlaycontainer').click(600, 400, FORCE); - cy.get('.ol-overlaycontainer').dblclick(400, 400, FORCE); + cy.get(".ol-overlaycontainer").click(500, 200, FORCE); + cy.get(".ol-overlaycontainer").click(600, 400, FORCE); + cy.get(".ol-overlaycontainer").dblclick(400, 400, FORCE); // Draw overlapping polygon (click on map container, double click to finish drawing) - cy.get('.ol-overlaycontainer').click(600, 200, FORCE); - cy.get('.ol-overlaycontainer').click(550, 350, FORCE); - cy.get('.ol-overlaycontainer').dblclick(400, 300, FORCE); + cy.get(".ol-overlaycontainer").click(600, 200, FORCE); + cy.get(".ol-overlaycontainer").click(550, 350, FORCE); + cy.get(".ol-overlaycontainer").dblclick(400, 300, FORCE); }); - it('should subtract overlapping polygons and result in the correct multipolygon', () => { + it("should subtract overlapping polygons and result in the correct multipolygon", () => { cy.window().then((win) => { // Activate union tool (click on toolbar) - cy.get('.ole-control-difference') - .click() - .then(() => { - // Click on map canvas to select polygon for subtraction - cy.get('.ol-overlaycontainer').click(500, 210, FORCE); - }) - .then(() => { - cy.wait(1000); // Wait to avoid zoom on map due to load races - // Click on map canvas to select polygon to subtract - cy.get('.ol-overlaycontainer').click(580, 220, FORCE); - cy.wait(1000).then(() => { - const united = win.editLayer.getSource().getFeatures()[0]; - // Should result in a multipolygon (thus have two coordinate arrays) - expect(united.getGeometry().getCoordinates().length).to.equal(2); - // First polygon should result in a triangle (3 nodes, 4 coordinates) - expect(united.getGeometry().getCoordinates()[0][0].length).to.equal( - 4, - ); - // Second polygon should have 5 nodes (6 coordinates) - expect(united.getGeometry().getCoordinates()[1][0].length).to.equal( - 6, - ); - }); - }); + cy.get(".ole-control-difference").click(); + // Click on map canvas to select polygon for subtraction + cy.get(".ol-overlaycontainer").click(500, 210, FORCE); + cy.wait(1000); // Wait to avoid zoom on map due to load races + // Click on map canvas to select polygon to subtract + cy.get(".ol-overlaycontainer").click(580, 220, FORCE); + cy.wait(1000).then(() => { + const united = win.editLayer.getSource().getFeatures()[0]; + // Should result in a multipolygon (thus have two coordinate arrays) + expect(united.getGeometry().getCoordinates().length).to.equal(2); + // First polygon should result in a triangle (3 nodes, 4 coordinates) + expect(united.getGeometry().getCoordinates()[0][0].length).to.equal(4); + // Second polygon should have 5 nodes (6 coordinates) + expect(united.getGeometry().getCoordinates()[1][0].length).to.equal(6); + }); }); }); }); diff --git a/cypress/e2e/control/draw.spec.js b/cypress/e2e/control/draw.spec.js index a61a56c1..665d18c8 100644 --- a/cypress/e2e/control/draw.spec.js +++ b/cypress/e2e/control/draw.spec.js @@ -1,29 +1,29 @@ -describe('Draw control', () => { +describe("Draw control", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); }); - it('should show draw control for points', () => { - cy.get('.ole-control-draw') + it("should show draw control for points", () => { + cy.get(".ole-control-draw") .first() - .should('have.attr', 'title', 'Draw Point'); + .should("have.attr", "title", "Draw Point"); - cy.get('.ole-control-draw').first().click(); - cy.get('.ol-viewport').click('center'); - cy.window().then((win) => - expect(win.editLayer.getSource().getFeatures().length).to.eq(1), - ); + cy.get(".ole-control-draw").first().click(); + cy.get(".ol-viewport").click("center"); + cy.window().then((win) => { + return expect(win.editLayer.getSource().getFeatures().length).to.eq(1); + }); }); - it('should show draw control for lines', () => { - cy.get('.ole-control-draw') + it("should show draw control for lines", () => { + cy.get(".ole-control-draw") .eq(1) - .should('have.attr', 'title', 'Draw LineString'); + .should("have.attr", "title", "Draw LineString"); }); - it('should show draw control for polygons', () => { - cy.get('.ole-control-draw') + it("should show draw control for polygons", () => { + cy.get(".ole-control-draw") .last() - .should('have.attr', 'title', 'Draw Polygon'); + .should("have.attr", "title", "Draw Polygon"); }); }); diff --git a/cypress/e2e/control/intersection.spec.js b/cypress/e2e/control/intersection.spec.js index b555ed43..09fe5d87 100644 --- a/cypress/e2e/control/intersection.spec.js +++ b/cypress/e2e/control/intersection.spec.js @@ -1,40 +1,35 @@ const FORCE = { force: true }; -describe('Intersect control', () => { +describe("Intersect control", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); // Draw polygon (click on map container, double click to finish drawing) cy.get('[title="Draw Polygon"]').click(); - cy.get('.ol-overlaycontainer').click(500, 200, FORCE); - cy.get('.ol-overlaycontainer').click(600, 400, FORCE); - cy.get('.ol-overlaycontainer').dblclick(400, 400, FORCE); + cy.get(".ol-overlaycontainer").click(500, 200, FORCE); + cy.get(".ol-overlaycontainer").click(600, 400, FORCE); + cy.get(".ol-overlaycontainer").dblclick(400, 400, FORCE); // Draw overlapping polygon (click on map container, double click to finish drawing) - cy.get('.ol-overlaycontainer').click(600, 200, FORCE); - cy.get('.ol-overlaycontainer').click(550, 350, FORCE); - cy.get('.ol-overlaycontainer').dblclick(400, 300, FORCE); + cy.get(".ol-overlaycontainer").click(600, 200, FORCE); + cy.get(".ol-overlaycontainer").click(550, 350, FORCE); + cy.get(".ol-overlaycontainer").dblclick(400, 300, FORCE); }); - it('should intersect two overlapping polygons resulting in one with correct nodes', () => { + it("should intersect two overlapping polygons resulting in one with correct nodes", () => { cy.window().then((win) => { // Activate union tool (click on toolbar) - cy.get('.ole-control-intersection') - .click() - .then(() => { - // Click on map canvas to select polygon for intersection - cy.get('.ol-overlaycontainer').click(500, 210, FORCE); - }) - .then(() => { - cy.wait(1000); // Wait to avoid zoom on map due to load races - // Click on map canvas to select overlapping polygon - cy.get('.ol-overlaycontainer').click(580, 220, FORCE); - cy.wait(1000).then(() => { - // New (united) polygon should have 5 nodes (6 coordinates) - const united = win.editLayer.getSource().getFeatures()[0]; - expect(united.getGeometry().getCoordinates()[0].length).to.equal(6); - }); - }); + cy.get(".ole-control-intersection").click(); + // Click on map canvas to select polygon for intersection + cy.get(".ol-overlaycontainer").click(500, 210, FORCE); + cy.wait(1000); // Wait to avoid zoom on map due to load races + // Click on map canvas to select overlapping polygon + cy.get(".ol-overlaycontainer").click(580, 220, FORCE); + cy.wait(1000).then(() => { + // New (united) polygon should have 5 nodes (6 coordinates) + const united = win.editLayer.getSource().getFeatures()[0]; + expect(united.getGeometry().getCoordinates()[0].length).to.equal(6); + }); }); }); }); diff --git a/cypress/e2e/control/modify.spec.js b/cypress/e2e/control/modify.spec.js index e4745cb7..b5e2aa52 100644 --- a/cypress/e2e/control/modify.spec.js +++ b/cypress/e2e/control/modify.spec.js @@ -1,35 +1,36 @@ +/* eslint-disable cypress/unsafe-to-chain-command */ const FORCE = { force: true }; -describe('ModifyControl', () => { +describe("ModifyControl", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); // Draw polygon (click on map container, double click to finish drawing) cy.get('[title="Draw Polygon"]').click(); - cy.get('.ol-overlaycontainer').click(100, 100, FORCE); - cy.get('.ol-overlaycontainer').click(100, 150, FORCE); - cy.get('.ol-overlaycontainer').click(150, 170, FORCE); - cy.get('.ol-overlaycontainer').dblclick(200, 100, FORCE); + cy.get(".ol-overlaycontainer").click(100, 100, FORCE); + cy.get(".ol-overlaycontainer").click(100, 150, FORCE); + cy.get(".ol-overlaycontainer").click(150, 170, FORCE); + cy.get(".ol-overlaycontainer").dblclick(200, 100, FORCE); // Draw line (click on map container, double click to finish drawing) cy.get('[title="Draw LineString"]').click(); - cy.get('.ol-overlaycontainer').click(400, 350, FORCE); - cy.get('.ol-overlaycontainer').click(270, 344, FORCE); - cy.get('.ol-overlaycontainer').dblclick(200, 450, FORCE); + cy.get(".ol-overlaycontainer").click(400, 350, FORCE); + cy.get(".ol-overlaycontainer").click(270, 344, FORCE); + cy.get(".ol-overlaycontainer").dblclick(200, 450, FORCE); }); - it('should correctly handle node deletion', () => { + it("should correctly handle node deletion", () => { cy.window().then((win) => { // Spy on selectModify.addFeatureLayerAssociation_, called when a feature is selected const omitFeatureSelectSpy = cy.spy( win.modify.selectModify, - 'addFeatureLayerAssociation_', + "addFeatureLayerAssociation_", ); let selectedFeaturesArray = []; // Select Modify Control (click on toolbar) - cy.get('.ole-control-modify').click(); + cy.get(".ole-control-modify").click(); // Select polygon (double click polygon in map canvas container to start modifying) - cy.get('.ol-viewport') + cy.get(".ol-viewport") .dblclick(100, 100, FORCE) .then(() => { selectedFeaturesArray = win.modify.selectModify @@ -44,7 +45,7 @@ describe('ModifyControl', () => { }); // Click & delete a node (click on map canvas at node pixel) // Click & delete a node (click on map canvas at node pixel) - cy.get('.ol-viewport') + cy.get(".ol-viewport") .click(102, 152) .then(() => { // singleclick event needs a timeout period. @@ -60,7 +61,7 @@ describe('ModifyControl', () => { }); // Click another node (click on map canvas at node pixel) - cy.get('.ol-viewport') + cy.get(".ol-viewport") .click(100, 100, FORCE) .then(() => { // singleclick event needs a timeout period. @@ -74,13 +75,14 @@ describe('ModifyControl', () => { omitFeatureSelectSpy.args[0][0], null, ); - // eslint-disable-next-line no-unused-expressions + + // eslint-disable-next-line @typescript-eslint/no-unused-expressions expect(toTest).to.not.be.called; }); }); // Select line (double click line in map canvas container to start modifying) - cy.get('.ol-viewport') + cy.get(".ol-viewport") .dblclick(270, 344, FORCE) .then(() => { selectedFeaturesArray = win.modify.selectModify @@ -95,7 +97,7 @@ describe('ModifyControl', () => { }); // Click & delete a node (click on map canvas at node pixel) - cy.get('.ol-viewport') + cy.get(".ol-viewport") .click(270, 344, FORCE) .then(() => { // singleclick event needs a timeout period. @@ -108,7 +110,7 @@ describe('ModifyControl', () => { }); // Click another node (click on map canvas at node pixel) - cy.get('.ol-viewport') + cy.get(".ol-viewport") .click(400, 350, FORCE) .then(() => { // Verify no further node was deleted on click (because polygon minimum number nodes is 2) @@ -116,7 +118,8 @@ describe('ModifyControl', () => { selectedFeaturesArray[0].getGeometry().getCoordinates().length, ).to.equal(2); // Check that no features from the overlay are mistakenly selected - // eslint-disable-next-line no-unused-expressions + + // eslint-disable-next-line @typescript-eslint/no-unused-expressions expect( omitFeatureSelectSpy.withArgs( omitFeatureSelectSpy.args[0][0], diff --git a/cypress/e2e/control/union.spec.js b/cypress/e2e/control/union.spec.js index a66735fc..67c06da1 100644 --- a/cypress/e2e/control/union.spec.js +++ b/cypress/e2e/control/union.spec.js @@ -1,42 +1,35 @@ const FORCE = { force: true }; -describe('Union control', () => { +describe("Union control", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); // Draw polygon (click on map container, double click to finish drawing) cy.get('[title="Draw Polygon"]').click(); - cy.get('.ol-overlaycontainer').click(500, 200, FORCE); - cy.get('.ol-overlaycontainer').click(600, 400, FORCE); - cy.get('.ol-overlaycontainer').dblclick(400, 400, FORCE); + cy.get(".ol-overlaycontainer").click(500, 200, FORCE); + cy.get(".ol-overlaycontainer").click(600, 400, FORCE); + cy.get(".ol-overlaycontainer").dblclick(400, 400, FORCE); // Draw overlapping polygon (click on map container, double click to finish drawing) - cy.get('.ol-overlaycontainer').click(600, 200, FORCE); - cy.get('.ol-overlaycontainer').click(550, 350, FORCE); - cy.get('.ol-overlaycontainer').dblclick(400, 300, FORCE); + cy.get(".ol-overlaycontainer").click(600, 200, FORCE); + cy.get(".ol-overlaycontainer").click(550, 350, FORCE); + cy.get(".ol-overlaycontainer").dblclick(400, 300, FORCE); }); - it('should unite two overlapping polygons to one polygon with correct nodes', () => { + it("should unite two overlapping polygons to one polygon with correct nodes", () => { cy.window().then((win) => { // Activate union tool (click on toolbar) - cy.get('.ole-control-union') - .click() - .then(() => { - // Click on map canvas to select polygon for unison - cy.get('.ol-overlaycontainer').click(500, 210, FORCE); - }) - .then(() => { - cy.wait(1000); // Wait to avoid zoom on map due to load races - // Click on map canvas to select overlapping polygon - cy.get('.ol-overlaycontainer').click(580, 220, FORCE); - cy.wait(1000).then(() => { - // New (united) polygon should have 9 nodes (10 coordinates) - const united = win.editLayer.getSource().getFeatures()[0]; - expect(united.getGeometry().getCoordinates()[0].length).to.equal( - 10, - ); - }); - }); + cy.get(".ole-control-union").click(); + // Click on map canvas to select polygon for unison + cy.get(".ol-overlaycontainer").click(500, 210, FORCE); + cy.wait(1000); // Wait to avoid zoom on map due to load races + // Click on map canvas to select overlapping polygon + cy.get(".ol-overlaycontainer").click(580, 220, FORCE); + cy.wait(1000).then(() => { + // New (united) polygon should have 9 nodes (10 coordinates) + const united = win.editLayer.getSource().getFeatures()[0]; + expect(united.getGeometry().getCoordinates()[0].length).to.equal(10); + }); }); }); }); diff --git a/cypress/e2e/ole.spec.js b/cypress/e2e/ole.spec.js index 08bd2609..c6105123 100644 --- a/cypress/e2e/ole.spec.js +++ b/cypress/e2e/ole.spec.js @@ -1,9 +1,9 @@ -describe('OLE', () => { +describe("OLE", () => { beforeEach(() => { - cy.visit('/'); + cy.visit("/"); }); - it('should initialize OLE toolbar', () => { - cy.get('#ole-toolbar').should('exist'); + it("should initialize OLE toolbar", () => { + cy.get("#ole-toolbar").should("exist"); }); }); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..1b48eb0f --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,33 @@ +import eslint from "@eslint/js"; +import pluginCypress from "eslint-plugin-cypress/flat"; +import perfectionist from "eslint-plugin-perfectionist"; +import prettier from "eslint-plugin-prettier/recommended"; +import globals from "globals"; +import ts from "typescript-eslint"; + +export default [ + { + ignores: ["build/*"], + languageOptions: { + globals: { + ...globals.browser, + }, + }, + }, + ...ts.config( + eslint.configs.recommended, + ...ts.configs.strict, + ...ts.configs.stylistic, + pluginCypress.configs.recommended, + perfectionist.configs["recommended-alphabetical"], + prettier, + { + rules: { + "@typescript-eslint/prefer-for-of": "off", + "arrow-body-style": ["error", "always"], + curly: "error", + "cypress/no-unnecessary-waiting": "off", + }, + }, + ), +]; diff --git a/index.html b/index.html index 727f5593..f8a92a6a 100644 --- a/index.html +++ b/index.html @@ -150,6 +150,9 @@ var cad = new ole.control.CAD({ source: editLayer.getSource(), + showSnapPointsOnlyOnPoints: true, + dialogTarget: null, + element: null }); var draw = new ole.control.Draw({ @@ -190,6 +193,85 @@ source: editLayer.getSource(), }); + draw.on('change:active', function (evt) { + if (evt.target.active) { + cad.setProperties({ + showSnapPoints: true, + showSnapLines: false, + }); + } + }); + + drawLine.on('change:active', function (evt) { + if (evt.target.active) { + cad.setProperties({ + showSnapPoints: false, + showSnapLines: true, + }); + } + }); + + drawPoly.on('change:active', function (evt) { + if (evt.target.active) { + cad.setProperties({ + showSnapPoints: false, + showSnapLines: true, + }); + } + }); + + [draw, drawLine, drawPoly].forEach(function (control) { + control.on('change:active', function (evt) { + if (evt.target.active) { + if (!cad.getActive()) { + cad.activate(); + } + } else if (cad.getActive() && !draw.getActive() && !drawLine.getActive() && !drawPoly.getActive()) { + cad.deactivate(); + } + }); + }); + + [modify, buffer, union, intersection, difference].forEach(function (control) { + control.on('change:active', function (evt) { + if (evt.target.active) { + cad.deactivate(true); + } + }); + }); + + modify.moveInteraction.on('movestart', function () { + const features = modify.selectMove.getFeatures(); + const length = features?.getLength(); + const firstFeature = features?.item(0); + if (length > 1 || firstFeature?.getGeometry()?.getType() !== 'Point') { + return; + } + cad.setProperties({ + showSnapPoints: true, + showSnapLines: false, + }); + cad.activate(); + }); + + modify.moveInteraction.on('moveend', function () { + cad.deactivate(); + }); + + modify.modifyInteraction.on('modifystart', function () { + cad.setProperties({ + showSnapPoints: false, + showSnapLines: true, + }); + cad.activate(); + }); + + modify.modifyInteraction.on('modifyend', function () { + cad.deactivate(); + }); + + + editor.addControls([ cad, draw, @@ -203,9 +285,9 @@ difference, ]); - var ls = new ole.service.LocalStorage(); + // var ls = new ole.service.LocalStorage(); - editor.addService(ls); + // editor.addService(ls); // For tests purpose window.editor = editor; diff --git a/package.json b/package.json index 2ddb336a..9a312a4a 100644 --- a/package.json +++ b/package.json @@ -13,15 +13,18 @@ "devDependencies": { "@commitlint/cli": "19.5.0", "@commitlint/config-conventional": "19.5.0", - "cypress": "13.14.2", - "esbuild": "0.23.1", - "eslint": "8", + "@eslint/js": "^9.12.0", + "cypress": "13.15.0", + "esbuild": "0.24.0", + "eslint": "9.12.0", "eslint-config-airbnb-base": "15.0.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-cypress": "3.5.0", - "eslint-plugin-import": "2.30.0", + "eslint-plugin-cypress": "4.0.0", + "eslint-plugin-import": "2.31.0", + "eslint-plugin-perfectionist": "^3.8.0", "eslint-plugin-prettier": "5.2.1", "fixpack": "4.0.0", + "globals": "^15.11.0", "happy-dom": "^15.7.4", "husky": "9.1.6", "is-ci": "3.0.1", @@ -30,15 +33,16 @@ "jsts": "2.11.3", "lint-staged": "15.2.10", "lodash.throttle": "4.1.1", - "ol": "^10.1.0", + "ol": "^10.2.1", "prettier": "3.3.3", "shx": "0.3.4", "standard-version": "9.5.0", "start-server-and-test": "2.0.8", - "stylelint": "16.9.0", + "stylelint": "16.10.0", "stylelint-config-standard": "36.0.1", - "typescript": "5.6.2", - "vitest": "^2.1.1" + "typescript": "5.6.3", + "typescript-eslint": "^8.9.0", + "vitest": "^2.1.3" }, "scripts": { "build": "shx rm -rf build && tsc --project config/tsconfig-build.json && esbuild build/index.js --bundle --global-name=ole --loader:.svg=dataurl --minify --outfile=build/bundle.js", @@ -47,8 +51,8 @@ "cy:test": "start-server-and-test start http://127.0.0.1:8000 cy:run", "doc": "jsdoc -p -r -c jsdoc_conf.json src -d doc README.md && shx cp build/bundle.js index.js", "fixpack": "fixpack", - "format": "prettier --write 'cypress/integration/*.js' 'src/**/*.js' && eslint 'src/**/*.js' --fix && stylelint 'style/**/*.css' 'src/**/*.css' 'src/**/*.scss' --fix", - "lint": "ESLINT_USE_FLAT_CONFIG=false eslint 'cypress/e2e/**/*.js' 'src/**/*.js' && stylelint 'style/**/*.css' 'src/**/*.css' 'src/**/*.scss'", + "format": "prettier --write 'cypress/e2e/**/*.js' 'src/**/*.js' && eslint 'src/**/*.js' --fix && stylelint 'style/**/*.css' 'src/**/*.css' 'src/**/*.scss' --fix", + "lint": "eslint 'cypress/e2e/**/*.js' 'src/**/*.js' && stylelint 'style/**/*.css' 'src/**/*.css' 'src/**/*.scss'", "prepare": "is-ci || husky", "publish:beta": "yarn release -- --prerelease beta --skip.changelog && yarn build && git push origin HEAD && git push --tags && yarn publish --tag beta", "publish:beta:dryrun": "yarn release -- --prerelease beta --dry-run --skip.changelog", diff --git a/src/control/buffer.js b/src/control/buffer.js index 53dfde47..03d36194 100644 --- a/src/control/buffer.js +++ b/src/control/buffer.js @@ -1,17 +1,18 @@ -import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser'; -import { BufferOp } from 'jsts/org/locationtech/jts/operation/buffer'; -import LinearRing from 'ol/geom/LinearRing'; +import OL3Parser from "jsts/org/locationtech/jts/io/OL3Parser"; +import { BufferOp } from "jsts/org/locationtech/jts/operation/buffer"; import { - Point, LineString, - Polygon, - MultiPoint, MultiLineString, + MultiPoint, MultiPolygon, -} from 'ol/geom'; -import Select from 'ol/interaction/Select'; -import Control from './control'; -import bufferSVG from '../../img/buffer.svg'; + Point, + Polygon, +} from "ol/geom"; +import LinearRing from "ol/geom/LinearRing"; +import Select from "ol/interaction/Select"; + +import bufferSVG from "../../img/buffer.svg"; +import Control from "./control"; /** * Control for creating buffers. @@ -30,10 +31,10 @@ class BufferControl extends Control { */ constructor(options) { super({ - title: 'Buffer geometry', - className: 'ole-control-buffer', - image: bufferSVG, buffer: 50, + className: "ole-control-buffer", + image: bufferSVG, + title: "Buffer geometry", ...options, }); @@ -42,10 +43,10 @@ class BufferControl extends Control { * @private */ this.selectInteraction = new Select({ - layers: this.layerFilter, hitTolerance: options.hitTolerance === undefined ? 10 : options.hitTolerance, - multi: typeof options.multi === 'undefined' ? true : options.multi, + layers: this.layerFilter, + multi: typeof options.multi === "undefined" ? true : options.multi, style: options.style, }); } @@ -53,15 +54,22 @@ class BufferControl extends Control { /** * @inheritdoc */ - getDialogTemplate() { - return ` - - - `; + activate() { + this.map?.addInteraction(this.selectInteraction); + super.activate(); + + document.getElementById("buffer-width")?.addEventListener("change", (e) => { + this.setProperties({ buffer: e.target.value }); + }); + + document.getElementById("buffer-btn")?.addEventListener("click", () => { + const input = document.getElementById("buffer-width"); + const width = parseInt(input.value, 10); + + if (width) { + this.buffer(width); + } + }); } /** @@ -92,30 +100,23 @@ class BufferControl extends Control { /** * @inheritdoc */ - activate() { - this.map?.addInteraction(this.selectInteraction); - super.activate(); - - document.getElementById('buffer-width')?.addEventListener('change', (e) => { - this.setProperties({ buffer: e.target.value }); - }); - - document.getElementById('buffer-btn')?.addEventListener('click', () => { - const input = document.getElementById('buffer-width'); - const width = parseInt(input.value, 10); - - if (width) { - this.buffer(width); - } - }); + deactivate() { + this.map?.removeInteraction(this.selectInteraction); + super.deactivate(); } /** * @inheritdoc */ - deactivate() { - this.map?.removeInteraction(this.selectInteraction); - super.deactivate(); + getDialogTemplate() { + return ` + + + `; } } diff --git a/src/control/cad.js b/src/control/cad.js index 0f783a7b..ed4d0ab8 100644 --- a/src/control/cad.js +++ b/src/control/cad.js @@ -1,29 +1,30 @@ -import { Style, Stroke } from 'ol/style'; -import { Point, LineString, Polygon, MultiPoint, Circle } from 'ol/geom'; -import Feature from 'ol/Feature'; -import Vector from 'ol/layer/Vector'; -import VectorSource from 'ol/source/Vector'; -import { Pointer, Snap } from 'ol/interaction'; -import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay'; -import { getUid } from 'ol/util'; -import Control from './control'; -import cadSVG from '../../img/cad.svg'; -import { SnapEvent, SnapEventType } from '../event'; +import { OverlayOp } from "jsts/org/locationtech/jts/operation/overlay"; +import Feature from "ol/Feature"; +import { Circle, LineString, MultiPoint, Point, Polygon } from "ol/geom"; +import { Pointer, Snap } from "ol/interaction"; +import Vector from "ol/layer/Vector"; +import VectorSource from "ol/source/Vector"; +import { Stroke, Style } from "ol/style"; +import { getUid } from "ol/util"; + +import cadSVG from "../../img/cad.svg"; +import { SnapEvent, SnapEventType } from "../event"; import { - parser, - getProjectedPoint, + CUSTOM_LINE_KEY, + defaultSnapStyles, getEquationOfLine, - getShiftedMultiPoint, getIntersectedLinesAndPoint, + getProjectedPoint, + getShiftedMultiPoint, isSameLines, - defaultSnapStyles, - VH_LINE_KEY, - SNAP_POINT_KEY, - SNAP_FEATURE_TYPE_PROPERTY, - SEGMENT_LINE_KEY, ORTHO_LINE_KEY, - CUSTOM_LINE_KEY, -} from '../helper'; + parser, + SEGMENT_LINE_KEY, + SNAP_FEATURE_TYPE_PROPERTY, + SNAP_POINT_KEY, + VH_LINE_KEY, +} from "../helper"; +import Control from "./control"; /** * Control with snapping functionality for geometry alignment. @@ -43,9 +44,11 @@ class CadControl extends Control { * @param {Number} [options.snapTolerance] Snap tolerance in pixel * for snap lines. Default is 10. * @param {Boolean} [options.showSnapLines] Whether to show - * snap lines (default is true). + * snap lines. Default is true. * @param {Boolean} [options.showSnapPoints] Whether to show * snap points around the closest feature. + * @param {Boolean} [options.showSnapPointsOnlyOnPoints] Whether to show + * snap points only on points or not. Default is false. * @param {Boolean} [options.showOrthoLines] Whether to show * snap lines that arae perpendicular to segment (default is true). * @param {Boolean} [options.showSegmentLines] Whether to show @@ -65,16 +68,17 @@ class CadControl extends Control { */ constructor(options = {}) { super({ - title: 'CAD control', - className: 'ole-control-cad', + className: "ole-control-cad", image: cadSVG, - showSnapPoints: true, - showSnapLines: false, showOrthoLines: true, showSegmentLines: true, + showSnapLines: false, + showSnapPoints: true, + showSnapPointsOnlyOnPoints: false, showVerticalAndHorizontalLines: true, - snapPointDist: 10, - snapLinesOrder: ['ortho', 'segment', 'vh'], + snapLinesOrder: ["ortho", "segment", "vh"], + snapPointDist: 30, + title: "CAD control", ...options, }); @@ -111,9 +115,9 @@ class CadControl extends Control { style: options.linesStyle || [ new Style({ stroke: new Stroke({ - width: 1, + color: "#FF530D", lineDash: [5, 10], - color: '#FF530D', + width: 1, }), }), ], @@ -147,14 +151,20 @@ class CadControl extends Control { * @type {Function} * @private */ - this.filter = options.filter || (() => true); + this.filter = + options.filter || + (() => { + return true; + }); /** * Filter the features spatially. */ this.extentFilter = options.extentFilter || - (() => [-Infinity, -Infinity, Infinity, Infinity]); + (() => { + return [-Infinity, -Infinity, Infinity, Infinity]; + }); /** * Filter the generated line list @@ -174,168 +184,410 @@ class CadControl extends Control { this.standalone = false; this.handleInteractionAdd = this.handleInteractionAdd.bind(this); + + this.on("propertychange", () => { + this.updateDialog(); + }); } /** * @inheritdoc */ - getDialogTemplate() { - const distLabel = this.properties.useMapUnits ? 'map units' : 'px'; + activate(silent) { + super.activate(silent); + this.snapLayer.setMap(this.map); + this.linesLayer.setMap(this.map); + this.map?.addInteraction(this.pointerInteraction); + this.map?.addInteraction(this.snapInteraction); - return ` -
- - -
-
- - - -
- `; - } + document.getElementById("aux-cb")?.addEventListener("change", (evt) => { + this.setProperties({ + showSnapLines: evt.target.checked, + showSnapPoints: !evt.target.checked, + }); + }); - handleInteractionAdd(evt) { - const pos = evt.target.getArray().indexOf(this.snapInteraction); + document.getElementById("dist-cb")?.addEventListener("change", (evt) => { + this.setProperties({ + showSnapLines: !evt.target.checked, + showSnapPoints: evt.target.checked, + }); + }); - if ( - this.snapInteraction.getActive() && - pos > -1 && - pos !== evt.target.getLength() - 1 - ) { - this.deactivate(true); - this.activate(true); - } + document.getElementById("width-input")?.addEventListener("keyup", (evt) => { + const snapPointDist = parseFloat(evt.target.value); + if (!Number.isNaN(snapPointDist)) { + this.setProperties({ snapPointDist }); + } + }); } /** * @inheritdoc */ - setMap(map) { - if (this.map) { - this.map.getInteractions().un('add', this.handleInteractionAdd); - } - - super.setMap(map); - - // Ensure that the snap interaction is at the last position - // as it must be the first to handle the pointermove event. - if (this.map) { - this.map.getInteractions().on('add', this.handleInteractionAdd); - } + deactivate(silent) { + super.deactivate(silent); + this.snapLayer.setMap(null); + this.linesLayer.setMap(null); + this.map?.removeInteraction(this.pointerInteraction); + this.map?.removeInteraction(this.snapInteraction); } /** - * Handle move event. + * Draws snap lines by building the extent for + * a pair of features. * @private - * @param {ol.MapBrowserEvent} evt Move event. + * @param {ol.Coordinate} coordinate Mouse pointer coordinate. + * @param {ol.Pixel} coordinate Mouse pointer pixel coordinate. + * @param {Array.} features List of features. */ - onMove(evt) { - const features = this.getClosestFeatures( - evt.coordinate, - this.nbClosestFeatures, - ); + drawSnapLines(coordinate, pixel, features) { + // First get all snap points: neighbouring feature vertices and extent corners + const snapCoordsBefore = []; // store the direct before point in the coordinate array + const snapCoords = []; + const snapCoordsAfter = []; // store the direct next point in the coordinate array - this.linesLayer.getSource().clear(); - this.snapLayer.getSource().clear(); + for (let i = 0; i < features.length; i += 1) { + const geom = features[i].getGeometry(); + let featureCoord = geom.getCoordinates(); - this.pointerInteraction.dispatchEvent( - new SnapEvent(SnapEventType.SNAP, features.length ? features : null, evt), - ); + if (!featureCoord && geom instanceof Circle) { + featureCoord = geom.getCenter(); + } - if (this.properties.showSnapLines) { - this.drawSnapLines(evt.coordinate, features); - } + // Polygons initially return a geometry with an empty coordinate array, so we need to catch it + if (featureCoord?.length) { + if (geom instanceof Point || geom instanceof Circle) { + snapCoordsBefore.push(); + snapCoords.push(featureCoord); + snapCoordsAfter.push(); + } else { + // Add feature vertices + if (geom instanceof LineString) { + for (let j = 0; j < featureCoord.length; j += 1) { + snapCoordsBefore.push(featureCoord[j - 1]); + snapCoords.push(featureCoord[j]); + snapCoordsAfter.push(featureCoord[j + 1]); + } + } else if (geom instanceof Polygon) { + for (let j = 0; j < featureCoord[0].length; j += 1) { + snapCoordsBefore.push(featureCoord[0][j - 1]); + snapCoords.push(featureCoord[0][j]); + snapCoordsAfter.push(featureCoord[0][j + 1]); + } + } - if (this.properties.showSnapPoints && features.length) { - this.drawSnapPoints(evt.coordinate, features[0]); + // Add extent vertices + // const coords = this.getRotatedExtent(geom, coordinate); + // for (let j = 0; j < coords.length; j += 1) { + // snapCoordsBefore.push(); + // snapCoords.push(coords[j]); + // snapCoordsNext.push(); + // } + } + } } - } - /** - * Returns a list of the {num} closest features - * to a given coordinate. - * @private - * @param {ol.Coordinate} coordinate Coordinate. - * @param {Number} nbFeatures Number of features to search. - * @returns {Array.} List of closest features. - */ - getClosestFeatures(coordinate, nbFeatures = 1) { - const editFeature = this.editor.getEditFeature(); - const drawFeature = this.editor.getDrawFeature(); - const currentFeatures = [editFeature, drawFeature].filter((f) => !!f); + const { + showOrthoLines, + showSegmentLines, + showVerticalAndHorizontalLines, + snapLinesOrder, + } = this.properties; - const cacheDist = {}; - const dist = (f) => { - const uid = getUid(f); - if (!cacheDist[uid]) { - const cCoord = f.getGeometry().getClosestPoint(coordinate); - const dx = cCoord[0] - coordinate[0]; - const dy = cCoord[1] - coordinate[1]; - cacheDist[uid] = dx * dx + dy * dy; - } - return cacheDist[uid]; + let lines = []; + const helpLinesOrdered = []; + const helpLines = { + [CUSTOM_LINE_KEY]: [], + [ORTHO_LINE_KEY]: [], + [SEGMENT_LINE_KEY]: [], + [VH_LINE_KEY]: [], }; - const sortByDistance = (a, b) => dist(a) - dist(b); - let features = this.source - .getFeaturesInExtent(this.extentFilter()) - .filter( - (feature) => this.filter(feature) && !currentFeatures.includes(feature), - ) - .sort(sortByDistance) - .slice(0, nbFeatures); + if (showOrthoLines) { + helpLines[ORTHO_LINE_KEY] = + this.getOrthoLines(coordinate, pixel, snapCoords, snapCoordsBefore) || + []; + } - // When using showSnapPoints, return all features except edit/draw features - if (this.properties.showSnapPoints) { - return features; + if (showSegmentLines) { + helpLines[SEGMENT_LINE_KEY] = + this.getSegmentLines(coordinate, pixel, snapCoords, snapCoordsBefore) || + []; } - // When using showSnapLines, return all features but edit/draw features are - // cloned to remove the node at the mouse position. - currentFeatures.filter(this.filter).forEach((feature) => { - const geom = feature.getGeometry(); + if (showVerticalAndHorizontalLines) { + helpLines[VH_LINE_KEY] = + this.getVerticalAndHorizontalLines(coordinate, pixel, snapCoords) || []; + } - if (!(geom instanceof Circle) && !(geom instanceof Point)) { - const snapGeom = getShiftedMultiPoint(geom, coordinate); - const isPolygon = geom instanceof Polygon; - const snapFeature = feature.clone(); - snapFeature - .getGeometry() - .setCoordinates( - isPolygon ? [snapGeom.getCoordinates()] : snapGeom.getCoordinates(), - ); - features = [snapFeature, ...features]; - } + // Add custom lines + if (this.drawCustomSnapLines) { + helpLines[CUSTOM_LINE_KEY] = + this.drawCustomSnapLines( + coordinate, + snapCoords, + snapCoordsBefore, + snapCoordsAfter, + ) || []; + } + + // Add help lines in a defined order. + snapLinesOrder.forEach((lineType) => { + helpLinesOrdered.push(...(helpLines[lineType] || [])); }); - return features; - } + // Remove duplicated lines, comparing their equation using pixels. + helpLinesOrdered.forEach((lineA) => { + if ( + !lines.length || + !lines.find((lineB) => { + return isSameLines(lineA, lineB, this.map); + }) + ) { + lines.push(lineA); + } + }); - /** - * Returns an extent array, considers the map rotation. - * @private - * @param {ol.Geometry} geometry An OL geometry. - * @returns {Array.} extent array. - */ - getRotatedExtent(geometry, coordinate) { - const coordinates = - geometry instanceof Polygon - ? geometry.getCoordinates()[0] - : geometry.getCoordinates(); + if (this.lineFilter) { + lines = this.lineFilter(lines, coordinate); + } - if (!coordinates.length) { + // We snap on intersections of lines (distance < this.snapTolerance) or on all the help lines. + const intersectFeatures = getIntersectedLinesAndPoint( + coordinate, + lines, + this.map, + this.snapTolerance, + ); + + if (intersectFeatures?.length) { + intersectFeatures.forEach((feature) => { + if (feature.getGeometry().getType() === "Point") { + this.snapLayer.getSource().addFeature(feature); + } else { + this.linesLayer.getSource().addFeature(feature); + } + }); + } else { + this.snapLayer.getSource().addFeatures(lines); + } + } + + /** + * Adds snap points to the snapping layer. + * @private + * @param {ol.Coordinate} coordinate cursor coordinate. + * @param {ol.eaturee} feature Feature to draw the snap points for. + */ + drawSnapPoints(coordinate, feature) { + if ( + this.properties.showSnapPointsOnlyOnPoints && + !(feature.getGeometry() instanceof Point) + ) { + return; + } + const featCoord = feature.getGeometry().getClosestPoint(coordinate); + + const px = this.map.getPixelFromCoordinate(featCoord); + let snapCoords = []; + + if (this.properties.useMapUnits) { + snapCoords = [ + [featCoord[0] - this.properties.snapPointDist, featCoord[1]], + [featCoord[0] + this.properties.snapPointDist, featCoord[1]], + [featCoord[0], featCoord[1] - this.properties.snapPointDist], + [featCoord[0], featCoord[1] + this.properties.snapPointDist], + ]; + } else { + const snapPx = [ + [px[0] - this.properties.snapPointDist, px[1]], + [px[0] + this.properties.snapPointDist, px[1]], + [px[0], px[1] - this.properties.snapPointDist], + [px[0], px[1] + this.properties.snapPointDist], + ]; + + for (let j = 0; j < snapPx.length; j += 1) { + snapCoords.push(this.map.getCoordinateFromPixel(snapPx[j])); + } + } + + const snapGeom = new MultiPoint(snapCoords); + this.snapLayer.getSource().addFeature(new Feature(snapGeom)); + } + + /** + * Returns a list of the {num} closest features + * to a given coordinate. + * @private + * @param {ol.Coordinate} coordinate Coordinate. + * @param {Number} nbFeatures Number of features to search. + * @returns {Array.} List of closest features. + */ + getClosestFeatures(coordinate, nbFeatures = 1) { + const editFeature = this.editor.getEditFeature(); + const drawFeature = this.editor.getDrawFeature(); + const currentFeatures = [editFeature, drawFeature].filter((f) => { + return !!f; + }); + + const cacheDist = {}; + const dist = (f) => { + const uid = getUid(f); + if (!cacheDist[uid]) { + const cCoord = f.getGeometry().getClosestPoint(coordinate); + const dx = cCoord[0] - coordinate[0]; + const dy = cCoord[1] - coordinate[1]; + cacheDist[uid] = dx * dx + dy * dy; + } + return cacheDist[uid]; + }; + const sortByDistance = (a, b) => { + return dist(a) - dist(b); + }; + + let features = this.source + .getFeaturesInExtent(this.extentFilter()) + .filter((feature) => { + return this.filter(feature) && !currentFeatures.includes(feature); + }) + .sort(sortByDistance) + .slice(0, nbFeatures); + + // When using showSnapPoints, return all features except edit/draw features + if (this.properties.showSnapPoints) { + return features; + } + + // When using showSnapLines, return all features but edit/draw features are + // cloned to remove the node being modified. + currentFeatures.filter(this.filter).forEach((feature) => { + const geom = feature.getGeometry(); + + if (!(geom instanceof Circle) && !(geom instanceof Point)) { + const snapGeom = getShiftedMultiPoint( + geom, + coordinate, + editFeature, + drawFeature, + ); + const isPolygon = geom instanceof Polygon; + const snapFeature = feature.clone(); + const coordinates = snapGeom.getCoordinates(); + snapFeature + .getGeometry() + .setCoordinates(isPolygon ? [coordinates] : coordinates); + features = [snapFeature, ...features]; + } + }); + + return features; + } + + /** + * @inheritdoc + */ + getDialogTemplate() { + const distLabel = this.properties.useMapUnits ? "map units" : "px"; + + return ` +
+ + +
+
+ + + +
+ `; + } + /** + * For each segment, we calculate lines that are perpendicular. + */ + getOrthoLines(coordinate, pixel, snapCoords, snapCoordsBefore) { + const mousePx = pixel; + const doubleTol = this.snapTolerance * 2; + const [mouseX, mouseY] = mousePx; + const lines = []; + + for (let i = 0; i < snapCoords.length; i += 1) { + if (!snapCoordsBefore[i]) { + continue; + } + const snapCoordBefore = snapCoordsBefore[i]; + const snapCoord = snapCoords[i]; + const snapPxBefore = this.getRoundedPixelFromCoordinate(snapCoordBefore); + const snapPx = this.getRoundedPixelFromCoordinate(snapCoord); + + const orthoLine1 = new LineString([snapPxBefore, snapPx]); + orthoLine1.rotate((90 * Math.PI) / 180, snapPxBefore); + + const orthoLine2 = new LineString([snapPx, snapPxBefore]); + orthoLine2.rotate((90 * Math.PI) / 180, snapPx); + + [orthoLine1, orthoLine2].forEach((line) => { + const [anchorPx, last] = line.getCoordinates(); + const projMousePx = getProjectedPoint(mousePx, anchorPx, last).map( + (v) => { + return Math.round(v); + }, + ); + const [projMouseX, projMouseY] = projMousePx; + const distance = Math.sqrt( + (projMouseX - mouseX) ** 2 + (projMouseY - mouseY) ** 2, + ); + + let newPt; + if (distance <= this.snapTolerance) { + // lineFunc is undefined when it's a vertical line + const lineFunc = getEquationOfLine(anchorPx, projMousePx); + const newX = + projMouseX + (projMouseX < anchorPx[0] ? -doubleTol : doubleTol); + if (lineFunc) { + newPt = this.map.getCoordinateFromPixel([ + newX, + lineFunc ? lineFunc(newX) : projMouseY, + ]); + } + } + + if (newPt) { + const coords = [this.map.getCoordinateFromPixel(anchorPx), newPt]; + const geom = new LineString(coords); + const feature = new Feature(geom); + feature.set(SNAP_FEATURE_TYPE_PROPERTY, ORTHO_LINE_KEY); + lines.push(feature); + } + }); + } + return lines; + } + + /** + * Returns an extent array, considers the map rotation. + * @private + * @param {ol.Geometry} geometry An OL geometry. + * @returns {Array.} extent array. + */ + getRotatedExtent(geometry, coordinate) { + const coordinates = + geometry instanceof Polygon + ? geometry.getCoordinates()[0] + : geometry.getCoordinates(); + + if (!coordinates.length) { // Polygons initially return a geometry with an empty coordinate array, so we need to catch it return [coordinate]; } @@ -427,106 +679,39 @@ class CadControl extends Control { ]; } - // Calculate lines that are vertical or horizontal to a coordinate. - getVerticalAndHorizontalLines(coordinate, snapCoords) { - // Draw snaplines when cursor vertically or horizontally aligns with a snap feature. - // We draw only on vertical and one horizontal line to avoid crowded lines when polygons or lines have a lot of coordinates. - const halfTol = this.snapTolerance / 2; + getRoundedPixelFromCoordinate(coordinate) { + return this.map.getPixelFromCoordinate(coordinate).map((v) => { + return Math.round(v); + }); + } + + /** + * For each segment, we calculate lines that extends it. + */ + getSegmentLines(coordinate, pixel, snapCoords, snapCoordsBefore) { + const mousePx = pixel; const doubleTol = this.snapTolerance * 2; - const mousePx = this.map.getPixelFromCoordinate(coordinate); const [mouseX, mouseY] = mousePx; - let vLine; - let hLine; - let closerDistanceWithVLine = Infinity; - let closerDistanceWithHLine = Infinity; - for (let i = 0; i < snapCoords.length; i += 1) { - const snapCoord = snapCoords[i]; - const snapPx = this.map.getPixelFromCoordinate(snapCoords[i]); - const [snapX, snapY] = snapPx; - const drawVLine = mouseX > snapX - halfTol && mouseX < snapX + halfTol; - const drawHLine = mouseY > snapY - halfTol && mouseY < snapY + halfTol; - - const distanceWithVLine = Math.abs(mouseX - snapX); - const distanceWithHLine = Math.abs(mouseY - snapY); + const lines = []; - if ( - (drawVLine && distanceWithVLine > closerDistanceWithVLine) || - (drawHLine && distanceWithHLine > closerDistanceWithHLine) - ) { - // eslint-disable-next-line no-continue + for (let i = 0; i < snapCoords.length; i += 1) { + if (!snapCoordsBefore[i]) { continue; } + const snapCoordBefore = snapCoordsBefore[i]; + const snapCoord = snapCoords[i]; + const snapPxBefore = this.getRoundedPixelFromCoordinate(snapCoordBefore); + const snapPx = this.map.getPixelFromCoordinate(snapCoord); - let newPt; + const [snapX] = snapPx; - if (drawVLine) { - closerDistanceWithVLine = distanceWithVLine; - const newY = mouseY + (mouseY < snapY ? -doubleTol : doubleTol); - newPt = this.map.getCoordinateFromPixel([snapX, newY]); - } else if (drawHLine) { - closerDistanceWithHLine = distanceWithHLine; - const newX = mouseX + (mouseX < snapX ? -doubleTol : doubleTol); - newPt = this.map.getCoordinateFromPixel([newX, snapY]); - } - - if (newPt) { - const lineCoords = [newPt, snapCoord]; - const geom = new LineString(lineCoords); - const feature = new Feature(geom); - - feature.set(SNAP_FEATURE_TYPE_PROPERTY, VH_LINE_KEY); - - if (drawVLine) { - vLine = feature; - } - - if (drawHLine) { - hLine = feature; - } - } - } - - const lines = []; - - if (hLine) { - lines.push(hLine); - } - - if (vLine && vLine !== hLine) { - lines.push(vLine); - } - - return lines; - } - - /** - * For each segment, we calculate lines that extends it. - */ - getSegmentLines(coordinate, snapCoords, snapCoordsBefore) { - const mousePx = this.map.getPixelFromCoordinate(coordinate); - const doubleTol = this.snapTolerance * 2; - const [mouseX, mouseY] = mousePx; - const lines = []; - - for (let i = 0; i < snapCoords.length; i += 1) { - if (!snapCoordsBefore[i]) { - // eslint-disable-next-line no-continue - continue; - } - const snapCoordBefore = snapCoordsBefore[i]; - const snapCoord = snapCoords[i]; - const snapPxBefore = this.map.getPixelFromCoordinate(snapCoordBefore); - const snapPx = this.map.getPixelFromCoordinate(snapCoord); - - const [snapX] = snapPx; - - // Calculate projected point - const projMousePx = getProjectedPoint(mousePx, snapPxBefore, snapPx); - const [projMouseX, projMouseY] = projMousePx; - const distance = Math.sqrt( - (projMouseX - mouseX) ** 2 + (projMouseY - mouseY) ** 2, - ); - let newPt; + // Calculate projected point + const projMousePx = getProjectedPoint(mousePx, snapPxBefore, snapPx); + const [projMouseX, projMouseY] = projMousePx; + const distance = Math.sqrt( + (projMouseX - mouseX) ** 2 + (projMouseY - mouseY) ** 2, + ); + let newPt; if (distance <= this.snapTolerance) { // lineFunc is undefined when it's a vertical line @@ -551,279 +736,132 @@ class CadControl extends Control { return lines; } - /** - * For each segment, we calculate lines that are perpendicular. - */ - getOrthoLines(coordinate, snapCoords, snapCoordsBefore) { - const mousePx = this.map.getPixelFromCoordinate(coordinate); + // Calculate lines that are vertical or horizontal to a coordinate. + getVerticalAndHorizontalLines(coordinate, pixel, snapCoords) { + // Draw snaplines when cursor vertically or horizontally aligns with a snap feature. + // We draw only one vertical and one horizontal line to avoid crowded lines when polygons or lines have a lot of coordinates. + const halfTol = this.snapTolerance / 2; const doubleTol = this.snapTolerance * 2; + const mousePx = pixel; const [mouseX, mouseY] = mousePx; - const lines = []; - + let vLine; + let hLine; + let closerDistanceWithVLine = Infinity; + let closerDistanceWithHLine = Infinity; for (let i = 0; i < snapCoords.length; i += 1) { - if (!snapCoordsBefore[i]) { - // eslint-disable-next-line no-continue - continue; - } - const snapCoordBefore = snapCoordsBefore[i]; const snapCoord = snapCoords[i]; - const snapPxBefore = this.map.getPixelFromCoordinate(snapCoordBefore); - const snapPx = this.map.getPixelFromCoordinate(snapCoord); - - const orthoLine1 = new LineString([snapPxBefore, snapPx]); - orthoLine1.rotate((90 * Math.PI) / 180, snapPxBefore); - - const orthoLine2 = new LineString([snapPx, snapPxBefore]); - orthoLine2.rotate((90 * Math.PI) / 180, snapPx); + const snapPx = this.getRoundedPixelFromCoordinate(snapCoords[i]); + const [snapX, snapY] = snapPx; + const drawVLine = mouseX > snapX - halfTol && mouseX < snapX + halfTol; + const drawHLine = mouseY > snapY - halfTol && mouseY < snapY + halfTol; - [orthoLine1, orthoLine2].forEach((line) => { - const [anchorPx, last] = line.getCoordinates(); - const projMousePx = getProjectedPoint(mousePx, anchorPx, last); - const [projMouseX, projMouseY] = projMousePx; - const distance = Math.sqrt( - (projMouseX - mouseX) ** 2 + (projMouseY - mouseY) ** 2, - ); + const distanceWithVLine = Math.abs(mouseX - snapX); + const distanceWithHLine = Math.abs(mouseY - snapY); - let newPt; - if (distance <= this.snapTolerance) { - // lineFunc is undefined when it's a vertical line - const lineFunc = getEquationOfLine(anchorPx, projMousePx); - const newX = - projMouseX + (projMouseX < anchorPx[0] ? -doubleTol : doubleTol); - if (lineFunc) { - newPt = this.map.getCoordinateFromPixel([ - newX, - lineFunc ? lineFunc(newX) : projMouseY, - ]); - } - } + if ( + (drawVLine && distanceWithVLine > closerDistanceWithVLine) || + (drawHLine && distanceWithHLine > closerDistanceWithHLine) + ) { + continue; + } - if (newPt) { - const coords = [this.map.getCoordinateFromPixel(anchorPx), newPt]; - const geom = new LineString(coords); - const feature = new Feature(geom); - feature.set(SNAP_FEATURE_TYPE_PROPERTY, ORTHO_LINE_KEY); - lines.push(feature); - } - }); - } - return lines; - } + let newPt; - /** - * Draws snap lines by building the extent for - * a pair of features. - * @private - * @param {ol.Coordinate} coordinate Mouse pointer coordinate. - * @param {Array.} features List of features. - */ - drawSnapLines(coordinate, features) { - // First get all snap points: neighbouring feature vertices and extent corners - const snapCoordsBefore = []; // store the direct before point in the coordinate array - const snapCoords = []; - const snapCoordsAfter = []; // store the direct next point in the coordinate array + if (drawVLine) { + closerDistanceWithVLine = distanceWithVLine; + const newY = mouseY + (mouseY < snapY ? -doubleTol : doubleTol); + newPt = this.map.getCoordinateFromPixel([snapX, newY]); + } else if (drawHLine) { + closerDistanceWithHLine = distanceWithHLine; + const newX = mouseX + (mouseX < snapX ? -doubleTol : doubleTol); + newPt = this.map.getCoordinateFromPixel([newX, snapY]); + } - for (let i = 0; i < features.length; i += 1) { - const geom = features[i].getGeometry(); - let featureCoord = geom.getCoordinates(); + if (newPt) { + const lineCoords = [newPt, snapCoord]; + const geom = new LineString(lineCoords); + const feature = new Feature(geom); - if (!featureCoord && geom instanceof Circle) { - featureCoord = geom.getCenter(); - } + feature.set(SNAP_FEATURE_TYPE_PROPERTY, VH_LINE_KEY); - // Polygons initially return a geometry with an empty coordinate array, so we need to catch it - if (featureCoord?.length) { - if (geom instanceof Point || geom instanceof Circle) { - snapCoordsBefore.push(); - snapCoords.push(featureCoord); - snapCoordsAfter.push(); - } else { - // Add feature vertices - // eslint-disable-next-line no-lonely-if - if (geom instanceof LineString) { - for (let j = 0; j < featureCoord.length; j += 1) { - snapCoordsBefore.push(featureCoord[j - 1]); - snapCoords.push(featureCoord[j]); - snapCoordsAfter.push(featureCoord[j + 1]); - } - } else if (geom instanceof Polygon) { - for (let j = 0; j < featureCoord[0].length; j += 1) { - snapCoordsBefore.push(featureCoord[0][j - 1]); - snapCoords.push(featureCoord[0][j]); - snapCoordsAfter.push(featureCoord[0][j + 1]); - } - } + if (drawVLine) { + vLine = feature; + } - // Add extent vertices - // const coords = this.getRotatedExtent(geom, coordinate); - // for (let j = 0; j < coords.length; j += 1) { - // snapCoordsBefore.push(); - // snapCoords.push(coords[j]); - // snapCoordsNext.push(); - // } + if (drawHLine) { + hLine = feature; } } } - const { - showVerticalAndHorizontalLines, - showOrthoLines, - showSegmentLines, - snapLinesOrder, - } = this.properties; - - let lines = []; - const helpLinesOrdered = []; - const helpLines = { - [ORTHO_LINE_KEY]: [], - [SEGMENT_LINE_KEY]: [], - [VH_LINE_KEY]: [], - [CUSTOM_LINE_KEY]: [], - }; - - if (showOrthoLines) { - helpLines[ORTHO_LINE_KEY] = - this.getOrthoLines(coordinate, snapCoords, snapCoordsBefore) || []; - } - - if (showSegmentLines) { - helpLines[SEGMENT_LINE_KEY] = - this.getSegmentLines(coordinate, snapCoords, snapCoordsBefore) || []; - } + const lines = []; - if (showVerticalAndHorizontalLines) { - helpLines[VH_LINE_KEY] = - this.getVerticalAndHorizontalLines(coordinate, snapCoords) || []; + if (hLine) { + lines.push(hLine); } - // Add custom lines - if (this.drawCustomSnapLines) { - helpLines[CUSTOM_LINE_KEY] = - this.drawCustomSnapLines( - coordinate, - snapCoords, - snapCoordsBefore, - snapCoordsAfter, - ) || []; + if (vLine && vLine !== hLine) { + lines.push(vLine); } - // Add help lines in a defined order. - snapLinesOrder.forEach((lineType) => { - helpLinesOrdered.push(...(helpLines[lineType] || [])); - }); - - // Remove duplicated lines, comparing their equation using pixels. - helpLinesOrdered.forEach((lineA) => { - if ( - !lines.length || - !lines.find((lineB) => isSameLines(lineA, lineB, this.map)) - ) { - lines.push(lineA); - } - }); - - if (this.lineFilter) { - lines = this.lineFilter(lines, coordinate); - } + return lines; + } - // We snap on intersections of lines (distance < this.snapTolerance) or on all the help lines. - const intersectFeatures = getIntersectedLinesAndPoint( - coordinate, - lines, - this.map, - this.snapTolerance, - ); + handleInteractionAdd(evt) { + const pos = evt.target.getArray().indexOf(this.snapInteraction); - if (intersectFeatures?.length) { - intersectFeatures.forEach((feature) => { - if (feature.getGeometry().getType() === 'Point') { - this.snapLayer.getSource().addFeature(feature); - } else { - this.linesLayer.getSource().addFeature(feature); - } - }); - } else { - this.snapLayer.getSource().addFeatures(lines); + if ( + this.snapInteraction.getActive() && + pos > -1 && + pos !== evt.target.getLength() - 1 + ) { + this.deactivate(true); + this.activate(true); } } /** - * Adds snap points to the snapping layer. + * Handle move event. * @private - * @param {ol.Coordinate} coordinate cursor coordinate. - * @param {ol.eaturee} feature Feature to draw the snap points for. + * @param {ol.MapBrowserEvent} evt Move event. */ - drawSnapPoints(coordinate, feature) { - const featCoord = feature.getGeometry().getClosestPoint(coordinate); + onMove(evt) { + const features = this.getClosestFeatures( + evt.coordinate, + this.nbClosestFeatures, + ); - const px = this.map.getPixelFromCoordinate(featCoord); - let snapCoords = []; + this.linesLayer.getSource().clear(); + this.snapLayer.getSource().clear(); - if (this.properties.useMapUnits) { - snapCoords = [ - [featCoord[0] - this.properties.snapPointDist, featCoord[1]], - [featCoord[0] + this.properties.snapPointDist, featCoord[1]], - [featCoord[0], featCoord[1] - this.properties.snapPointDist], - [featCoord[0], featCoord[1] + this.properties.snapPointDist], - ]; - } else { - const snapPx = [ - [px[0] - this.properties.snapPointDist, px[1]], - [px[0] + this.properties.snapPointDist, px[1]], - [px[0], px[1] - this.properties.snapPointDist], - [px[0], px[1] + this.properties.snapPointDist], - ]; + this.pointerInteraction.dispatchEvent( + new SnapEvent(SnapEventType.SNAP, features.length ? features : null, evt), + ); - for (let j = 0; j < snapPx.length; j += 1) { - snapCoords.push(this.map.getCoordinateFromPixel(snapPx[j])); - } + if (this.properties.showSnapLines) { + this.drawSnapLines(evt.coordinate, evt.pixel, features); } - const snapGeom = new MultiPoint(snapCoords); - this.snapLayer.getSource().addFeature(new Feature(snapGeom)); + if (this.properties.showSnapPoints && features.length) { + this.drawSnapPoints(evt.coordinate, features[0]); + } } /** * @inheritdoc */ - activate(silent) { - super.activate(silent); - this.snapLayer.setMap(this.map); - this.linesLayer.setMap(this.map); - this.map?.addInteraction(this.pointerInteraction); - this.map?.addInteraction(this.snapInteraction); - - document.getElementById('aux-cb')?.addEventListener('change', (evt) => { - this.setProperties({ - showSnapLines: evt.target.checked, - showSnapPoints: !evt.target.checked, - }); - }); - - document.getElementById('dist-cb')?.addEventListener('change', (evt) => { - this.setProperties({ - showSnapPoints: evt.target.checked, - showSnapLines: !evt.target.checked, - }); - }); + setMap(map) { + if (this.map) { + this.map.getInteractions().un("add", this.handleInteractionAdd); + } - document.getElementById('width-input')?.addEventListener('keyup', (evt) => { - const snapPointDist = parseFloat(evt.target.value); - if (!Number.isNaN(snapPointDist)) { - this.setProperties({ snapPointDist }); - } - }); - } + super.setMap(map); - /** - * @inheritdoc - */ - deactivate(silent) { - super.deactivate(silent); - this.snapLayer.setMap(null); - this.linesLayer.setMap(null); - this.map?.removeInteraction(this.pointerInteraction); - this.map?.removeInteraction(this.snapInteraction); + // Ensure that the snap interaction is at the last position + // as it must be the first to handle the pointermove event. + if (this.map) { + this.map.getInteractions().on("add", this.handleInteractionAdd); + } } } diff --git a/src/control/control.js b/src/control/control.js index 80ae120d..1144880a 100644 --- a/src/control/control.js +++ b/src/control/control.js @@ -1,5 +1,5 @@ -import OLControl from 'ol/control/Control'; -import VectorSource from 'ol/source/Vector'; +import OLControl from "ol/control/Control"; +import VectorSource from "ol/source/Vector"; /** * OLE control base class. * @extends ol.control.Control @@ -24,14 +24,14 @@ class Control extends OLControl { constructor(options) { let button = null; if (options.element !== null && !options.element) { - button = document.createElement('button'); + button = document.createElement("button"); button.className = `ole-control ${options.className}`; } super({ element: options.element === null - ? document.createElement('div') // An element must be define otherwise ol complains, when we add control + ? document.createElement("div") // An element must be define otherwise ol complains, when we add control : options.element || button, }); @@ -65,13 +65,13 @@ class Control extends OLControl { this.title = options.title; if (button) { - const img = document.createElement('img'); + const img = document.createElement("img"); img.src = options.image; button.appendChild(img); button.title = this.title; - button.addEventListener('click', this.onClick.bind(this)); + button.addEventListener("click", this.onClick.bind(this)); } /** @@ -93,7 +93,9 @@ class Control extends OLControl { */ this.layerFilter = options.layerFilter || - ((layer) => !this.source || (layer && layer.getSource() === this.source)); + ((layer) => { + return !this.source || (layer && layer.getSource() === this.source); + }); /** * ole.Editor instance. @@ -109,65 +111,39 @@ class Control extends OLControl { this.standalone = true; } - /** - * Returns the control's element. - * @returns {Element} the control element. - */ - getElement() { - return this.element; - } - - /** - * Click handler for the control element. - * @private - */ - onClick() { - if (this.active) { - this.deactivate(); - } else { - this.activate(); - } - } - - /** - * Sets the map of the control. - * @protected - * @param {ol.Map} map The map object. - */ - setMap(map) { - this.map = map; - super.setMap(this.map); - } - - /** - * Introduce the control to it's editor. - * @param {ole.Editor} editor OLE Editor. - * @protected - */ - setEditor(editor) { - this.editor = editor; - } - /** * Activate the control */ activate(silent) { this.active = true; if (this.element) { - this.element.className += ' active'; + this.element.className += " active"; } if (!silent) { this.dispatchEvent({ - type: 'change:active', - target: this, detail: { control: this }, + target: this, + type: "change:active", }); } this.openDialog(); } + /** + * Closes the control dialog. + * @private + */ + closeDialog() { + if (this.dialogDiv) { + (this.dialogTarget || this.map.getTargetElement()).removeChild( + this.dialogDiv, + ); + this.dialogDiv = null; + } + } + /** * Dectivate the control * @param {boolean} [silent] Do not trigger an event. @@ -175,14 +151,14 @@ class Control extends OLControl { deactivate(silent) { this.active = false; if (this.element) { - this.element.classList.remove('active'); + this.element.classList.remove("active"); } if (!silent) { this.dispatchEvent({ - type: 'change:active', - target: this, detail: { control: this }, + target: this, + type: "change:active", }); } @@ -197,13 +173,41 @@ class Control extends OLControl { return this.active; } + /** + * Returns the control's element. + * @returns {Element} the control element. + */ + getElement() { + return this.element; + } + + /** + * Return properties. + * @returns {object} Copy of control properties. + */ + getProperties() { + return { ...this.properties }; + } + + /** + * Click handler for the control element. + * @private + */ + onClick() { + if (this.active) { + this.deactivate(); + } else { + this.activate(); + } + } + /** * Open the control's dialog (if defined). */ openDialog() { this.closeDialog(); if (this.dialogTarget !== null && this.getDialogTemplate) { - this.dialogDiv = document.createElement('div'); + this.dialogDiv = document.createElement("div"); this.dialogDiv.innerHTML = `
@@ -217,16 +221,22 @@ class Control extends OLControl { } /** - * Closes the control dialog. - * @private + * Introduce the control to it's editor. + * @param {ole.Editor} editor OLE Editor. + * @protected */ - closeDialog() { - if (this.dialogDiv) { - (this.dialogTarget || this.map.getTargetElement()).removeChild( - this.dialogDiv, - ); - this.dialogDiv = null; - } + setEditor(editor) { + this.editor = editor; + } + + /** + * Sets the map of the control. + * @protected + * @param {ol.Map} map The map object. + */ + setMap(map) { + this.map = map; + super.setMap(this.map); } /** @@ -239,19 +249,22 @@ class Control extends OLControl { if (!silent) { this.dispatchEvent({ - type: 'propertychange', + detail: { control: this, properties: this.properties }, target: this, - detail: { properties: this.properties, control: this }, + type: "propertychange", }); } + this.updateDialog(); } - /** - * Return properties. - * @returns {object} Copy of control properties. - */ - getProperties() { - return { ...this.properties }; + updateDialog() { + if (this.dialogDiv && this.getDialogTemplate) { + this.dialogDiv.innerHTML = ` +
+ ${this.getDialogTemplate()} +
+ `; + } } } diff --git a/src/control/difference.js b/src/control/difference.js index b996311c..67878fcf 100644 --- a/src/control/difference.js +++ b/src/control/difference.js @@ -1,16 +1,17 @@ -import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser'; -import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay'; -import LinearRing from 'ol/geom/LinearRing'; +import OL3Parser from "jsts/org/locationtech/jts/io/OL3Parser"; +import { OverlayOp } from "jsts/org/locationtech/jts/operation/overlay"; import { - Point, LineString, - Polygon, - MultiPoint, MultiLineString, + MultiPoint, MultiPolygon, -} from 'ol/geom'; -import TopologyControl from './topology'; -import diffSVG from '../../img/difference.svg'; + Point, + Polygon, +} from "ol/geom"; +import LinearRing from "ol/geom/LinearRing"; + +import diffSVG from "../../img/difference.svg"; +import TopologyControl from "./topology"; /** * Control for creating a difference of geometries. @@ -26,9 +27,9 @@ class Difference extends TopologyControl { */ constructor(options) { super({ - title: 'Difference', - className: 'ole-control-difference', + className: "ole-control-difference", image: diffSVG, + title: "Difference", ...options, }); } diff --git a/src/control/draw.js b/src/control/draw.js index 5243fc97..25d0354b 100644 --- a/src/control/draw.js +++ b/src/control/draw.js @@ -1,8 +1,9 @@ -import { Draw } from 'ol/interaction'; -import Control from './control'; -import drawPointSVG from '../../img/draw_point.svg'; -import drawPolygonSVG from '../../img/draw_polygon.svg'; -import drawLineSVG from '../../img/draw_line.svg'; +import { Draw } from "ol/interaction"; + +import drawLineSVG from "../../img/draw_line.svg"; +import drawPointSVG from "../../img/draw_point.svg"; +import drawPolygonSVG from "../../img/draw_polygon.svg"; +import Control from "./control"; /** * Control for drawing features. @@ -22,10 +23,10 @@ class DrawControl extends Control { let image = null; switch (options?.type) { - case 'Polygon': + case "Polygon": image = drawPolygonSVG; break; - case 'LineString': + case "LineString": image = drawLineSVG; break; default: @@ -33,9 +34,9 @@ class DrawControl extends Control { } super({ - title: `Draw ${options?.type || 'Point'}`, - className: 'ole-control-draw', + className: "ole-control-draw", image, + title: `Draw ${options?.type || "Point"}`, ...(options || {}), }); @@ -43,19 +44,19 @@ class DrawControl extends Control { * @type {ol.interaction.Draw} */ this.drawInteraction = new Draw({ - type: options?.type || 'Point', features: options?.features, source: options?.source, - style: options?.style, stopClick: true, + style: options?.style, + type: options?.type || "Point", ...(options?.drawInteractionOptions || {}), }); - this.drawInteraction.on('drawstart', (evt) => { + this.drawInteraction.on("drawstart", (evt) => { this.editor.setDrawFeature(evt.feature); }); - this.drawInteraction.on('drawend', () => { + this.drawInteraction.on("drawend", () => { this.editor.setDrawFeature(); }); } diff --git a/src/control/index.js b/src/control/index.js index 0e90bc04..748dc54d 100644 --- a/src/control/index.js +++ b/src/control/index.js @@ -1,10 +1,10 @@ -export { default as Control } from './control'; -export { default as CAD } from './cad'; -export { default as Rotate } from './rotate'; -export { default as Draw } from './draw'; -export { default as Modify } from './modify'; -export { default as Buffer } from './buffer'; -export { default as Union } from './union'; -export { default as Intersection } from './intersection'; -export { default as Difference } from './difference'; -export { default as Toolbar } from './toolbar'; +export { default as Buffer } from "./buffer"; +export { default as CAD } from "./cad"; +export { default as Control } from "./control"; +export { default as Difference } from "./difference"; +export { default as Draw } from "./draw"; +export { default as Intersection } from "./intersection"; +export { default as Modify } from "./modify"; +export { default as Rotate } from "./rotate"; +export { default as Toolbar } from "./toolbar"; +export { default as Union } from "./union"; diff --git a/src/control/intersection.js b/src/control/intersection.js index 3858f757..74608691 100644 --- a/src/control/intersection.js +++ b/src/control/intersection.js @@ -1,16 +1,17 @@ -import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser'; -import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay'; -import LinearRing from 'ol/geom/LinearRing'; +import OL3Parser from "jsts/org/locationtech/jts/io/OL3Parser"; +import { OverlayOp } from "jsts/org/locationtech/jts/operation/overlay"; import { - Point, LineString, - Polygon, - MultiPoint, MultiLineString, + MultiPoint, MultiPolygon, -} from 'ol/geom'; -import TopologyControl from './topology'; -import intersectionSVG from '../../img/intersection.svg'; + Point, + Polygon, +} from "ol/geom"; +import LinearRing from "ol/geom/LinearRing"; + +import intersectionSVG from "../../img/intersection.svg"; +import TopologyControl from "./topology"; /** * Control for intersection geometries. @@ -26,9 +27,9 @@ class Intersection extends TopologyControl { */ constructor(options) { super({ - title: 'Intersection', - className: 'ole-control-intersection', + className: "ole-control-intersection", image: intersectionSVG, + title: "Intersection", ...options, }); } diff --git a/src/control/modify.js b/src/control/modify.js index adc400ea..4d6e5e5f 100644 --- a/src/control/modify.js +++ b/src/control/modify.js @@ -1,14 +1,14 @@ -import { Modify, Interaction } from 'ol/interaction'; -import { singleClick } from 'ol/events/condition'; -// eslint-disable-next-line import/no-extraneous-dependencies -import throttle from 'lodash.throttle'; -import { unByKey } from 'ol/Observable'; -import Control from './control'; -import image from '../../img/modify_geometry2.svg'; -import SelectMove from '../interaction/selectmove'; -import SelectModify from '../interaction/selectmodify'; -import Move from '../interaction/move'; -import Delete from '../interaction/delete'; +import throttle from "lodash.throttle"; +import { singleClick } from "ol/events/condition"; +import { Interaction, Modify } from "ol/interaction"; +import { unByKey } from "ol/Observable"; + +import image from "../../img/modify_geometry2.svg"; +import Delete from "../interaction/delete"; +import Move from "../interaction/move"; +import SelectModify from "../interaction/selectmodify"; +import SelectMove from "../interaction/selectmove"; +import Control from "./control"; /** * Control for modifying geometries. @@ -31,9 +31,9 @@ class ModifyControl extends Control { */ constructor(options = {}) { super({ - title: 'Modify geometry', - className: 'ole-control-modify', + className: "ole-control-modify", image, + title: "Modify geometry", ...options, }); @@ -75,7 +75,10 @@ class ModifyControl extends Control { leading: true, }); this.cursorStyleHandler = - options?.cursorStyleHandler || ((cursorStyle) => cursorStyle); + options?.cursorStyleHandler || + ((cursorStyle) => { + return cursorStyle; + }); /* Interactions */ this.createSelectMoveInteraction(options.selectMoveOptions); @@ -87,74 +90,145 @@ class ModifyControl extends Control { } /** - * Create the interaction used to select feature to move. + * @inheritdoc + */ + activate() { + super.activate(); + this.deselectInteraction.setActive(true); + this.deleteInteraction.setActive(true); + this.selectModify.setActive(true); + // For the default behavior it's very important to add selectMove after selectModify. + // It will avoid single/dbleclick mess. + this.selectMove.setActive(true); + this.addListeners(); + } + + /** + * Add others listeners on the map than interactions. + * @param {*} evt + * @private + */ + addListeners() { + this.removeListeners(); + this.cursorListenerKeys = [ + this.map?.on("pointerdown", (evt) => { + const element = evt.map.getViewport(); + if (element?.style?.cursor === "grab") { + this.changeCursor("grabbing"); + } + }), + this.map?.on("pointermove", this.cursorHandlerThrottled), + this.map?.on("pointerup", (evt) => { + const element = evt.map.getViewport(); + if (element?.style?.cursor === "grabbing") { + this.changeCursor("grab"); + } + }), + ]; + } + + /** + * Change cursor style. + * @param {string} cursor New cursor name. + * @private + */ + changeCursor(cursor) { + if (!this.getActive()) { + return; + } + const newCursor = this.cursorStyleHandler(cursor); + const element = this.map.getViewport(); + if ( + (element.style.cursor || newCursor) && + element.style.cursor !== newCursor + ) { + if (this.previousCursor === null) { + this.previousCursor = element.style.cursor; + } + element.style.cursor = newCursor; + } + } + + /** + * Create the interaction used to delete selected features. * @param {*} options * @private */ - createSelectMoveInteraction(options = {}) { + createDeleteInteraction(options = {}) { /** - * Select interaction to move features. - * @type {ol.interaction.Select} + * @type {ol.interaction.Delete} * @private */ - this.selectMove = new SelectMove({ - filter: (feature, layer) => { - // If the feature is already selected by modify interaction ignore the selection. - if (this.isSelectedByModify(feature)) { - return false; - } - return this.selectFilter(feature, layer); - }, - hitTolerance: this.hitTolerance, - ...options, - }); + this.deleteInteraction = new Delete({ source: this.source, ...options }); - this.selectMove.getFeatures().on('add', () => { - this.selectModify.getFeatures().clear(); - this.moveInteraction.setActive(true); - this.deleteInteraction.setFeatures(this.selectMove.getFeatures()); + this.deleteInteraction.on("delete", () => { + this.changeCursor(null); }); + this.deleteInteraction.setActive(false); + } - this.selectMove.getFeatures().on('remove', () => { - // Deactive interaction when the select array is empty - if (this.selectMove.getFeatures().getLength() === 0) { - this.moveInteraction.setActive(false); - this.deleteInteraction.setFeatures(); - } + /** + * Create the interaction used to deselected features when we click on the map. + * @param {*} options + * @private + */ + createDeselectInteraction(options = {}) { + // it's important that this condition was the same as the selectModify's + // deleteCondition to avoid the selection of the feature under the node to delete. + const condition = options.condition || singleClick; + + /** + * @type {ol.interaction.Interaction} + * @private + */ + this.deselectInteraction = new Interaction({ + handleEvent: (mapBrowserEvent) => { + if (!condition(mapBrowserEvent)) { + return true; + } + const onFeature = this.getFeatureAtPixel(mapBrowserEvent.pixel); + const onVertex = this.isHoverVertexFeatureAtPixel( + mapBrowserEvent.pixel, + ); + + if (!onVertex && !onFeature) { + // Default: Clear selection on click outside features. + this.selectMove.getFeatures().clear(); + this.selectModify.getFeatures().clear(); + return false; + } + return true; + }, }); - this.selectMove.setActive(false); + this.deselectInteraction.setActive(false); } /** - * Create the interaction used to select feature to modify. + * Create the interaction used to modify vertexes of features. * @param {*} options * @private */ - createSelectModifyInteraction(options = {}) { + createModifyInteraction(options = {}) { /** - * Select interaction to modify features. - * @type {ol.interaction.Select} + * @type {ol.interaction.Modify} + * @private */ - this.selectModify = new SelectModify({ - filter: this.selectFilter, - hitTolerance: this.hitTolerance, + this.modifyInteraction = new Modify({ + deleteCondition: singleClick, + features: this.selectModify.getFeatures(), ...options, }); - this.selectModify.getFeatures().on('add', () => { - this.selectMove.getFeatures().clear(); - this.modifyInteraction.setActive(true); - this.deleteInteraction.setFeatures(this.selectModify.getFeatures()); + this.modifyInteraction.on("modifystart", (evt) => { + this.editor.setEditFeature(evt.features.item(0)); + this.isModifying = true; }); - this.selectModify.getFeatures().on('remove', () => { - // Deactive interaction when the select array is empty - if (this.selectModify.getFeatures().getLength() === 0) { - this.modifyInteraction.setActive(false); - this.deleteInteraction.setFeatures(); - } + this.modifyInteraction.on("modifyend", () => { + this.editor.setEditFeature(); + this.isModifying = false; }); - this.selectModify.setActive(false); + this.modifyInteraction.setActive(false); } /** @@ -172,12 +246,12 @@ class ModifyControl extends Control { ...options, }); - this.moveInteraction.on('movestart', (evt) => { + this.moveInteraction.on("movestart", (evt) => { this.editor.setEditFeature(evt.feature); this.isMoving = true; }); - this.moveInteraction.on('moveend', () => { + this.moveInteraction.on("moveend", () => { this.editor.setEditFeature(); this.isMoving = false; }); @@ -185,85 +259,120 @@ class ModifyControl extends Control { } /** - * Create the interaction used to modify vertexes of features. + * Create the interaction used to select feature to modify. * @param {*} options * @private */ - createModifyInteraction(options = {}) { + createSelectModifyInteraction(options = {}) { /** - * @type {ol.interaction.Modify} - * @private + * Select interaction to modify features. + * @type {ol.interaction.Select} */ - this.modifyInteraction = new Modify({ - features: this.selectModify.getFeatures(), - deleteCondition: singleClick, + this.selectModify = new SelectModify({ + filter: this.selectFilter, + hitTolerance: this.hitTolerance, ...options, }); - this.modifyInteraction.on('modifystart', (evt) => { - this.editor.setEditFeature(evt.features.item(0)); - this.isModifying = true; + this.selectModify.getFeatures().on("add", () => { + this.selectMove.getFeatures().clear(); + this.modifyInteraction.setActive(true); + this.deleteInteraction.setFeatures(this.selectModify.getFeatures()); }); - this.modifyInteraction.on('modifyend', () => { - this.editor.setEditFeature(); - this.isModifying = false; + this.selectModify.getFeatures().on("remove", () => { + // Deactive interaction when the select array is empty + if (this.selectModify.getFeatures().getLength() === 0) { + this.modifyInteraction.setActive(false); + this.deleteInteraction.setFeatures(); + } }); - this.modifyInteraction.setActive(false); + this.selectModify.setActive(false); } /** - * Create the interaction used to delete selected features. + * Create the interaction used to select feature to move. * @param {*} options * @private */ - createDeleteInteraction(options = {}) { + createSelectMoveInteraction(options = {}) { /** - * @type {ol.interaction.Delete} + * Select interaction to move features. + * @type {ol.interaction.Select} * @private */ - this.deleteInteraction = new Delete({ source: this.source, ...options }); + this.selectMove = new SelectMove({ + filter: (feature, layer) => { + // If the feature is already selected by modify interaction ignore the selection. + if (this.isSelectedByModify(feature)) { + return false; + } + return this.selectFilter(feature, layer); + }, + hitTolerance: this.hitTolerance, + ...options, + }); - this.deleteInteraction.on('delete', () => { - this.changeCursor(null); + this.selectMove.getFeatures().on("add", () => { + this.selectModify.getFeatures().clear(); + this.moveInteraction.setActive(true); + this.deleteInteraction.setFeatures(this.selectMove.getFeatures()); }); - this.deleteInteraction.setActive(false); + + this.selectMove.getFeatures().on("remove", () => { + // Deactive interaction when the select array is empty + if (this.selectMove.getFeatures().getLength() === 0) { + this.moveInteraction.setActive(false); + this.deleteInteraction.setFeatures(); + } + }); + this.selectMove.setActive(false); } /** - * Create the interaction used to deselected features when we click on the map. - * @param {*} options + * Handle the move event of the move interaction. + * @param {ol.MapBrowserEvent} evt Event. * @private */ - createDeselectInteraction(options = {}) { - // it's important that this condition was the same as the selectModify's - // deleteCondition to avoid the selection of the feature under the node to delete. - const condition = options.condition || singleClick; + cursorHandler(evt) { + if (evt.dragging || this.isMoving || this.isModifying) { + this.changeCursor("grabbing"); + return; + } - /** - * @type {ol.interaction.Interaction} - * @private - */ - this.deselectInteraction = new Interaction({ - handleEvent: (mapBrowserEvent) => { - if (!condition(mapBrowserEvent)) { - return true; - } - const onFeature = this.getFeatureAtPixel(mapBrowserEvent.pixel); - const onVertex = this.isHoverVertexFeatureAtPixel( - mapBrowserEvent.pixel, - ); + const feature = this.getFeatureAtPixel(evt.pixel); + if (!feature) { + this.changeCursor(this.previousCursor); + this.previousCursor = null; + return; + } - if (!onVertex && !onFeature) { - // Default: Clear selection on click outside features. - this.selectMove.getFeatures().clear(); - this.selectModify.getFeatures().clear(); - return false; - } - return true; - }, - }); + if (this.isSelectedByMove(feature)) { + this.changeCursor("grab"); + } else if (this.isSelectedByModify(feature)) { + if (this.isHoverVertexFeatureAtPixel(evt.pixel)) { + this.changeCursor("grab"); + } else { + this.changeCursor(this.previousCursor); + } + } else { + // Feature available for selection. + this.changeCursor("pointer"); + } + } + + /** + * @inheritdoc + */ + deactivate(silent) { + this.removeListeners(); + this.selectMove.getFeatures().clear(); + this.selectModify.getFeatures().clear(); this.deselectInteraction.setActive(false); + this.deleteInteraction.setActive(false); + this.selectModify.setActive(false); + this.selectMove.setActive(false); + super.deactivate(silent); } /** @@ -309,66 +418,21 @@ class ModifyControl extends Control { return isHoverVertex; } - isSelectedByMove(feature) { - return this.selectMove.getFeatures().getArray().indexOf(feature) !== -1; - } - isSelectedByModify(feature) { return this.selectModify.getFeatures().getArray().indexOf(feature) !== -1; } - /** - * Handle the move event of the move interaction. - * @param {ol.MapBrowserEvent} evt Event. - * @private - */ - cursorHandler(evt) { - if (evt.dragging || this.isMoving || this.isModifying) { - this.changeCursor('grabbing'); - return; - } - - const feature = this.getFeatureAtPixel(evt.pixel); - if (!feature) { - this.changeCursor(this.previousCursor); - this.previousCursor = null; - return; - } - - if (this.isSelectedByMove(feature)) { - this.changeCursor('grab'); - } else if (this.isSelectedByModify(feature)) { - if (this.isHoverVertexFeatureAtPixel(evt.pixel)) { - this.changeCursor('grab'); - } else { - this.changeCursor(this.previousCursor); - } - } else { - // Feature available for selection. - this.changeCursor('pointer'); - } + isSelectedByMove(feature) { + return this.selectMove.getFeatures().getArray().indexOf(feature) !== -1; } /** - * Change cursor style. - * @param {string} cursor New cursor name. + * Remove others listeners on the map than interactions. + * @param {*} evt * @private */ - changeCursor(cursor) { - if (!this.getActive()) { - return; - } - const newCursor = this.cursorStyleHandler(cursor); - const element = this.map.getViewport(); - if ( - (element.style.cursor || newCursor) && - element.style.cursor !== newCursor - ) { - if (this.previousCursor === null) { - this.previousCursor = element.style.cursor; - } - element.style.cursor = newCursor; - } + removeListeners() { + unByKey(this.cursorListenerKeys); } setMap(map) { @@ -394,67 +458,6 @@ class ModifyControl extends Control { this.map?.addInteraction(this.moveInteraction); this.map?.addInteraction(this.modifyInteraction); } - - /** - * Add others listeners on the map than interactions. - * @param {*} evt - * @private - */ - addListeners() { - this.removeListeners(); - this.cursorListenerKeys = [ - this.map?.on('pointerdown', (evt) => { - const element = evt.map.getViewport(); - if (element?.style?.cursor === 'grab') { - this.changeCursor('grabbing'); - } - }), - this.map?.on('pointermove', this.cursorHandlerThrottled), - this.map?.on('pointerup', (evt) => { - const element = evt.map.getViewport(); - if (element?.style?.cursor === 'grabbing') { - this.changeCursor('grab'); - } - }), - ]; - } - - /** - * Remove others listeners on the map than interactions. - * @param {*} evt - * @private - */ - removeListeners() { - unByKey(this.cursorListenerKeys); - } - - /** - * @inheritdoc - */ - activate() { - super.activate(); - this.deselectInteraction.setActive(true); - this.deleteInteraction.setActive(true); - this.selectModify.setActive(true); - // For the default behavior it's very important to add selectMove after selectModify. - // It will avoid single/dbleclick mess. - this.selectMove.setActive(true); - this.addListeners(); - } - - /** - * @inheritdoc - */ - deactivate(silent) { - this.removeListeners(); - this.selectMove.getFeatures().clear(); - this.selectModify.getFeatures().clear(); - this.deselectInteraction.setActive(false); - this.deleteInteraction.setActive(false); - this.selectModify.setActive(false); - this.selectMove.setActive(false); - super.deactivate(silent); - } } export default ModifyControl; diff --git a/src/control/rotate.js b/src/control/rotate.js index edd92812..3ee0b7a9 100644 --- a/src/control/rotate.js +++ b/src/control/rotate.js @@ -1,11 +1,12 @@ -import { Style, Icon } from 'ol/style'; -import Point from 'ol/geom/Point'; -import Vector from 'ol/layer/Vector'; -import VectorSource from 'ol/source/Vector'; -import Pointer from 'ol/interaction/Pointer'; -import Control from './control'; -import rotateSVG from '../../img/rotate.svg'; -import rotateMapSVG from '../../img/rotate_map.svg'; +import Point from "ol/geom/Point"; +import Pointer from "ol/interaction/Pointer"; +import Vector from "ol/layer/Vector"; +import VectorSource from "ol/source/Vector"; +import { Icon, Style } from "ol/style"; + +import rotateMapSVG from "../../img/rotate_map.svg"; +import rotateSVG from "../../img/rotate.svg"; +import Control from "./control"; /** * Tool with for rotating geometries. @@ -22,9 +23,9 @@ class RotateControl extends Control { */ constructor(options) { super({ - title: 'Rotate', - className: 'icon-rotate', + className: "icon-rotate", image: rotateSVG, + title: "Rotate", ...options, }); @@ -42,7 +43,7 @@ class RotateControl extends Control { * @type {string} * @private */ - this.rotateAttribute = options.rotateAttribute || 'ole_rotation'; + this.rotateAttribute = options.rotateAttribute || "ole_rotation"; /** * Layer for rotation feature. @@ -68,6 +69,25 @@ class RotateControl extends Control { }); } + /** + * @inheritdoc + */ + activate() { + this.map?.addInteraction(this.pointerInteraction); + this.rotateLayer.setMap(this.map); + super.activate(); + } + + /** + * @inheritdoc + */ + deactivate(silent) { + this.rotateLayer.getSource().clear(); + this.rotateLayer.setMap(null); + this.map?.removeInteraction(this.pointerInteraction); + super.deactivate(silent); + } + /** * Handle a pointer down event. * @param {ol.MapBrowserEvent} event Down event @@ -147,25 +167,6 @@ class RotateControl extends Control { } } } - - /** - * @inheritdoc - */ - activate() { - this.map?.addInteraction(this.pointerInteraction); - this.rotateLayer.setMap(this.map); - super.activate(); - } - - /** - * @inheritdoc - */ - deactivate(silent) { - this.rotateLayer.getSource().clear(); - this.rotateLayer.setMap(null); - this.map?.removeInteraction(this.pointerInteraction); - super.deactivate(silent); - } } export default RotateControl; diff --git a/src/control/toolbar.js b/src/control/toolbar.js index f3a15bc1..f261278c 100644 --- a/src/control/toolbar.js +++ b/src/control/toolbar.js @@ -1,4 +1,4 @@ -import Control from 'ol/control/Control'; +import Control from "ol/control/Control"; /** * The editor's toolbar. @@ -14,8 +14,8 @@ class Toolbar extends Control { * the control to be rendered outside of the map's viewport. */ constructor(map, controls, target) { - const element = document.createElement('div'); - element.setAttribute('id', 'ole-toolbar'); + const element = document.createElement("div"); + element.setAttribute("id", "ole-toolbar"); super({ element: target || element, @@ -38,31 +38,31 @@ class Toolbar extends Control { } this.load(); - this.controls.on('change:length', this.load.bind(this)); + this.controls.on("change:length", this.load.bind(this)); } /** - * Load the toolbar. + * Destroy the toolbar. * @private */ - load() { + destroy() { for (let i = 0; i < this.controls.getLength(); i += 1) { const btn = this.controls.item(i).getElement(); if (this.element && btn) { - this.element.appendChild(btn); + this.element.removeChild(btn); } } } /** - * Destroy the toolbar. + * Load the toolbar. * @private */ - destroy() { + load() { for (let i = 0; i < this.controls.getLength(); i += 1) { const btn = this.controls.item(i).getElement(); if (this.element && btn) { - this.element.removeChild(btn); + this.element.appendChild(btn); } } } diff --git a/src/control/topology.js b/src/control/topology.js index dc2056cb..17a55567 100644 --- a/src/control/topology.js +++ b/src/control/topology.js @@ -1,6 +1,7 @@ -import Select from 'ol/interaction/Select'; -import Control from './control'; -import delSVG from '../../img/buffer.svg'; +import Select from "ol/interaction/Select"; + +import delSVG from "../../img/buffer.svg"; +import Control from "./control"; /** * Control for deleting geometries. @@ -17,9 +18,9 @@ class TopologyControl extends Control { */ constructor(options) { super({ - title: 'TopoloyOp', - className: 'ole-control-topology', + className: "ole-control-topology", image: delSVG, + title: "TopoloyOp", ...options, }); @@ -28,35 +29,28 @@ class TopologyControl extends Control { * @private */ this.selectInteraction = new Select({ - toggleCondition: () => true, - layers: this.layerFilter, hitTolerance: options.hitTolerance === undefined ? 10 : options.hitTolerance, + layers: this.layerFilter, multi: true, style: options.style, + toggleCondition: () => { + return true; + }, }); - this.selectInteraction.on('select', () => { + this.selectInteraction.on("select", () => { const feats = this.selectInteraction.getFeatures(); try { this.applyTopologyOperation(feats.getArray()); - } catch (ex) { - // eslint-disable-next-line no-console - console.error('Unable to process features.'); + } catch (error) { + console.error("Unable to process features.", error); feats.clear(); } }); } - /** - * Apply a topology operation for given features. - * @param {Array.} features Features. - */ - applyTopologyOperation(features) { - this.topologyFeatures = features; - } - /** * @inheritdoc */ @@ -66,6 +60,14 @@ class TopologyControl extends Control { super.activate(); } + /** + * Apply a topology operation for given features. + * @param {Array.} features Features. + */ + applyTopologyOperation(features) { + this.topologyFeatures = features; + } + /** * @inheritdoc */ diff --git a/src/control/union.js b/src/control/union.js index 9a3663f8..4073f367 100644 --- a/src/control/union.js +++ b/src/control/union.js @@ -1,16 +1,17 @@ -import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser'; -import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay'; -import LinearRing from 'ol/geom/LinearRing'; +import OL3Parser from "jsts/org/locationtech/jts/io/OL3Parser"; +import { OverlayOp } from "jsts/org/locationtech/jts/operation/overlay"; import { - Point, LineString, - Polygon, - MultiPoint, MultiLineString, + MultiPoint, MultiPolygon, -} from 'ol/geom'; -import TopologyControl from './topology'; -import unionSVG from '../../img/union.svg'; + Point, + Polygon, +} from "ol/geom"; +import LinearRing from "ol/geom/LinearRing"; + +import unionSVG from "../../img/union.svg"; +import TopologyControl from "./topology"; /** * Control for creating a union of geometries. @@ -26,9 +27,9 @@ class Union extends TopologyControl { */ constructor(options) { super({ - title: 'Union', - className: 'ole-control-union', + className: "ole-control-union", image: unionSVG, + title: "Union", ...options, }); } diff --git a/src/editor.js b/src/editor.js index a77b8d4a..a6516f6e 100644 --- a/src/editor.js +++ b/src/editor.js @@ -1,6 +1,7 @@ -import Collection from 'ol/Collection'; -import BaseObject from 'ol/Object'; -import Toolbar from './control/toolbar'; +import Collection from "ol/Collection"; +import BaseObject from "ol/Object"; + +import Toolbar from "./control/toolbar"; /** * Core component of OLE. @@ -54,7 +55,7 @@ class Editor extends BaseObject { */ this.editFeature = null; - if (typeof this.options.showToolbar === 'undefined') { + if (typeof this.options.showToolbar === "undefined") { this.options.showToolbar = true; } @@ -65,6 +66,35 @@ class Editor extends BaseObject { this.activeStateChange = this.activeStateChange.bind(this); } + /** + * Controls use this function for triggering activity state changes. + * @param {ol.control.Control} control Control. + * @private + */ + activeStateChange(evt) { + const ctrl = evt.detail.control; + // Deactivate other controls that are not standalone + if (ctrl.getActive() && ctrl.standalone) { + for (let i = 0; i < this.controls.getLength(); i += 1) { + const otherCtrl = this.controls.item(i); + if ( + otherCtrl !== ctrl && + otherCtrl.getActive() && + otherCtrl.standalone + ) { + otherCtrl.deactivate(); + this.activeControls.remove(otherCtrl); + } + } + } + + if (ctrl.getActive()) { + this.activeControls.push(ctrl); + } else { + this.activeControls.remove(ctrl); + } + } + /** * Adds a new control to the editor. * @param {ole.Control} control The control. @@ -72,32 +102,10 @@ class Editor extends BaseObject { addControl(control) { control.setMap(this.map); control.setEditor(this); - control.addEventListener('change:active', this.activeStateChange); + control.addEventListener("change:active", this.activeStateChange); this.controls.push(control); } - /** - * Remove a control from the editor - * @param {ole.Control} control The control. - */ - removeControl(control) { - control.deactivate(); - this.controls.remove(control); - control.removeEventListener('change:active', this.activeStateChange); - control.setEditor(); - control.setMap(); - } - - /** - * Adds a service to the editor. - */ - addService(service) { - service.setMap(this.map); - service.setEditor(this); - service.activate(); - this.services.push(service); - } - /** * Adds a collection of controls to the editor. * @param {ol.Collection} controls Collection of controls. @@ -112,45 +120,37 @@ class Editor extends BaseObject { } /** - * Removes the editor from the map. + * Adds a service to the editor. */ - remove() { - const controls = [...this.controls.getArray()]; - controls.forEach((control) => { - this.removeControl(control); - }); - if (this.toolbar) { - this.toolbar.destroy(); - } + addService(service) { + service.setMap(this.map); + service.setEditor(this); + service.activate(); + this.services.push(service); } /** - * Returns a list of ctive controls. + * Returns a list of active controls. * @returns {ol.Collection.} Active controls. */ - getControls() { - return this.controls; + getActiveControls() { + return this.activeControls; } /** - * Returns a list of active controls. + * Returns a list of ctive controls. * @returns {ol.Collection.} Active controls. */ - getActiveControls() { - return this.activeControls; + getControls() { + return this.controls; } /** - * Sets an instance of the feature that is edited. - * Some controls need information about the feature - * that is currently edited (e.g. for not snapping on them). - * @param {ol.Feature|null} feature The editfeature (or null if none) - * @protected + * Returns the feature that is currently being drawn. + * @returns {ol.Feature|null} The drawFeature. */ - setEditFeature(feature) { - if (feature !== this.editFeature) { - this.editFeature = feature; - } + getDrawFeature() { + return this.drawFeature; } /** @@ -161,6 +161,31 @@ class Editor extends BaseObject { return this.editFeature; } + /** + * Removes the editor from the map. + */ + remove() { + const controls = [...this.controls.getArray()]; + controls.forEach((control) => { + this.removeControl(control); + }); + if (this.toolbar) { + this.toolbar.destroy(); + } + } + + /** + * Remove a control from the editor + * @param {ole.Control} control The control. + */ + removeControl(control) { + control.deactivate(); + this.controls.remove(control); + control.removeEventListener("change:active", this.activeStateChange); + control.setEditor(); + control.setMap(); + } + /** * Sets an instance of the feature that is being drawn. * Some controls need information about the feature @@ -175,56 +200,32 @@ class Editor extends BaseObject { } /** - * Returns the feature that is currently being drawn. - * @returns {ol.Feature|null} The drawFeature. - */ - getDrawFeature() { - return this.drawFeature; - } - - /** - * Controls use this function for triggering activity state changes. - * @param {ol.control.Control} control Control. - * @private + * Sets an instance of the feature that is edited. + * Some controls need information about the feature + * that is currently edited (e.g. for not snapping on them). + * @param {ol.Feature|null} feature The editfeature (or null if none) + * @protected */ - activeStateChange(evt) { - const ctrl = evt.detail.control; - // Deactivate other controls that are not standalone - if (ctrl.getActive() && ctrl.standalone) { - for (let i = 0; i < this.controls.getLength(); i += 1) { - const otherCtrl = this.controls.item(i); - if ( - otherCtrl !== ctrl && - otherCtrl.getActive() && - otherCtrl.standalone - ) { - otherCtrl.deactivate(); - this.activeControls.remove(otherCtrl); - } - } - } - - if (ctrl.getActive()) { - this.activeControls.push(ctrl); - } else { - this.activeControls.remove(ctrl); + setEditFeature(feature) { + if (feature !== this.editFeature) { + this.editFeature = feature; } } - get editFeature() { - return this.get('editFeature'); + get drawFeature() { + return this.get("drawFeature"); } - set editFeature(feature) { - this.set('editFeature', feature); + set drawFeature(feature) { + this.set("drawFeature", feature); } - get drawFeature() { - return this.get('drawFeature'); + get editFeature() { + return this.get("editFeature"); } - set drawFeature(feature) { - this.set('drawFeature', feature); + set editFeature(feature) { + this.set("editFeature", feature); } } diff --git a/src/editor.test.js b/src/editor.test.js index 30752440..4ee50759 100644 --- a/src/editor.test.js +++ b/src/editor.test.js @@ -1,11 +1,11 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { expect, test, describe, beforeEach } from 'vitest'; -import Map from 'ol/Map'; -import Editor from './editor'; -import CAD from './control/cad'; -import ModifyControl from './control/modify'; +import Map from "ol/Map"; +import { beforeEach, describe, expect, test } from "vitest"; -describe('editor', () => { +import CAD from "./control/cad"; +import ModifyControl from "./control/modify"; +import Editor from "./editor"; + +describe("editor", () => { let map; let editor; let cad; @@ -14,14 +14,14 @@ describe('editor', () => { beforeEach(() => { // In the test we use pixel as coordinates. map = new Map({ - target: document.createElement('div'), + target: document.createElement("div"), }); editor = new Editor(map); cad = new CAD(); modify = new ModifyControl(); }); - test('adds a control', () => { + test("adds a control", () => { editor.addControl(cad); expect(editor.controls.getArray()[0]).toBe(cad); expect(editor.activeControls.getLength()).toBe(0); @@ -34,7 +34,7 @@ describe('editor', () => { expect(editor.activeControls.getArray()[0]).toBe(cad); }); - test('removes a control', () => { + test("removes a control", () => { editor.addControl(cad); cad.activate(); expect(cad.getActive()).toBe(true); @@ -48,7 +48,7 @@ describe('editor', () => { expect(cad.getActive()).toBe(false); }); - test('is removed', () => { + test("is removed", () => { editor.addControl(modify); editor.addControl(cad); modify.activate(); diff --git a/src/event/delete-event.js b/src/event/delete-event.js index a49e2f50..5693e960 100644 --- a/src/event/delete-event.js +++ b/src/event/delete-event.js @@ -1,4 +1,4 @@ -import Event from 'ol/events/Event'; +import Event from "ol/events/Event"; /** * Enum for delete event type. @@ -10,7 +10,7 @@ export const DeleteEventType = { * Triggered upon feature(s) is(are) deleted. * @type {string} */ - DELETE: 'delete', + DELETE: "delete", }; /** diff --git a/src/event/index.js b/src/event/index.js index fb41c4e2..0882dd73 100644 --- a/src/event/index.js +++ b/src/event/index.js @@ -1,6 +1,6 @@ -export { default as DeleteEvent } from './delete-event'; -export { default as MoveEvent } from './move-event'; -export { default as SnapEvent } from './snap-event'; -export * from './snap-event'; -export * from './move-event'; -export * from './delete-event'; +export { default as DeleteEvent } from "./delete-event"; +export * from "./delete-event"; +export { default as MoveEvent } from "./move-event"; +export * from "./move-event"; +export { default as SnapEvent } from "./snap-event"; +export * from "./snap-event"; diff --git a/src/event/move-event.js b/src/event/move-event.js index 6f70903d..38eff1c6 100644 --- a/src/event/move-event.js +++ b/src/event/move-event.js @@ -1,4 +1,4 @@ -import Event from 'ol/events/Event'; +import Event from "ol/events/Event"; /** * @enum {string} MoveEventType @@ -6,14 +6,14 @@ import Event from 'ol/events/Event'; */ export const MoveEventType = { /** - * Triggered upon feature move start + * Triggered upon feature move end */ - MOVESTART: 'movestart', + MOVEEND: "moveend", /** - * Triggered upon feature move end + * Triggered upon feature move start */ - MOVEEND: 'moveend', + MOVESTART: "movestart", }; /** diff --git a/src/event/snap-event.js b/src/event/snap-event.js index d57f27e3..00eed17e 100644 --- a/src/event/snap-event.js +++ b/src/event/snap-event.js @@ -1,4 +1,4 @@ -import Event from 'ol/events/Event'; +import Event from "ol/events/Event"; /** * Enum for snap event type. @@ -10,7 +10,7 @@ export const SnapEventType = { * Triggered upon feature is snapped. * @type {string} */ - SNAP: 'snap', + SNAP: "snap", }; /** diff --git a/src/helper/constants.js b/src/helper/constants.js index 7f11d47b..363f67f9 100644 --- a/src/helper/constants.js +++ b/src/helper/constants.js @@ -1,47 +1,47 @@ -import { Fill, RegularShape, Stroke, Style } from 'ol/style'; +import { Fill, RegularShape, Stroke, Style } from "ol/style"; -export const ORTHO_LINE_KEY = 'ortho'; -export const SEGMENT_LINE_KEY = 'segment'; -export const VH_LINE_KEY = 'vh'; -export const CUSTOM_LINE_KEY = 'custom'; -export const SNAP_POINT_KEY = 'point'; -export const SNAP_FEATURE_TYPE_PROPERTY = 'ole.snap.feature.type'; +export const ORTHO_LINE_KEY = "ortho"; +export const SEGMENT_LINE_KEY = "segment"; +export const VH_LINE_KEY = "vh"; +export const CUSTOM_LINE_KEY = "custom"; +export const SNAP_POINT_KEY = "point"; +export const SNAP_FEATURE_TYPE_PROPERTY = "ole.snap.feature.type"; export const defaultSnapStyles = { [ORTHO_LINE_KEY]: new Style({ stroke: new Stroke({ - width: 1, - color: 'purple', + color: "purple", lineDash: [5, 10], + width: 1, }), }), [SEGMENT_LINE_KEY]: new Style({ stroke: new Stroke({ - width: 1, - color: 'orange', + color: "orange", lineDash: [5, 10], - }), - }), - [VH_LINE_KEY]: new Style({ - stroke: new Stroke({ width: 1, - lineDash: [5, 10], - color: '#618496', }), }), [SNAP_POINT_KEY]: new Style({ image: new RegularShape({ + angle: Math.PI / 4, fill: new Fill({ - color: '#E8841F', - }), - stroke: new Stroke({ - width: 1, - color: '#618496', + color: "#E8841F", }), points: 4, radius: 5, radius2: 0, - angle: Math.PI / 4, + stroke: new Stroke({ + color: "#618496", + width: 1, + }), + }), + }), + [VH_LINE_KEY]: new Style({ + stroke: new Stroke({ + color: "#618496", + lineDash: [5, 10], + width: 1, }), }), }; diff --git a/src/helper/getEquationOfLine.js b/src/helper/getEquationOfLine.js index 30a36c89..67faca6e 100644 --- a/src/helper/getEquationOfLine.js +++ b/src/helper/getEquationOfLine.js @@ -10,7 +10,9 @@ const getEquationOfLine = (coordA, coordB) => { } const m = (yB - yA) / (xB - xA); const b = yB - m * xB; - return (x) => m * x + b; + return (x) => { + return m * x + b; + }; }; export default getEquationOfLine; diff --git a/src/helper/getIntersectedLinesAndPoint.js b/src/helper/getIntersectedLinesAndPoint.js index e73ba345..f4433da0 100644 --- a/src/helper/getIntersectedLinesAndPoint.js +++ b/src/helper/getIntersectedLinesAndPoint.js @@ -1,10 +1,11 @@ -import { OverlayOp } from 'jsts/org/locationtech/jts/operation/overlay'; -import { Feature } from 'ol'; -import { Point } from 'ol/geom'; -import { SNAP_FEATURE_TYPE_PROPERTY, SNAP_POINT_KEY } from './constants'; -import getDistance from './getDistance'; -import isSameLines from './isSameLines'; -import parser from './parser'; +import { OverlayOp } from "jsts/org/locationtech/jts/operation/overlay"; +import { Feature } from "ol"; +import { Point } from "ol/geom"; + +import { SNAP_FEATURE_TYPE_PROPERTY, SNAP_POINT_KEY } from "./constants"; +import getDistance from "./getDistance"; +import isSameLines from "./isSameLines"; +import parser from "./parser"; // Find lines that intersects and calculate the intersection point. // Return only point (and corresponding lines) that are distant from the mouse coordinate < snapTolerance @@ -15,10 +16,9 @@ const getIntersectedLinesAndPoint = (coordinate, lines, map, snapTolerance) => { const isPointAlreadyExist = {}; const mousePx = map.getPixelFromCoordinate(coordinate); - const parsedLines = lines.map((line) => [ - line, - parser.read(line.getGeometry()), - ]); + const parsedLines = lines.map((line) => { + return [line, parser.read(line.getGeometry())]; + }); parsedLines.forEach(([lineA, parsedLineA]) => { parsedLines.forEach(([lineB, parsedLineB]) => { if (lineA === lineB || isSameLines(lineA, lineB, map)) { @@ -28,7 +28,9 @@ const getIntersectedLinesAndPoint = (coordinate, lines, map, snapTolerance) => { let intersections; try { intersections = OverlayOp.intersection(parsedLineA, parsedLineB); - } catch (e) { + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { return; // The OverlayOp will sometimes error with topology errors for certain lines } diff --git a/src/helper/getIntersectedLinesAndPoint.test.js b/src/helper/getIntersectedLinesAndPoint.test.js index 01daaf9b..b9593f53 100644 --- a/src/helper/getIntersectedLinesAndPoint.test.js +++ b/src/helper/getIntersectedLinesAndPoint.test.js @@ -1,20 +1,22 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { expect, test, describe, beforeEach } from 'vitest'; -import LineString from 'ol/geom/LineString'; -import Feature from 'ol/Feature'; -import getIntersectedLinesAndPoint from './getIntersectedLinesAndPoint'; +import Feature from "ol/Feature"; +import LineString from "ol/geom/LineString"; +import { beforeEach, describe, expect, test } from "vitest"; -describe('getIntersectedLinesAndPoint', () => { +import getIntersectedLinesAndPoint from "./getIntersectedLinesAndPoint"; + +describe("getIntersectedLinesAndPoint", () => { let map; beforeEach(() => { // In the test we use pixel as coordinates. map = { - getPixelFromCoordinate: (coord) => coord, + getPixelFromCoordinate: (coord) => { + return coord; + }, }; }); - test('returns empty array because lines are not intersected', () => { + test("returns empty array because lines are not intersected", () => { const line1 = new Feature( new LineString([ [0, 0], @@ -38,7 +40,7 @@ describe('getIntersectedLinesAndPoint', () => { expect(intersectedLines).toEqual([]); }); - test('returns empty array because the tolerance is not big enough', () => { + test("returns empty array because the tolerance is not big enough", () => { const line1 = new Feature( new LineString([ [0, 0], @@ -62,7 +64,7 @@ describe('getIntersectedLinesAndPoint', () => { expect(intersectedLines).toEqual([]); }); - test('returns intersected lines and the intersection point', () => { + test("returns intersected lines and the intersection point", () => { const line1 = new Feature( new LineString([ [0, 0], diff --git a/src/helper/getProjectedPoint.js b/src/helper/getProjectedPoint.js index f7484754..308f0874 100644 --- a/src/helper/getProjectedPoint.js +++ b/src/helper/getProjectedPoint.js @@ -1,4 +1,6 @@ -const dotProduct = (e1, e2) => e1[0] * e2[0] + e1[1] * e2[1]; +const dotProduct = (e1, e2) => { + return e1[0] * e2[0] + e1[1] * e2[1]; +}; /** * Get projected point P' of P on line e1. Faster version. diff --git a/src/helper/getShiftedMultiPoint.js b/src/helper/getShiftedMultiPoint.js index 4f8ba377..4b74f1d4 100644 --- a/src/helper/getShiftedMultiPoint.js +++ b/src/helper/getShiftedMultiPoint.js @@ -1,30 +1,78 @@ -import { MultiPoint } from 'ol/geom'; +import { getUid } from "ol"; +import { LineString, MultiPoint } from "ol/geom"; + +let prevCoordinates; +let prevFeature; +let prevIndex = -1; /** - * Removes the closest node to a given coordinate from a given geometry. + * Removes the last coordinate of a given geometry (Line or Polygon). + * When we draw the last coordinate if tat mouse cursor. * @private * @param {ol.Geometry} geometry An openlayers geometry. - * @param {ol.Coordinate} coordinate Coordinate. * @returns {ol.Geometry.MultiPoint} An openlayers MultiPoint geometry. */ -const getShiftedMultipoint = (geometry, coordinate) => { - // Include all but the closest vertex to the coordinate (e.g. at mouse position) +const getShiftedMultipoint = ( + geometry, + coordinate, + editFeature, + drawFeature, +) => { + // Include all but the last vertex to the coordinate (e.g. at mouse position) // to prevent snapping on mouse cursor node - const isPolygon = geometry.getType() === 'Polygon'; - const shiftedMultipoint = new MultiPoint( - isPolygon ? geometry.getCoordinates()[0] : geometry.getCoordinates(), - ); + let lineGeometry = geometry; + + const isPolygon = geometry.getType() === "Polygon"; + if (isPolygon) { + const coordinates = geometry.getCoordinates()[0]; + + // If the poylgon is properly closed we remove the last coordinate to avoid duplicated snapping nodes and lines. + if ( + coordinates[0].toString() === + coordinates[coordinates.length - 1].toString() + ) { + coordinates.pop(); + } + lineGeometry = new LineString(coordinates); + } + + let coordinates = []; + + if ( + !editFeature || + (prevFeature && getUid(editFeature) !== getUid(prevFeature)) + ) { + prevFeature = editFeature; + prevCoordinates = null; + prevIndex = -1; + } + + // When the user is drawing a line or polygon, we just want to remove the last coordinate drawn. + if (drawFeature) { + lineGeometry.forEachSegment((start) => { + coordinates.push(start); + }); - const drawNodeCoordinate = shiftedMultipoint.getClosestPoint(coordinate); + // When we are modifying a line or polygon, we want to remove the node that is being modified. + } else if (editFeature) { + const index = prevCoordinates?.length + ? lineGeometry.getCoordinates()?.findIndex((coord, index) => { + return coord.toString() !== prevCoordinates[index].toString(); + }) + : -1; - // Exclude the node being modified - shiftedMultipoint.setCoordinates( - shiftedMultipoint - .getCoordinates() - .filter((coord) => coord.toString() !== drawNodeCoordinate.toString()), - ); + // The use of prevIndex avoid the flickering of the snapping node on each pointer move event. + prevIndex = index != -1 ? index : prevIndex; + prevCoordinates = lineGeometry.getCoordinates(); - return shiftedMultipoint; + if (prevIndex > -1) { + // Exclude the node being modified + const coords = lineGeometry.getCoordinates(); + coords.splice(prevIndex, 1); + coordinates = coords; + } + } + return new MultiPoint(coordinates); }; export default getShiftedMultipoint; diff --git a/src/helper/index.js b/src/helper/index.js index 8536a3bb..68a777b3 100644 --- a/src/helper/index.js +++ b/src/helper/index.js @@ -1,7 +1,7 @@ -export { default as getEquationOfLine } from './getEquationOfLine'; -export { default as getIntersectedLinesAndPoint } from './getIntersectedLinesAndPoint'; -export { default as getProjectedPoint } from './getProjectedPoint'; -export { default as getShiftedMultiPoint } from './getShiftedMultiPoint'; -export { default as isSameLines } from './isSameLines'; -export { default as parser } from './parser'; -export * from './constants'; +export * from "./constants"; +export { default as getEquationOfLine } from "./getEquationOfLine"; +export { default as getIntersectedLinesAndPoint } from "./getIntersectedLinesAndPoint"; +export { default as getProjectedPoint } from "./getProjectedPoint"; +export { default as getShiftedMultiPoint } from "./getShiftedMultiPoint"; +export { default as isSameLines } from "./isSameLines"; +export { default as parser } from "./parser"; diff --git a/src/helper/isSameLines.js b/src/helper/isSameLines.js index f4af472e..93cf1c68 100644 --- a/src/helper/isSameLines.js +++ b/src/helper/isSameLines.js @@ -1,7 +1,7 @@ // We consider 2 lines identical when 2 lines have the same equation when the use their pixel values not coordinate. // Using the coordinate the calculation is falsy because of some rounding. -import getEquationOfLine from './getEquationOfLine'; +import getEquationOfLine from "./getEquationOfLine"; // This function compares only 2 lines of 2 coordinates. const isSameLines = (lineA, lineB, map) => { diff --git a/src/helper/isSameLines.test.js b/src/helper/isSameLines.test.js index f1d78b82..7f260de7 100644 --- a/src/helper/isSameLines.test.js +++ b/src/helper/isSameLines.test.js @@ -1,20 +1,22 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { expect, test, describe, beforeEach } from 'vitest'; -import LineString from 'ol/geom/LineString'; -import Feature from 'ol/Feature'; -import isSameLines from './isSameLines'; +import Feature from "ol/Feature"; +import LineString from "ol/geom/LineString"; +import { beforeEach, describe, expect, test } from "vitest"; -describe('isSameLines', () => { +import isSameLines from "./isSameLines"; + +describe("isSameLines", () => { let map; beforeEach(() => { // In the test we use pixel as coordinates. map = { - getPixelFromCoordinate: (coord) => coord, + getPixelFromCoordinate: (coord) => { + return coord; + }, }; }); - test('returns false', () => { + test("returns false", () => { const line1 = new Feature( new LineString([ [0, 0], @@ -32,7 +34,7 @@ describe('isSameLines', () => { expect(isSameLine).toBe(false); }); - test('returns true', () => { + test("returns true", () => { const line1 = new Feature( new LineString([ [0, 0], diff --git a/src/helper/parser.js b/src/helper/parser.js index 1ec5f335..bd660a6f 100644 --- a/src/helper/parser.js +++ b/src/helper/parser.js @@ -1,5 +1,5 @@ -import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser'; -import { LineString, MultiPoint, Point, Polygon } from 'ol/geom'; +import OL3Parser from "jsts/org/locationtech/jts/io/OL3Parser"; +import { LineString, MultiPoint, Point, Polygon } from "ol/geom"; // Create a JSTS parser for OpenLayers geometry. const parser = new OL3Parser(); diff --git a/src/index.js b/src/index.js index e434b9bc..8c061127 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ -export { default as Editor } from './editor'; -export * as control from './control'; -export * as service from './service'; -export * as interaction from './interaction'; -export * as helper from './helper'; +export * as control from "./control"; +export { default as Editor } from "./editor"; +export * as helper from "./helper"; +export * as interaction from "./interaction"; +export * as service from "./service"; diff --git a/src/interaction/delete.js b/src/interaction/delete.js index 1cd23eab..79be5ecd 100644 --- a/src/interaction/delete.js +++ b/src/interaction/delete.js @@ -1,7 +1,8 @@ -import Interaction from 'ol/interaction/Interaction'; -import EventType from 'ol/events/EventType'; -import { noModifierKeys, targetNotEditable } from 'ol/events/condition'; -import DeleteEvent, { DeleteEventType } from '../event/delete-event'; +import { noModifierKeys, targetNotEditable } from "ol/events/condition"; +import EventType from "ol/events/EventType"; +import Interaction from "ol/interaction/Interaction"; + +import DeleteEvent, { DeleteEventType } from "../event/delete-event"; class Delete extends Interaction { constructor(options = {}) { @@ -23,10 +24,6 @@ class Delete extends Interaction { }); } - setFeatures(features) { - this.features = features; - } - handleEvent(mapBrowserEvent) { let stopEvent = false; if ( @@ -36,9 +33,9 @@ class Delete extends Interaction { this.features ) { // Loop delete through selected features array - this.features - .getArray() - .forEach((feature) => this.source.removeFeature(feature)); + this.features.getArray().forEach((feature) => { + return this.source.removeFeature(feature); + }); this.dispatchEvent( new DeleteEvent(DeleteEventType.DELETE, this.features, mapBrowserEvent), @@ -50,6 +47,10 @@ class Delete extends Interaction { } return !stopEvent; } + + setFeatures(features) { + this.features = features; + } } export default Delete; diff --git a/src/interaction/index.js b/src/interaction/index.js index 8c7d97f5..d84e5cb4 100644 --- a/src/interaction/index.js +++ b/src/interaction/index.js @@ -1,4 +1,4 @@ -export { default as Delete } from './delete'; -export { default as SelectMove } from './selectmove'; -export { default as SelectModify } from './selectmodify'; -export { default as Move } from './move'; +export { default as Delete } from "./delete"; +export { default as Move } from "./move"; +export { default as SelectModify } from "./selectmodify"; +export { default as SelectMove } from "./selectmove"; diff --git a/src/interaction/move.js b/src/interaction/move.js index cbc3543d..ac629349 100644 --- a/src/interaction/move.js +++ b/src/interaction/move.js @@ -1,7 +1,8 @@ -import Pointer from 'ol/interaction/Pointer'; -import Point from 'ol/geom/Point'; -import { getCenter } from 'ol/extent'; -import MoveEvent, { MoveEventType } from '../event/move-event'; +import { getCenter } from "ol/extent"; +import Point from "ol/geom/Point"; +import Pointer from "ol/interaction/Pointer"; + +import MoveEvent, { MoveEventType } from "../event/move-event"; class Move extends Pointer { constructor(options) { diff --git a/src/interaction/selectmodify.js b/src/interaction/selectmodify.js index 99646ff2..a11bf871 100644 --- a/src/interaction/selectmodify.js +++ b/src/interaction/selectmodify.js @@ -1,54 +1,41 @@ -/* eslint-disable no-underscore-dangle */ -import Select from 'ol/interaction/Select'; -import { doubleClick } from 'ol/events/condition'; -import { Circle, Style, Fill, Stroke } from 'ol/style'; -import GeometryCollection from 'ol/geom/GeometryCollection'; -import { MultiPoint } from 'ol/geom'; +import { doubleClick } from "ol/events/condition"; +import { MultiPoint } from "ol/geom"; +import GeometryCollection from "ol/geom/GeometryCollection"; +import Select from "ol/interaction/Select"; +import { Circle, Fill, Stroke, Style } from "ol/style"; // Default style on modifying geometries const selectModifyStyle = new Style({ - zIndex: 10000, // Always on top - image: new Circle({ - radius: 5, - fill: new Fill({ - color: '#05A0FF', - }), - stroke: new Stroke({ color: '#05A0FF', width: 2 }), - }), - stroke: new Stroke({ - color: '#05A0FF', - width: 3, - }), fill: new Fill({ - color: 'rgba(255,255,255,0.4)', + color: "rgba(255,255,255,0.4)", }), geometry: (f) => { const coordinates = []; const geometry = f.getGeometry(); let geometries = [geometry]; - if (geometry.getType() === 'GeometryCollection') { + if (geometry.getType() === "GeometryCollection") { geometries = geometry.getGeometriesArrayRecursive(); } // At this point geometries doesn't contains any GeometryCollections. geometries.forEach((geom) => { let multiGeometries = [geom]; - if (geom.getType() === 'MultiLineString') { + if (geom.getType() === "MultiLineString") { multiGeometries = geom.getLineStrings(); - } else if (geom.getType() === 'MultiPolygon') { + } else if (geom.getType() === "MultiPolygon") { multiGeometries = geom.getPolygons(); - } else if (geom.getType() === 'MultiPoint') { + } else if (geom.getType() === "MultiPoint") { multiGeometries = geom.getPoints(); } // At this point multiGeometries contains only single geometry. multiGeometries.forEach((geomm) => { - if (geomm.getType() === 'Polygon') { + if (geomm.getType() === "Polygon") { geomm.getLinearRings().forEach((ring) => { coordinates.push(...ring.getCoordinates()); }); - } else if (geomm.getType() === 'LineString') { + } else if (geomm.getType() === "LineString") { coordinates.push(...geomm.getCoordinates()); - } else if (geomm.getType() === 'Point') { + } else if (geomm.getType() === "Point") { coordinates.push(geomm.getCoordinates()); } }); @@ -58,6 +45,18 @@ const selectModifyStyle = new Style({ new MultiPoint(coordinates), ]); }, + image: new Circle({ + fill: new Fill({ + color: "#05A0FF", + }), + radius: 5, + stroke: new Stroke({ color: "#05A0FF", width: 2 }), + }), + stroke: new Stroke({ + color: "#05A0FF", + width: 3, + }), + zIndex: 10000, // Always on top }); /** @@ -100,8 +99,8 @@ class SelectModify extends Select { } }, { - layerFilter: this.layerFilter_, hitTolerance: this.hitTolerance_, + layerFilter: this.layerFilter_, }, ); diff --git a/src/interaction/selectmove.js b/src/interaction/selectmove.js index c62643fc..4fccab5f 100644 --- a/src/interaction/selectmove.js +++ b/src/interaction/selectmove.js @@ -1,24 +1,24 @@ -import Select from 'ol/interaction/Select'; -import { Circle, Style, Fill, Stroke } from 'ol/style'; -import { singleClick } from 'ol/events/condition'; +import { singleClick } from "ol/events/condition"; +import Select from "ol/interaction/Select"; +import { Circle, Fill, Stroke, Style } from "ol/style"; // Default style on moving geometries const selectMoveStyle = new Style({ - zIndex: 10000, // Always on top + fill: new Fill({ + color: "rgba(255,255,255,0.4)", + }), image: new Circle({ - radius: 5, fill: new Fill({ - color: '#05A0FF', + color: "#05A0FF", }), - stroke: new Stroke({ color: '#05A0FF', width: 2 }), + radius: 5, + stroke: new Stroke({ color: "#05A0FF", width: 2 }), }), stroke: new Stroke({ - color: '#05A0FF', + color: "#05A0FF", width: 3, }), - fill: new Fill({ - color: 'rgba(255,255,255,0.4)', - }), + zIndex: 10000, // Always on top }); /** diff --git a/src/service/index.js b/src/service/index.js index 4e138b25..2a61cb81 100644 --- a/src/service/index.js +++ b/src/service/index.js @@ -1,2 +1,2 @@ -export { default as LocalStorage } from './local-storage'; -export { default as Storage } from './storage'; +export { default as LocalStorage } from "./local-storage"; +export { default as Storage } from "./storage"; diff --git a/src/service/local-storage.js b/src/service/local-storage.js index 8e088125..f4446722 100644 --- a/src/service/local-storage.js +++ b/src/service/local-storage.js @@ -1,4 +1,4 @@ -import Storage from './storage'; +import Storage from "./storage"; /** * OLE LocalStorage. @@ -9,9 +9,25 @@ export default class LocalStorage extends Storage { /** * @inheritdoc */ - storeProperties(controlName, properties) { - const props = super.storeProperties(controlName, properties); - window.localStorage.setItem(controlName, JSON.stringify(props)); + restoreActiveControls() { + let activeControlNames = window.localStorage.getItem("active"); + activeControlNames = activeControlNames + ? JSON.parse(activeControlNames) + : []; + + if (!activeControlNames.length) { + return; + } + + for (let i = 0; i < this.controls.length; i += 1) { + const controlName = this.controls[i].getProperties().title; + + if (activeControlNames.indexOf(controlName) > -1) { + this.controls[i].activate(); + } else { + this.controls[i].deactivate(); + } + } } /** @@ -33,30 +49,14 @@ export default class LocalStorage extends Storage { */ storeActiveControls() { const activeControlNames = super.storeActiveControls(); - window.localStorage.setItem('active', JSON.stringify(activeControlNames)); + window.localStorage.setItem("active", JSON.stringify(activeControlNames)); } /** * @inheritdoc */ - restoreActiveControls() { - let activeControlNames = window.localStorage.getItem('active'); - activeControlNames = activeControlNames - ? JSON.parse(activeControlNames) - : []; - - if (!activeControlNames.length) { - return; - } - - for (let i = 0; i < this.controls.length; i += 1) { - const controlName = this.controls[i].getProperties().title; - - if (activeControlNames.indexOf(controlName) > -1) { - this.controls[i].activate(); - } else { - this.controls[i].deactivate(); - } - } + storeProperties(controlName, properties) { + const props = super.storeProperties(controlName, properties); + window.localStorage.setItem(controlName, JSON.stringify(props)); } } diff --git a/src/service/storage.js b/src/service/storage.js index d464be9c..943b1f07 100644 --- a/src/service/storage.js +++ b/src/service/storage.js @@ -1,4 +1,4 @@ -import Service from './service'; +import Service from "./service"; /** * OLE storage service. @@ -28,7 +28,7 @@ export default class Storage extends Service { * List of properties keys to ignore. * @type {array.} */ - this.ignoreKeys = ['title', 'image', 'className']; + this.ignoreKeys = ["title", "image", "className"]; } /** @@ -41,14 +41,14 @@ export default class Storage extends Service { this.restoreActiveControls(); this.controls.forEach((control) => { - control.addEventListener('propertychange', (evt) => { + control.addEventListener("propertychange", (evt) => { this.storeProperties( evt.detail.control.getProperties().title, evt.detail.properties, ); }); - control.addEventListener('change:active', () => { + control.addEventListener("change:active", () => { this.storeActiveControls(); }); }); @@ -61,36 +61,21 @@ export default class Storage extends Service { super.deactivate(); this.controls.forEach((control) => { - control.removeEventListener('propertychange'); + control.removeEventListener("propertychange"); }); } /** - * Store control properties. - * @param {string} controlName Name of the control. - * @param {object} properties Control properties. + * Restore the active state of the controls. */ - storeProperties(controlName, properties) { - const storageProps = {}; - const propKeys = Object.keys(properties); - - for (let i = 0; i < propKeys.length; i += 1) { - const key = propKeys[i]; - if ( - this.ignoreKeys.indexOf(key) === -1 && - !(properties[key] instanceof Object) - ) { - storageProps[key] = properties[key]; - } - } - - return storageProps; + restoreActiveControls() { + // to be implemented by child class } /** * Restore the control properties. */ - // eslint-disable-next-line class-methods-use-this + restoreProperties() { // to be implemented by child class } @@ -100,14 +85,30 @@ export default class Storage extends Service { */ storeActiveControls() { const activeControls = this.editor.getActiveControls(); - return activeControls.getArray().map((c) => c.getProperties().title); + return activeControls.getArray().map((c) => { + return c.getProperties().title; + }); } /** - * Restore the active state of the controls. + * Store control properties. + * @param {string} controlName Name of the control. + * @param {object} properties Control properties. */ - // eslint-disable-next-line class-methods-use-this - restoreActiveControls() { - // to be implemented by child class + storeProperties(controlName, properties) { + const storageProps = {}; + const propKeys = Object.keys(properties); + + for (let i = 0; i < propKeys.length; i += 1) { + const key = propKeys[i]; + if ( + this.ignoreKeys.indexOf(key) === -1 && + !(properties[key] instanceof Object) + ) { + storageProps[key] = properties[key]; + } + } + + return storageProps; } } diff --git a/yarn.lock b/yarn.lock index aa171b0a..3a8335d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -226,7 +226,7 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz#7dfccb9df5499e627e7bfdbb4021a06813a45dba" integrity sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ== -"@cypress/request@^3.0.1": +"@cypress/request@^3.0.4": version "3.0.5" resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.5.tgz#d893a6e68ce2636c085fcd8d7283c3186499ba63" integrity sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA== @@ -268,267 +268,293 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== -"@esbuild/aix-ppc64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" - integrity sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ== +"@esbuild/aix-ppc64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz#b57697945b50e99007b4c2521507dc613d4a648c" + integrity sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw== "@esbuild/android-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== -"@esbuild/android-arm64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz#58565291a1fe548638adb9c584237449e5e14018" - integrity sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw== +"@esbuild/android-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz#1add7e0af67acefd556e407f8497e81fddad79c0" + integrity sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w== "@esbuild/android-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== -"@esbuild/android-arm@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.1.tgz#5eb8c652d4c82a2421e3395b808e6d9c42c862ee" - integrity sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ== +"@esbuild/android-arm@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.24.0.tgz#ab7263045fa8e090833a8e3c393b60d59a789810" + integrity sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew== "@esbuild/android-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== -"@esbuild/android-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.1.tgz#ae19d665d2f06f0f48a6ac9a224b3f672e65d517" - integrity sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg== +"@esbuild/android-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.24.0.tgz#e8f8b196cfdfdd5aeaebbdb0110983460440e705" + integrity sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ== "@esbuild/darwin-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== -"@esbuild/darwin-arm64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz#05b17f91a87e557b468a9c75e9d85ab10c121b16" - integrity sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q== +"@esbuild/darwin-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz#2d0d9414f2acbffd2d86e98253914fca603a53dd" + integrity sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw== "@esbuild/darwin-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== -"@esbuild/darwin-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz#c58353b982f4e04f0d022284b8ba2733f5ff0931" - integrity sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw== +"@esbuild/darwin-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz#33087aab31a1eb64c89daf3d2cf8ce1775656107" + integrity sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA== "@esbuild/freebsd-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== -"@esbuild/freebsd-arm64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz#f9220dc65f80f03635e1ef96cfad5da1f446f3bc" - integrity sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA== +"@esbuild/freebsd-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz#bb76e5ea9e97fa3c753472f19421075d3a33e8a7" + integrity sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA== "@esbuild/freebsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== -"@esbuild/freebsd-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz#69bd8511fa013b59f0226d1609ac43f7ce489730" - integrity sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g== +"@esbuild/freebsd-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz#e0e2ce9249fdf6ee29e5dc3d420c7007fa579b93" + integrity sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ== "@esbuild/linux-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== -"@esbuild/linux-arm64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz#8050af6d51ddb388c75653ef9871f5ccd8f12383" - integrity sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g== +"@esbuild/linux-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz#d1b2aa58085f73ecf45533c07c82d81235388e75" + integrity sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g== "@esbuild/linux-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== -"@esbuild/linux-arm@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz#ecaabd1c23b701070484990db9a82f382f99e771" - integrity sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ== +"@esbuild/linux-arm@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz#8e4915df8ea3e12b690a057e77a47b1d5935ef6d" + integrity sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw== "@esbuild/linux-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== -"@esbuild/linux-ia32@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz#3ed2273214178109741c09bd0687098a0243b333" - integrity sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ== +"@esbuild/linux-ia32@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz#8200b1110666c39ab316572324b7af63d82013fb" + integrity sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA== "@esbuild/linux-loong64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== -"@esbuild/linux-loong64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz#a0fdf440b5485c81b0fbb316b08933d217f5d3ac" - integrity sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw== +"@esbuild/linux-loong64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz#6ff0c99cf647504df321d0640f0d32e557da745c" + integrity sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g== "@esbuild/linux-mips64el@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== -"@esbuild/linux-mips64el@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz#e11a2806346db8375b18f5e104c5a9d4e81807f6" - integrity sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q== +"@esbuild/linux-mips64el@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz#3f720ccd4d59bfeb4c2ce276a46b77ad380fa1f3" + integrity sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA== "@esbuild/linux-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== -"@esbuild/linux-ppc64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz#06a2744c5eaf562b1a90937855b4d6cf7c75ec96" - integrity sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw== +"@esbuild/linux-ppc64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz#9d6b188b15c25afd2e213474bf5f31e42e3aa09e" + integrity sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ== "@esbuild/linux-riscv64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== -"@esbuild/linux-riscv64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz#65b46a2892fc0d1af4ba342af3fe0fa4a8fe08e7" - integrity sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA== +"@esbuild/linux-riscv64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz#f989fdc9752dfda286c9cd87c46248e4dfecbc25" + integrity sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw== "@esbuild/linux-s390x@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== -"@esbuild/linux-s390x@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz#e71ea18c70c3f604e241d16e4e5ab193a9785d6f" - integrity sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw== +"@esbuild/linux-s390x@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz#29ebf87e4132ea659c1489fce63cd8509d1c7319" + integrity sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g== "@esbuild/linux-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== -"@esbuild/linux-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz#d47f97391e80690d4dfe811a2e7d6927ad9eed24" - integrity sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ== +"@esbuild/linux-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz#4af48c5c0479569b1f359ffbce22d15f261c0cef" + integrity sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA== "@esbuild/netbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== -"@esbuild/netbsd-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz#44e743c9778d57a8ace4b72f3c6b839a3b74a653" - integrity sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA== +"@esbuild/netbsd-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz#1ae73d23cc044a0ebd4f198334416fb26c31366c" + integrity sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg== -"@esbuild/openbsd-arm64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz#05c5a1faf67b9881834758c69f3e51b7dee015d7" - integrity sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q== +"@esbuild/openbsd-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz#5d904a4f5158c89859fd902c427f96d6a9e632e2" + integrity sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg== "@esbuild/openbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== -"@esbuild/openbsd-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz#2e58ae511bacf67d19f9f2dcd9e8c5a93f00c273" - integrity sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA== +"@esbuild/openbsd-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz#4c8aa88c49187c601bae2971e71c6dc5e0ad1cdf" + integrity sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q== "@esbuild/sunos-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== -"@esbuild/sunos-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz#adb022b959d18d3389ac70769cef5a03d3abd403" - integrity sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA== +"@esbuild/sunos-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz#8ddc35a0ea38575fa44eda30a5ee01ae2fa54dd4" + integrity sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA== "@esbuild/win32-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== -"@esbuild/win32-arm64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz#84906f50c212b72ec360f48461d43202f4c8b9a2" - integrity sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A== +"@esbuild/win32-arm64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz#6e79c8543f282c4539db684a207ae0e174a9007b" + integrity sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA== "@esbuild/win32-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== -"@esbuild/win32-ia32@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz#5e3eacc515820ff729e90d0cb463183128e82fac" - integrity sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ== +"@esbuild/win32-ia32@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz#057af345da256b7192d18b676a02e95d0fa39103" + integrity sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw== "@esbuild/win32-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== -"@esbuild/win32-x64@0.23.1": - version "0.23.1" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699" - integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg== +"@esbuild/win32-x64@0.24.0": + version "0.24.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz#168ab1c7e1c318b922637fad8f339d48b01e1244" + integrity sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": version "4.11.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.1": - version "8.57.1" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" - integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== +"@eslint/js@9.12.0", "@eslint/js@^9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" + integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== + dependencies: + levn "^0.4.1" "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" @@ -542,24 +568,28 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@humanwhocodes/config-array@^0.13.0": - version "0.13.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" - integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== +"@humanfs/core@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" + integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== + +"@humanfs/node@^0.16.5": + version "0.16.5" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" + integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== dependencies: - "@humanwhocodes/object-schema" "^2.0.3" - debug "^4.3.1" - minimatch "^3.0.5" + "@humanfs/core" "^0.19.0" + "@humanwhocodes/retry" "^0.3.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" - integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -591,7 +621,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -723,6 +753,16 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -763,10 +803,10 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== -"@types/rbush@^3.0.3": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/rbush/-/rbush-3.0.4.tgz#265d84ec76dc48e464e95ae4f58e085f28f0a227" - integrity sha512-knSt9cCW8jj1ZSFcFeBZaX++OucmfPxxHiRwTahZfJlnQsek7O0bazTJHWD2RVj9LEoejUYF2de3/stf+QXcXw== +"@types/rbush@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/rbush/-/rbush-3.0.3.tgz#f7ba6bc940e0913678f5df119e7a7803f1842ece" + integrity sha512-lX55lR0iYCgapxD3IrgujpQA1zDxwZI5qMRelKvmKAsSMplFVr7wmMpG7/6+Op2tjrgEex8o3vjg8CRDrRNYxg== "@types/sinonjs__fake-timers@8.1.1": version "8.1.1" @@ -785,67 +825,188 @@ dependencies: "@types/node" "*" -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== +"@typescript-eslint/eslint-plugin@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz#bf0b25305b0bf014b4b194a6919103d7ac2a7907" + integrity sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.9.0" + "@typescript-eslint/type-utils" "8.9.0" + "@typescript-eslint/utils" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" -"@vitest/expect@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.1.tgz#907137a86246c5328929d796d741c4e95d1ee19d" - integrity sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w== +"@typescript-eslint/parser@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.9.0.tgz#0cecda6def8aef95d7c7098359c0fda5a362d6ad" + integrity sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ== + dependencies: + "@typescript-eslint/scope-manager" "8.9.0" + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/typescript-estree" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" + integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== dependencies: - "@vitest/spy" "2.1.1" - "@vitest/utils" "2.1.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + +"@typescript-eslint/scope-manager@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz#c98fef0c4a82a484e6a1eb610a55b154d14d46f3" + integrity sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ== + dependencies: + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" + +"@typescript-eslint/type-utils@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz#aa86da3e4555fe7c8b42ab75e13561c4b5a8dfeb" + integrity sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q== + dependencies: + "@typescript-eslint/typescript-estree" "8.9.0" + "@typescript-eslint/utils" "8.9.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.8.1", "@typescript-eslint/types@^8.8.0": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" + integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== + +"@typescript-eslint/types@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.9.0.tgz#b733af07fb340b32e962c6c63b1062aec2dc0fe6" + integrity sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ== + +"@typescript-eslint/typescript-estree@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" + integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + 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 "^1.3.0" + +"@typescript-eslint/typescript-estree@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz#1714f167e9063062dc0df49c1d25afcbc7a96199" + integrity sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g== + dependencies: + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.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 "^1.3.0" + +"@typescript-eslint/utils@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.9.0.tgz#748bbe3ea5bee526d9786d9405cf1b0df081c299" + integrity sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.9.0" + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/typescript-estree" "8.9.0" + +"@typescript-eslint/utils@^8.8.0": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" + integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + +"@typescript-eslint/visitor-keys@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" + integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== + dependencies: + "@typescript-eslint/types" "8.8.1" + eslint-visitor-keys "^3.4.3" + +"@typescript-eslint/visitor-keys@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz#5f11f4d9db913f37da42776893ffe0dd1ae78f78" + integrity sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA== + dependencies: + "@typescript-eslint/types" "8.9.0" + eslint-visitor-keys "^3.4.3" + +"@vitest/expect@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.1.3.tgz#4b9a6fff22be4c4cd5d57e687cfda611b514b0ad" + integrity sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ== + dependencies: + "@vitest/spy" "2.1.3" + "@vitest/utils" "2.1.3" chai "^5.1.1" tinyrainbow "^1.2.0" -"@vitest/mocker@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.1.tgz#3e37c80ac267318d4aa03c5073a017d148dc8e67" - integrity sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA== +"@vitest/mocker@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-2.1.3.tgz#a3593b426551be5715fa108faf04f8a9ddb0a9cc" + integrity sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ== dependencies: - "@vitest/spy" "^2.1.0-beta.1" + "@vitest/spy" "2.1.3" estree-walker "^3.0.3" magic-string "^0.30.11" -"@vitest/pretty-format@2.1.1", "@vitest/pretty-format@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.1.tgz#fea25dd4e88c3c1329fbccd1d16b1d607eb40067" - integrity sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ== +"@vitest/pretty-format@2.1.3", "@vitest/pretty-format@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.1.3.tgz#48b9b03de75507d1d493df7beb48dc39a1946a3e" + integrity sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ== dependencies: tinyrainbow "^1.2.0" -"@vitest/runner@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.1.tgz#f3b1fbc3c109fc44e2cceecc881344453f275559" - integrity sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA== +"@vitest/runner@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.1.3.tgz#20a6da112007dfd92969951df189c6da66c9dac4" + integrity sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ== dependencies: - "@vitest/utils" "2.1.1" + "@vitest/utils" "2.1.3" pathe "^1.1.2" -"@vitest/snapshot@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.1.tgz#38ef23104e90231fea5540754a19d8468afbba66" - integrity sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw== +"@vitest/snapshot@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.1.3.tgz#1b405a9c40a82563605b13fdc045217751069e58" + integrity sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg== dependencies: - "@vitest/pretty-format" "2.1.1" + "@vitest/pretty-format" "2.1.3" magic-string "^0.30.11" pathe "^1.1.2" -"@vitest/spy@2.1.1", "@vitest/spy@^2.1.0-beta.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.1.tgz#20891f7421a994256ea0d739ed72f05532c78488" - integrity sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g== +"@vitest/spy@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.1.3.tgz#2c8a457673094ec4c1ab7c50cb11c58e3624ada2" + integrity sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ== dependencies: tinyspy "^3.0.0" -"@vitest/utils@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.1.tgz#284d016449ecb4f8704d198d049fde8360cc136e" - integrity sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ== +"@vitest/utils@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.1.3.tgz#e52aa5745384091b151cbdf79bb5a3ad2bea88d2" + integrity sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA== dependencies: - "@vitest/pretty-format" "2.1.1" + "@vitest/pretty-format" "2.1.3" loupe "^3.1.1" tinyrainbow "^1.2.0" @@ -862,7 +1023,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: +acorn@^8.12.0: version "8.12.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== @@ -1155,6 +1316,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -1682,17 +1850,17 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -css-functions-list@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.2.tgz#9a54c6dd8416ed25c1079cd88234e927526c1922" - integrity sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ== +css-functions-list@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.3.tgz#95652b0c24f0f59b291a9fc386041a19d4f40dbe" + integrity sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA== -css-tree@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" - integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== +css-tree@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.0.0.tgz#079c7b87e465a28cedbc826502f9a227213db0f3" + integrity sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw== dependencies: - mdn-data "2.0.30" + mdn-data "2.10.0" source-map-js "^1.0.1" cssesc@^3.0.0: @@ -1700,12 +1868,12 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cypress@13.14.2: - version "13.14.2" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.14.2.tgz#4237eb7b26de2baeaa1f01e585f965d88fca7f39" - integrity sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA== +cypress@13.15.0: + version "13.15.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.15.0.tgz#5eca5387ef34b2e611cfa291967c69c2cd39381d" + integrity sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw== dependencies: - "@cypress/request" "^3.0.1" + "@cypress/request" "^3.0.4" "@cypress/xvfb" "^1.2.4" "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" @@ -1802,7 +1970,7 @@ dayjs@^1.10.4: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== -debug@4.3.7, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@~4.3.6: +debug@4.3.7, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7, debug@~4.3.6: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -1891,13 +2059,6 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -2074,35 +2235,35 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -esbuild@0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.1.tgz#40fdc3f9265ec0beae6f59824ade1bd3d3d2dab8" - integrity sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg== +esbuild@0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.24.0.tgz#f2d470596885fcb2e91c21eb3da3b3c89c0b55e7" + integrity sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ== optionalDependencies: - "@esbuild/aix-ppc64" "0.23.1" - "@esbuild/android-arm" "0.23.1" - "@esbuild/android-arm64" "0.23.1" - "@esbuild/android-x64" "0.23.1" - "@esbuild/darwin-arm64" "0.23.1" - "@esbuild/darwin-x64" "0.23.1" - "@esbuild/freebsd-arm64" "0.23.1" - "@esbuild/freebsd-x64" "0.23.1" - "@esbuild/linux-arm" "0.23.1" - "@esbuild/linux-arm64" "0.23.1" - "@esbuild/linux-ia32" "0.23.1" - "@esbuild/linux-loong64" "0.23.1" - "@esbuild/linux-mips64el" "0.23.1" - "@esbuild/linux-ppc64" "0.23.1" - "@esbuild/linux-riscv64" "0.23.1" - "@esbuild/linux-s390x" "0.23.1" - "@esbuild/linux-x64" "0.23.1" - "@esbuild/netbsd-x64" "0.23.1" - "@esbuild/openbsd-arm64" "0.23.1" - "@esbuild/openbsd-x64" "0.23.1" - "@esbuild/sunos-x64" "0.23.1" - "@esbuild/win32-arm64" "0.23.1" - "@esbuild/win32-ia32" "0.23.1" - "@esbuild/win32-x64" "0.23.1" + "@esbuild/aix-ppc64" "0.24.0" + "@esbuild/android-arm" "0.24.0" + "@esbuild/android-arm64" "0.24.0" + "@esbuild/android-x64" "0.24.0" + "@esbuild/darwin-arm64" "0.24.0" + "@esbuild/darwin-x64" "0.24.0" + "@esbuild/freebsd-arm64" "0.24.0" + "@esbuild/freebsd-x64" "0.24.0" + "@esbuild/linux-arm" "0.24.0" + "@esbuild/linux-arm64" "0.24.0" + "@esbuild/linux-ia32" "0.24.0" + "@esbuild/linux-loong64" "0.24.0" + "@esbuild/linux-mips64el" "0.24.0" + "@esbuild/linux-ppc64" "0.24.0" + "@esbuild/linux-riscv64" "0.24.0" + "@esbuild/linux-s390x" "0.24.0" + "@esbuild/linux-x64" "0.24.0" + "@esbuild/netbsd-x64" "0.24.0" + "@esbuild/openbsd-arm64" "0.24.0" + "@esbuild/openbsd-x64" "0.24.0" + "@esbuild/sunos-x64" "0.24.0" + "@esbuild/win32-arm64" "0.24.0" + "@esbuild/win32-ia32" "0.24.0" + "@esbuild/win32-x64" "0.24.0" esbuild@^0.21.3: version "0.21.5" @@ -2177,24 +2338,24 @@ eslint-import-resolver-node@^0.3.9: is-core-module "^2.13.0" resolve "^1.22.4" -eslint-module-utils@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz#b99b211ca4318243f09661fae088f373ad5243c4" - integrity sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ== +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" -eslint-plugin-cypress@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-3.5.0.tgz#380ef5049ad80ebeca923db69e4aa96e72fcd893" - integrity sha512-JZQ6XnBTNI8h1B9M7wJSFzc48SYbh7VMMKaNTQOFa3BQlnmXPrVc4PKen8R+fpv6VleiPeej6VxloGb42zdRvw== +eslint-plugin-cypress@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-4.0.0.tgz#e4333e635808ec28ec04f598ec02d42b2bf253a5" + integrity sha512-KRzI4zxoOKMhWKRxcikRu/Vjsomnx1vXJEY2CTG+4oluFbXxGuyRC1CLlhmBVOK5/iR17vY7rzuyRbpcx5zEPA== dependencies: - globals "^13.20.0" + globals "^15.11.0" -eslint-plugin-import@2.30.0: - version "2.30.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449" - integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw== +eslint-plugin-import@2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== dependencies: "@rtsao/scc" "^1.1.0" array-includes "^3.1.8" @@ -2204,7 +2365,7 @@ eslint-plugin-import@2.30.0: debug "^3.2.7" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.9.0" + eslint-module-utils "^2.12.0" hasown "^2.0.2" is-core-module "^2.15.1" is-glob "^4.0.3" @@ -2213,8 +2374,19 @@ eslint-plugin-import@2.30.0: 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" +eslint-plugin-perfectionist@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-3.8.0.tgz#943c1c9ef79517e671cb241b16d247e72ee2c70d" + integrity sha512-BYJWbQVOjvIGK9V1xUfn790HuvkePjxti8epOi1H6sdzo0N4RehBmQ8coHPbgA/f12BUG1NIoDtQhI9mUm+o2A== + dependencies: + "@typescript-eslint/types" "^8.8.0" + "@typescript-eslint/utils" "^8.8.0" + minimatch "^9.0.5" + natural-compare-lite "^1.4.0" + eslint-plugin-prettier@5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95" @@ -2223,78 +2395,80 @@ eslint-plugin-prettier@5.2.1: prettier-linter-helpers "^1.0.0" synckit "^0.9.1" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" + integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@8: - version "8.57.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" - integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== +eslint-visitor-keys@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" + integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== + +eslint@9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" + integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== 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" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.12.0" + "@eslint/plugin-kit" "^0.2.0" + "@humanfs/node" "^0.16.5" "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" + "@humanwhocodes/retry" "^0.3.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" 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" + eslint-scope "^8.1.0" + eslint-visitor-keys "^4.1.0" + espree "^10.2.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" 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" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^10.0.1, espree@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" + integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== dependencies: - acorn "^8.9.0" + acorn "^8.12.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^4.1.0" esprima@^1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" integrity sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ== -esquery@^1.4.2: +esquery@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== @@ -2503,14 +2677,14 @@ figures@^3.1.0, figures@^3.2.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" -file-entry-cache@^9.0.0: +file-entry-cache@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-9.1.0.tgz#2e66ad98ce93f49aed1b178c57b0b5741591e075" integrity sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg== @@ -2575,14 +2749,13 @@ fixpack@4.0.0: extend-object "^1.0.0" rc "^1.2.8" -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" + keyv "^4.5.4" flat-cache@^5.0.0: version "5.0.0" @@ -2815,7 +2988,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.0.0, glob@^7.1.3: +glob@^7.0.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2857,12 +3030,15 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -globals@^13.19.0, globals@^13.20.0: - version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^15.11.0: + version "15.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e" + integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw== globalthis@^1.0.3: version "1.0.4" @@ -3029,11 +3205,16 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.2.0, ignore@^5.3.2: +ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +ignore@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-6.0.2.tgz#77cccb72a55796af1b6d2f9eb14fa326d24f4283" + integrity sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A== + import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -3224,7 +3405,7 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-path-inside@^3.0.2, is-path-inside@^3.0.3: +is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -3483,7 +3664,7 @@ jsts@2.11.3: dependencies: fastpriorityqueue "^0.7.5" -keyv@^4.5.3, keyv@^4.5.4: +keyv@^4.5.4: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== @@ -3793,10 +3974,10 @@ mathml-tag-names@^2.1.3: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -mdn-data@2.0.30: - version "2.0.30" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" - integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== +mdn-data@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.10.0.tgz#701da407f8fbc7a42aa0ba0c149ec897daef8986" + integrity sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw== mdurl@^2.0.0: version "2.0.0" @@ -3880,13 +4061,20 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -3921,6 +4109,11 @@ nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4027,12 +4220,12 @@ object.values@^1.2.0: define-properties "^1.2.1" es-object-atoms "^1.0.0" -ol@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/ol/-/ol-10.1.0.tgz#f163fc57585c454c149a87f201c207fe642d2f46" - integrity sha512-/efepydpzhFoeczA9KAN5t7G0WpFhP46ZXEfSl6JbZ7ipQZ2axpkYB2qt0qcOUlPFYMt7/XQFApH652KB08tTg== +ol@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/ol/-/ol-10.2.1.tgz#05143d0bbc0d8761385e0acae4ec9074a570bf64" + integrity sha512-2bB/y2vEnmzjqynP0NA7Cp8k86No3Psn63Dueicep3E3i09axWRVIG5IS/bylEAGfWQx0QXD/uljkyFoY60Wig== dependencies: - "@types/rbush" "^3.0.3" + "@types/rbush" "3.0.3" color-rgba "^3.0.0" color-space "^2.0.1" earcut "^3.0.0" @@ -4316,10 +4509,10 @@ postcss-resolve-nested-selector@^0.1.6: resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz#3d84dec809f34de020372c41b039956966896686" integrity sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw== -postcss-safe-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz#6273d4e5149e286db5a45bc6cf6eafcad464014a" - integrity sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg== +postcss-safe-parser@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz#36e4f7e608111a0ca940fd9712ce034718c40ec0" + integrity sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A== postcss-selector-parser@^6.1.2: version "6.1.2" @@ -4334,7 +4527,7 @@ postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.41, postcss@^8.4.43: +postcss@^8.4.43, postcss@^8.4.47: version "8.4.47" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== @@ -4638,13 +4831,6 @@ rfdc@^1.3.0, rfdc@^1.4.1: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rollup@^4.20.0: version "4.21.3" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.3.tgz#c64ba119e6aeb913798a6f7eef2780a0df5a0821" @@ -5104,10 +5290,10 @@ stylelint-config-standard@36.0.1: dependencies: stylelint-config-recommended "^14.0.1" -stylelint@16.9.0: - version "16.9.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.9.0.tgz#81615c0608b9dc645486e08e35c6c9206e1ba132" - integrity sha512-31Nm3WjxGOBGpQqF43o3wO9L5AC36TPIe6030Lnm13H3vDMTcS21DrLh69bMX+DBilKqMMVLian4iG6ybBoNRQ== +stylelint@16.10.0: + version "16.10.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.10.0.tgz#452b42a5d82f2ad910954eb2ba2b3a2ec583cd75" + integrity sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ== dependencies: "@csstools/css-parser-algorithms" "^3.0.1" "@csstools/css-tokenizer" "^3.0.1" @@ -5117,17 +5303,17 @@ stylelint@16.9.0: balanced-match "^2.0.0" colord "^2.9.3" cosmiconfig "^9.0.0" - css-functions-list "^3.2.2" - css-tree "^2.3.1" - debug "^4.3.6" + css-functions-list "^3.2.3" + css-tree "^3.0.0" + debug "^4.3.7" fast-glob "^3.3.2" fastest-levenshtein "^1.0.16" - file-entry-cache "^9.0.0" + file-entry-cache "^9.1.0" global-modules "^2.0.0" globby "^11.1.0" globjoin "^0.1.4" html-tags "^3.3.1" - ignore "^5.3.2" + ignore "^6.0.2" imurmurhash "^0.1.4" is-plain-object "^5.0.0" known-css-properties "^0.34.0" @@ -5136,14 +5322,13 @@ stylelint@16.9.0: micromatch "^4.0.8" normalize-path "^3.0.0" picocolors "^1.0.1" - postcss "^8.4.41" + postcss "^8.4.47" postcss-resolve-nested-selector "^0.1.6" - postcss-safe-parser "^7.0.0" + postcss-safe-parser "^7.0.1" postcss-selector-parser "^6.1.2" postcss-value-parser "^4.2.0" resolve-from "^5.0.0" string-width "^4.2.3" - strip-ansi "^7.1.0" supports-hyperlinks "^3.1.0" svg-tags "^1.0.0" table "^6.8.2" @@ -5304,6 +5489,11 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -5343,11 +5533,6 @@ type-fest@^0.18.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -5412,10 +5597,19 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@5.6.2: - version "5.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.2.tgz#d1de67b6bef77c41823f822df8f0b3bcff60a5a0" - integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== +typescript-eslint@^8.9.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.9.0.tgz#20a9b8125c57f3de962080ebebf366697f75bf79" + integrity sha512-AuD/FXGYRQyqyOBCpNLldMlsCGvmDNxptQ3Dp58/NXeB+FqyvTfXmMyba3PYa0Vi9ybnj7G8S/yd/4Cw8y47eA== + dependencies: + "@typescript-eslint/eslint-plugin" "8.9.0" + "@typescript-eslint/parser" "8.9.0" + "@typescript-eslint/utils" "8.9.0" + +typescript@5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== uc.micro@^2.0.0, uc.micro@^2.1.0: version "2.1.0" @@ -5509,10 +5703,10 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vite-node@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.1.tgz#7d46f623c04dfed6df34e7127711508a3386fa1c" - integrity sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA== +vite-node@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.1.3.tgz#8291d31f91c69dc22fea7909f4394c2b3cc2e2d9" + integrity sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA== dependencies: cac "^6.7.14" debug "^4.3.6" @@ -5530,18 +5724,18 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vitest@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.1.tgz#24a6f6f5d894509f10685b82de008c507faacbb1" - integrity sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA== - dependencies: - "@vitest/expect" "2.1.1" - "@vitest/mocker" "2.1.1" - "@vitest/pretty-format" "^2.1.1" - "@vitest/runner" "2.1.1" - "@vitest/snapshot" "2.1.1" - "@vitest/spy" "2.1.1" - "@vitest/utils" "2.1.1" +vitest@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.1.3.tgz#dae1055dd328621b59fc6e594fd988fbf2e5370e" + integrity sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA== + dependencies: + "@vitest/expect" "2.1.3" + "@vitest/mocker" "2.1.3" + "@vitest/pretty-format" "^2.1.3" + "@vitest/runner" "2.1.3" + "@vitest/snapshot" "2.1.3" + "@vitest/spy" "2.1.3" + "@vitest/utils" "2.1.3" chai "^5.1.1" debug "^4.3.6" magic-string "^0.30.11" @@ -5552,7 +5746,7 @@ vitest@^2.1.1: tinypool "^1.0.0" tinyrainbow "^1.2.0" vite "^5.0.0" - vite-node "2.1.1" + vite-node "2.1.3" why-is-node-running "^2.3.0" wait-on@8.0.1: