From 3d710ba4cbafdcc2e6c7dfe0f926a6bf67b5ccac Mon Sep 17 00:00:00 2001 From: Alexander Vogt Date: Tue, 4 Mar 2025 07:49:29 +0100 Subject: [PATCH 1/7] add eslint config --- eslint.config.mjs | 35 + package-lock.json | 2179 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 6 + 3 files changed, 2191 insertions(+), 29 deletions(-) create mode 100644 eslint.config.mjs diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..4ca975a --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,35 @@ +import js from '@eslint/js' +import tseslint from 'typescript-eslint' +import eslintConfigPrettier from 'eslint-config-prettier' + +export default [ + js.configs.recommended, + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + ignores: ['**/*.config.ts', 'node_modules/**', 'dist/**'] + }, + { + files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + parser: tseslint.parser, + parserOptions: { + ecmaFeatures: { + jsx: true + } + } + }, + rules: { + 'no-console': ['error', { allow: ['warn', 'error', 'info'] }], + 'no-restricted-exports': ['error', { restrictDefaultExports: { direct: true } }], + } + }, + { + files: ['**/*.config.ts', '**/*.config.js', '**/*.d.ts'], + rules: { + 'no-restricted-exports': 'off' + } + }, +] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0d2e096..3f963ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,12 @@ "name": "data-flow-analysis-web-editor", "version": "0.1.0", "devDependencies": { + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.20.0", "@fortawesome/fontawesome-free": "^6.7.2", "@vscode/codicons": "^0.0.36", + "eslint": "^9.21.0", + "eslint-config-prettier": "^10.0.2", "husky": "^9.1.7", "inversify": "^6.2.2", "lint-staged": "^15.4.3", @@ -20,6 +24,7 @@ "sprotty-elk": "^1.4.0", "sprotty-protocol": "^1.4.0", "typescript": "^5.7.3", + "typescript-eslint": "^8.25.0", "vite": "^6.1.0" } }, @@ -448,6 +453,125 @@ "node": ">=18" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "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" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", + "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dev": true, + "dependencies": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@fortawesome/fontawesome-free": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", @@ -458,6 +582,67 @@ "node": ">=6" } }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@inversifyjs/common": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@inversifyjs/common/-/common-1.4.0.tgz", @@ -553,6 +738,41 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.32.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz", @@ -826,6 +1046,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/node": { "version": "20.1.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz", @@ -834,6 +1060,202 @@ "optional": true, "peer": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz", + "integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/type-utils": "8.26.0", + "@typescript-eslint/utils": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz", + "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", + "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz", + "integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/utils": "8.26.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz", + "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", + "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.0.tgz", + "integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", + "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.26.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@vscode/codicons": { "version": "0.0.36", "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.36.tgz", @@ -842,12 +1264,10 @@ "license": "CC-BY-4.0" }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, - "optional": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -855,6 +1275,31 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-escapes": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", @@ -897,12 +1342,34 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/autocompleter": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-9.3.2.tgz", "integrity": "sha512-rLbf2TLGOD7y+gOS36ksrZdIsvoHa2KXc2A7503w+NBRPrcF73zzFeYBxEcV/iMPjaBH3jFhNIYObZ7zt1fkCQ==", "dev": true }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -924,6 +1391,15 @@ "optional": true, "peer": true }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", @@ -970,6 +1446,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -985,10 +1479,16 @@ "optional": true, "peer": true }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -1017,6 +1517,12 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/elkjs": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", @@ -1084,6 +1590,207 @@ "@esbuild/win32-x64": "0.24.2" } }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz", + "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.21.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz", + "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==", + "dev": true, + "bin": { + "eslint-config-prettier": "build/bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -1114,6 +1821,73 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/file-saver": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", @@ -1133,6 +1907,41 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1173,6 +1982,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -1198,6 +2046,40 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inversify": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.2.2.tgz", @@ -1212,6 +2094,15 @@ "reflect-metadata": "~0.2.2" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", @@ -1225,6 +2116,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1253,6 +2156,58 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -1322,6 +2277,27 @@ "node": ">=18.0.0" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -1381,6 +2357,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -1416,8 +2401,20 @@ "engines": { "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/monaco-editor": { @@ -1452,6 +2449,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -1494,6 +2497,74 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1564,6 +2635,15 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prettier": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", @@ -1580,6 +2660,35 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -1587,6 +2696,15 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -1620,6 +2738,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -1666,6 +2794,41 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1847,6 +3010,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/terser": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", @@ -1886,6 +3073,30 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "dev": true, + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", @@ -1900,6 +3111,37 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.26.0.tgz", + "integrity": "sha512-PtVz9nAnuNJuAVeUFvwztjuUgSnJInODAUx47VDwWPXzd5vismPOtPtt83tzNXyOjVQbPRp786D6WFW/M2koIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.26.0", + "@typescript-eslint/parser": "8.26.0", + "@typescript-eslint/utils": "8.26.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/vite": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz", @@ -1987,6 +3229,15 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -2017,6 +3268,18 @@ "engines": { "node": ">= 14" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { @@ -2195,12 +3458,130 @@ "dev": true, "optional": true }, + "@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.4.3" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + } + } + }, + "@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true + }, + "@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "requires": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + } + }, + "@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.15" + } + }, + "@eslint/eslintrc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", + "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "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": { + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", + "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==", + "dev": true + }, + "@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true + }, + "@eslint/plugin-kit": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dev": true, + "requires": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + } + }, "@fortawesome/fontawesome-free": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==", "dev": true }, + "@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true + }, + "@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "requires": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "dependencies": { + "@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true + }, "@inversifyjs/common": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@inversifyjs/common/-/common-1.4.0.tgz", @@ -2285,6 +3666,32 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, "@rollup/rollup-android-arm-eabi": { "version": "4.32.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz", @@ -2418,19 +3825,141 @@ "dev": true, "optional": true }, - "@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "@types/node": { + "version": "20.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz", + "integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==", + "dev": true, + "optional": true, + "peer": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz", + "integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/type-utils": "8.26.0", + "@typescript-eslint/utils": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + } + }, + "@typescript-eslint/parser": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz", + "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", + "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz", + "integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "8.26.0", + "@typescript-eslint/utils": "8.26.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + } + }, + "@typescript-eslint/types": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz", + "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", + "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/visitor-keys": "8.26.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.0.tgz", + "integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.26.0", + "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.0" + } }, - "@types/node": { - "version": "20.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz", - "integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==", + "@typescript-eslint/visitor-keys": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", + "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", "dev": true, - "optional": true, - "peer": true + "requires": { + "@typescript-eslint/types": "8.26.0", + "eslint-visitor-keys": "^4.2.0" + } }, "@vscode/codicons": { "version": "0.0.36", @@ -2439,12 +3968,29 @@ "dev": true }, "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "optional": true, - "peer": true + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } }, "ansi-escapes": { "version": "7.0.0", @@ -2467,12 +4013,34 @@ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "autocompleter": { "version": "9.3.2", "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-9.3.2.tgz", "integrity": "sha512-rLbf2TLGOD7y+gOS36ksrZdIsvoHa2KXc2A7503w+NBRPrcF73zzFeYBxEcV/iMPjaBH3jFhNIYObZ7zt1fkCQ==", "dev": true }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -2490,6 +4058,12 @@ "optional": true, "peer": true }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "chalk": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", @@ -2515,6 +4089,21 @@ "string-width": "^7.0.0" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -2529,10 +4118,16 @@ "optional": true, "peer": true }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -2549,6 +4144,12 @@ "ms": "^2.1.3" } }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "elkjs": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", @@ -2600,6 +4201,139 @@ "@esbuild/win32-x64": "0.24.2" } }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "9.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz", + "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.0", + "@eslint/js": "9.21.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz", + "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true + }, + "espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "requires": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + } + }, + "esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -2623,6 +4357,66 @@ "strip-final-newline": "^3.0.0" } }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "requires": { + "flat-cache": "^4.0.0" + } + }, "file-saver": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", @@ -2638,6 +4432,32 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + } + }, + "flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, "fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2657,6 +4477,33 @@ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "human-signals": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", @@ -2669,6 +4516,28 @@ "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, "inversify": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.2.2.tgz", @@ -2679,12 +4548,27 @@ "@inversifyjs/core": "1.3.5" } }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, "is-fullwidth-code-point": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2703,6 +4587,52 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -2749,6 +4679,21 @@ "wrap-ansi": "^9.0.0" } }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -2789,6 +4734,12 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -2811,6 +4762,15 @@ "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "monaco-editor": { "version": "0.45.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.45.0.tgz", @@ -2829,6 +4789,12 @@ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "npm-run-path": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", @@ -2855,6 +4821,53 @@ "mimic-fn": "^4.0.0" } }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2890,18 +4903,42 @@ "source-map-js": "^1.2.1" } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "prettier": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", "integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", "dev": true }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", "dev": true }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -2923,6 +4960,12 @@ } } }, + "reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true + }, "rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -2958,6 +5001,21 @@ "fsevents": "~2.3.2" } }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3084,6 +5142,21 @@ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "terser": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", @@ -3113,12 +5186,48 @@ "is-number": "^7.0.0" } }, + "ts-api-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", + "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "dev": true, + "requires": {} + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, "typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true }, + "typescript-eslint": { + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.26.0.tgz", + "integrity": "sha512-PtVz9nAnuNJuAVeUFvwztjuUgSnJInODAUx47VDwWPXzd5vismPOtPtt83tzNXyOjVQbPRp786D6WFW/M2koIA==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "8.26.0", + "@typescript-eslint/parser": "8.26.0", + "@typescript-eslint/utils": "8.26.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "vite": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz", @@ -3140,6 +5249,12 @@ "isexe": "^2.0.0" } }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, "wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -3156,6 +5271,12 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 14988c3..7397a2e 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,12 @@ "url": "https://github.com/DataFlowAnalysis/WebEditor.git" }, "devDependencies": { + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.20.0", "@fortawesome/fontawesome-free": "^6.7.2", "@vscode/codicons": "^0.0.36", + "eslint": "^9.21.0", + "eslint-config-prettier": "^10.0.2", "husky": "^9.1.7", "inversify": "^6.2.2", "lint-staged": "^15.4.3", @@ -19,6 +23,7 @@ "sprotty-elk": "^1.4.0", "sprotty-protocol": "^1.4.0", "typescript": "^5.7.3", + "typescript-eslint": "^8.25.0", "vite": "^6.1.0" }, "scripts": { @@ -26,6 +31,7 @@ "build": "tsc && vite build", "preview": "vite preview", "format": "prettier --write \"./**/*.{html,css,ts,tsx,json,yaml,md}\"", + "lint": "eslint --max-warnings 0", "prepare": "husky" }, "lint-staged": { From 216e68a110b2daf74292b3a098f98d85007b9607 Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Mon, 31 Mar 2025 12:47:51 +0200 Subject: [PATCH 2/7] fix lint errors --- eslint.config.mjs | 4 +++- src/common/commandPalette.ts | 8 +------- src/features/autoLayout/layouter.ts | 4 ++-- src/features/constraintMenu/AutoCompletion.ts | 8 ++++---- src/features/constraintMenu/ConstraintMenu.ts | 2 +- src/features/constraintMenu/DslLanguage.ts | 8 ++++---- src/features/copyPaste/keyListener.ts | 2 +- src/features/dfdElements/behaviorRefactorer.ts | 3 +++ src/features/dfdElements/edges.tsx | 3 ++- src/features/dfdElements/labels.tsx | 1 + src/features/dfdElements/nodeAnnotationUi.ts | 1 - src/features/dfdElements/nodes.tsx | 1 + .../dfdElements/outputPortBehaviorValidation.ts | 12 ++++-------- src/features/dfdElements/outputPortEditUi.ts | 17 ++++++++++------- src/features/dfdElements/portSnapper.ts | 1 - src/features/dfdElements/ports.tsx | 3 ++- src/features/labels/labelRenderer.tsx | 1 + src/features/labels/labelTypeEditor.ts | 2 +- src/features/serialize/load.ts | 8 ++------ src/features/serialize/loadDFDandDD.ts | 8 ++++++-- src/features/serialize/loadPalladio.ts | 12 +++++++----- src/features/serialize/webSocketHandler.ts | 12 ++++++------ src/features/toolPalette/creationTool.ts | 1 + src/features/toolPalette/toolPalette.tsx | 3 ++- src/index.ts | 6 ++++-- 25 files changed, 69 insertions(+), 62 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 4ca975a..45f424e 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -22,8 +22,10 @@ export default [ } }, rules: { - 'no-console': ['error', { allow: ['warn', 'error', 'info'] }], + 'no-console': 'error', 'no-restricted-exports': ['error', { restrictDefaultExports: { direct: true } }], + // used multiple times to stay consistent with sprotty + '@typescript-eslint/no-namespace': 'off', } }, { diff --git a/src/common/commandPalette.ts b/src/common/commandPalette.ts index 3478f44..8afca70 100644 --- a/src/common/commandPalette.ts +++ b/src/common/commandPalette.ts @@ -1,6 +1,5 @@ import { injectable } from "inversify"; import { ICommandPaletteActionProvider, LabeledAction, SModelRootImpl, CommitModelAction } from "sprotty"; -import { Point } from "sprotty-protocol"; import { LoadDiagramAction } from "../features/serialize/load"; import { createDefaultFitToScreenAction } from "../utils"; import { SaveDiagramAction } from "../features/serialize/save"; @@ -19,12 +18,7 @@ import { LoadPalladioAction } from "../features/serialize/loadPalladio"; */ @injectable() export class ServerCommandPaletteActionProvider implements ICommandPaletteActionProvider { - async getActions( - root: Readonly, - _text: string, - _lastMousePosition?: Point, - _index?: number, - ): Promise { + async getActions(root: Readonly): Promise { const fitToScreenAction = createDefaultFitToScreenAction(root); const commitAction = CommitModelAction.create(); diff --git a/src/features/autoLayout/layouter.ts b/src/features/autoLayout/layouter.ts index cc8c461..a3fb8db 100644 --- a/src/features/autoLayout/layouter.ts +++ b/src/features/autoLayout/layouter.ts @@ -8,11 +8,11 @@ import { ILayoutConfigurator, } from "sprotty-elk"; import { SChildElementImpl, SShapeElementImpl, isBoundsAware } from "sprotty"; -import { SShapeElement, SGraph, SModelIndex } from "sprotty-protocol"; +import { SShapeElement, SModelIndex } from "sprotty-protocol"; import { ElkShape, LayoutOptions } from "elkjs"; export class DfdLayoutConfigurator extends DefaultLayoutConfigurator { - protected override graphOptions(_sgraph: SGraph, _index: SModelIndex): LayoutOptions { + protected override graphOptions(): LayoutOptions { // Elk settings. See https://eclipse.dev/elk/reference.html for available options. return { "org.eclipse.elk.algorithm": "org.eclipse.elk.layered", diff --git a/src/features/constraintMenu/AutoCompletion.ts b/src/features/constraintMenu/AutoCompletion.ts index c039b62..a5df409 100644 --- a/src/features/constraintMenu/AutoCompletion.ts +++ b/src/features/constraintMenu/AutoCompletion.ts @@ -43,7 +43,7 @@ export class ConstantWord implements AbstractWord { } } - completionOptions(_: string): WordCompletion[] { + completionOptions(): WordCompletion[] { return [ { insertText: this.word, @@ -54,7 +54,7 @@ export class ConstantWord implements AbstractWord { } export class AnyWord implements AbstractWord { - completionOptions(_: string): WordCompletion[] { + completionOptions(): WordCompletion[] { return []; } verifyWord(word: string): string[] { @@ -110,7 +110,7 @@ export class AutoCompleteTree { return; } this.content = line.split(" "); - this.startColumns = this.content.map((_) => 0); + this.startColumns = this.content.map(() => 0); for (let i = 1; i < this.content.length; i++) { this.startColumns[i] = this.startColumns[i - 1] + this.content[i - 1].length + 1; } @@ -134,7 +134,7 @@ export class AutoCompleteTree { } } - let foundErrors: ValidationError[] = []; + const foundErrors: ValidationError[] = []; let childErrors: ValidationError[] = []; for (const n of nodes) { const v = n.word.verifyWord(this.content[index]); diff --git a/src/features/constraintMenu/ConstraintMenu.ts b/src/features/constraintMenu/ConstraintMenu.ts index 1f9b884..f515aa5 100644 --- a/src/features/constraintMenu/ConstraintMenu.ts +++ b/src/features/constraintMenu/ConstraintMenu.ts @@ -44,7 +44,7 @@ export class ConstraintMenu extends AbstractUIExtension implements Switchable { this.constraintRegistry = constraintRegistry; this.tree = new AutoCompleteTree(TreeBuilder.buildTree(modelSource, labelTypeRegistry)); this.forceReadOnly = editorModeController?.getCurrentMode() !== "edit"; - editorModeController?.onModeChange((_) => { + editorModeController?.onModeChange(() => { this.forceReadOnly = editorModeController!.isReadOnly(); }); } diff --git a/src/features/constraintMenu/DslLanguage.ts b/src/features/constraintMenu/DslLanguage.ts index 26a9d79..531b09c 100644 --- a/src/features/constraintMenu/DslLanguage.ts +++ b/src/features/constraintMenu/DslLanguage.ts @@ -35,7 +35,7 @@ export class MonacoEditorConstraintDslCompletionProvider implements monaco.langu export const constraintDslLanguageMonarchDefinition: monaco.languages.IMonarchLanguage = { keywords: ["data", "vertex", "neverFlows", "to", "where", "named", "present", "empty", "type"], - symbols: /[=> 2) { return []; } - return this.constraintVariableReference.completionOptions(attributes[attributes.length - 1]); + return this.constraintVariableReference.completionOptions(); } verifyWord(word: string): string[] { if (!word.startsWith("intersection(")) { @@ -303,7 +303,7 @@ export namespace TreeBuilder { class VariableName implements AbstractWord { constructor(private readonly modelSource: LocalModelSource) {} - completionOptions(_: string): WordCompletion[] { + completionOptions(): WordCompletion[] { return this.getAllPortNames().map((n) => ({ insertText: n, kind: monaco.languages.CompletionItemKind.Variable, diff --git a/src/features/copyPaste/keyListener.ts b/src/features/copyPaste/keyListener.ts index b62e944..1d70f51 100644 --- a/src/features/copyPaste/keyListener.ts +++ b/src/features/copyPaste/keyListener.ts @@ -23,7 +23,7 @@ export class CopyPasteKeyListener implements KeyListener { constructor(@inject(MousePositionTracker) private readonly mousePositionTracker: MousePositionTracker) {} - keyUp(_element: SModelElementImpl, _event: KeyboardEvent): Action[] { + keyUp(): Action[] { return []; } diff --git a/src/features/dfdElements/behaviorRefactorer.ts b/src/features/dfdElements/behaviorRefactorer.ts index c8091b3..46c9f21 100644 --- a/src/features/dfdElements/behaviorRefactorer.ts +++ b/src/features/dfdElements/behaviorRefactorer.ts @@ -132,6 +132,7 @@ export class DFDBehaviorRefactorer { let newLine = line; changedLabelTypes.forEach((changedLabelType) => { newLine = newLine.replace( + // eslint-disable-next-line no-useless-escape new RegExp(`([^a-zA-Z0-9_])${changedLabelType.oldLabelType.name}(\.)`, "g"), `$1${changedLabelType.newLabelType.name}$2`, ); @@ -144,6 +145,7 @@ export class DFDBehaviorRefactorer { changedLabelValues.forEach((changedLabelValue) => { newLine = newLine.replace( new RegExp( + // eslint-disable-next-line no-useless-escape `([^a-zA-Z0-9_])${changedLabelValue.labelType.name}\.${changedLabelValue.oldLabelValue.text}([^a-zA-Z0-9_]|$)`, "g", ), @@ -201,6 +203,7 @@ export class DFDBehaviorRefactorer { // inside the input. We can use these two constraints to identify the input name // and only change inputs with that name. Label types/values with the same name are not replaced // because of these constraints. + // eslint-disable-next-line no-useless-escape return line.replace(new RegExp(`( )${oldInputName}(\.)`, "g"), `$1${newInputName}$2`); } else { // Idk what to do with this line, just return it as is diff --git a/src/features/dfdElements/edges.tsx b/src/features/dfdElements/edges.tsx index be91701..d81db60 100644 --- a/src/features/dfdElements/edges.tsx +++ b/src/features/dfdElements/edges.tsx @@ -3,6 +3,7 @@ import { injectable } from "inversify"; import { PolylineEdgeViewWithGapsOnIntersections, SEdgeImpl, + // eslint-disable-next-line @typescript-eslint/no-unused-vars svg, RenderingContext, IViewArgs, @@ -92,7 +93,7 @@ export class ArrowEdgeView extends PolylineEdgeViewWithGapsOnIntersections { * In contrast to the default implementation that we override here, * this implementation makes the edge line 10px shorter at the end to make space for the arrow without any overlap. */ - protected renderLine(edge: SEdgeImpl, segments: Point[], _context: RenderingContext, _args?: IViewArgs): VNode { + protected renderLine(edge: SEdgeImpl, segments: Point[]): VNode { const firstPoint = segments[0]; let path = `M ${firstPoint.x},${firstPoint.y}`; for (let i = 1; i < segments.length; i++) { diff --git a/src/features/dfdElements/labels.tsx b/src/features/dfdElements/labels.tsx index f30fdae..f7dec3c 100644 --- a/src/features/dfdElements/labels.tsx +++ b/src/features/dfdElements/labels.tsx @@ -1,4 +1,5 @@ /** @jsx svg */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars import { IViewArgs, SLabelImpl, SNodeImpl, ShapeView, RenderingContext, svg } from "sprotty"; import { VNode } from "snabbdom"; import { injectable } from "inversify"; diff --git a/src/features/dfdElements/nodeAnnotationUi.ts b/src/features/dfdElements/nodeAnnotationUi.ts index 0afe4ce..2cbd070 100644 --- a/src/features/dfdElements/nodeAnnotationUi.ts +++ b/src/features/dfdElements/nodeAnnotationUi.ts @@ -122,7 +122,6 @@ export class DfdNodeAnnotationUI extends AbstractUIExtension { // If mouse not in popup => hide const rect = containerElement.getBoundingClientRect(); - console.log(rect); if ( event.clientX < rect.left || event.clientX > rect.right || diff --git a/src/features/dfdElements/nodes.tsx b/src/features/dfdElements/nodes.tsx index a11c019..30d1c1e 100644 --- a/src/features/dfdElements/nodes.tsx +++ b/src/features/dfdElements/nodes.tsx @@ -3,6 +3,7 @@ import { SNodeImpl, WithEditableLabel, isEditableLabel, + // eslint-disable-next-line @typescript-eslint/no-unused-vars svg, withEditLabelFeature, RenderingContext, diff --git a/src/features/dfdElements/outputPortBehaviorValidation.ts b/src/features/dfdElements/outputPortBehaviorValidation.ts index bf44e94..acdf2fb 100644 --- a/src/features/dfdElements/outputPortBehaviorValidation.ts +++ b/src/features/dfdElements/outputPortBehaviorValidation.ts @@ -21,7 +21,7 @@ interface PortBehaviorValidationError { @injectable() export class PortBehaviorValidator { // RegEx validating names of input pins - private static readonly INPUT_LABEL_REGEX = /[A-Za-z0-9_~][A-Za-z0-9_~\|]+/; + private static readonly INPUT_LABEL_REGEX = /[A-Za-z0-9_~][A-Za-z0-9_~|]+/; // RegEx validating names of output labels private static readonly OUTPUT_LABEL_REGEX = /[A-Za-z0-9_]+\.[A-Za-z0-9_]+/; @@ -58,7 +58,7 @@ export class PortBehaviorValidator { ); // Regex matching alphanumeric characters. - public static readonly REGEX_ALPHANUMERIC = /[A-Za-z0-9_\|]+/; + public static readonly REGEX_ALPHANUMERIC = /[A-Za-z0-9_|]+/; constructor(@inject(LabelTypeRegistry) @optional() private readonly labelTypeRegistry?: LabelTypeRegistry) {} @@ -362,7 +362,7 @@ export class PortBehaviorValidator { } // Extract all used inputs, label types and the corresponding label values. - let term = match[2]; + const term = match[2]; const termMatch = term.match(PortBehaviorValidator.TERM_REGEX); if (term == "" || !termMatch) { @@ -379,8 +379,6 @@ export class PortBehaviorValidator { ]; const inputAccessErrors = []; - console.log(matches); - for (const inputMatch of matches) { const inputLabelType = inputMatch[1]; const inputLabelValue = inputMatch[2]; @@ -434,8 +432,6 @@ export class PortBehaviorValidator { } } - console.log(inputMatch); - if (inputMatch[3] !== undefined) { inputAccessErrors.push({ line: lineNumber, @@ -458,7 +454,7 @@ export class PortBehaviorValidator { for (const inPortName of inPorts) { if (!availableInputs.includes(inPortName) && inPortName !== "") { // Find all occurrences of the unavailable input. - let idx = line.indexOf(inPortName); + const idx = line.indexOf(inPortName); inputAccessErrors.push({ line: lineNumber, message: `invalid/unknown input: ${inPortName}`, diff --git a/src/features/dfdElements/outputPortEditUi.ts b/src/features/dfdElements/outputPortEditUi.ts index 63980b2..47b6139 100644 --- a/src/features/dfdElements/outputPortEditUi.ts +++ b/src/features/dfdElements/outputPortEditUi.ts @@ -42,7 +42,7 @@ import { LightDarkSwitch, Switchable } from "../../common/lightDarkSwitch"; export class OutputPortEditUIMouseListener extends MouseListener { private editUIVisible = false; - mouseDown(target: SModelElementImpl, _event: MouseEvent): (Action | Promise)[] { + mouseDown(target: SModelElementImpl): (Action | Promise)[] { if (this.editUIVisible) { // The user has clicked somewhere on the sprotty diagram (not the port edit UI) // while the UI was open. In this case we hide the UI. @@ -64,7 +64,7 @@ export class OutputPortEditUIMouseListener extends MouseListener { return []; } - doubleClick(target: SModelElementImpl, _event: MouseEvent): (Action | Promise)[] { + doubleClick(target: SModelElementImpl): (Action | Promise)[] { if (target instanceof DfdOutputPortImpl) { // The user has double clicked on a dfd output port // => show the OutputPortEditUI for this port. @@ -91,13 +91,13 @@ const dfdBehaviorLanguageMonarchDefinition: monaco.languages.IMonarchLanguage = operators: ["=", "||", "&&", "!"], - symbols: /[=>)[] { + wheel(): (Action | Promise)[] { // Re-set position of the UI after next event loop tick. // In the current event loop tick the scoll is still processed and the // position of the port may change after the scroll processing, so we need to wait for that. diff --git a/src/features/dfdElements/portSnapper.ts b/src/features/dfdElements/portSnapper.ts index cee721e..520e6ad 100644 --- a/src/features/dfdElements/portSnapper.ts +++ b/src/features/dfdElements/portSnapper.ts @@ -3,7 +3,6 @@ import { CenterGridSnapper, Command, CommandExecutionContext, - ApplyLabelEditCommand, CommandReturn, ISnapper, MoveMouseListener, diff --git a/src/features/dfdElements/ports.tsx b/src/features/dfdElements/ports.tsx index 6d0f5e6..1ae8dc8 100644 --- a/src/features/dfdElements/ports.tsx +++ b/src/features/dfdElements/ports.tsx @@ -1,5 +1,6 @@ /** @jsx svg */ import { + // eslint-disable-next-line @typescript-eslint/no-unused-vars svg, ShapeView, SPortImpl, @@ -18,7 +19,7 @@ import { ArrowEdgeImpl } from "./edges"; const defaultPortFeatures = [...SPortImpl.DEFAULT_FEATURES, moveFeature, deletableFeature]; const portSize = 7; -export interface DfdInputPort extends SPort {} +export type DfdInputPort = SPort; @injectable() export class DfdInputPortImpl extends SPortImpl { diff --git a/src/features/labels/labelRenderer.tsx b/src/features/labels/labelRenderer.tsx index b79a346..e55d130 100644 --- a/src/features/labels/labelRenderer.tsx +++ b/src/features/labels/labelRenderer.tsx @@ -1,6 +1,7 @@ /** @jsx svg */ import { injectable, inject, optional } from "inversify"; import { VNode } from "snabbdom"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars import { IActionDispatcher, SNodeImpl, TYPES, svg } from "sprotty"; import { calculateTextSize } from "../../utils"; import { LabelAssignment, LabelTypeRegistry, globalLabelTypeRegistry } from "./labelTypeRegistry"; diff --git a/src/features/labels/labelTypeEditor.ts b/src/features/labels/labelTypeEditor.ts index 508d097..1eb3f8c 100644 --- a/src/features/labels/labelTypeEditor.ts +++ b/src/features/labels/labelTypeEditor.ts @@ -308,7 +308,7 @@ export class LabelTypeEditorUI extends AbstractUIExtension implements KeyListene return []; } - keyUp(_element: SModelElementImpl, _event: KeyboardEvent): Action[] { + keyUp(): Action[] { return []; } diff --git a/src/features/serialize/load.ts b/src/features/serialize/load.ts index 17fccb9..b401ae7 100644 --- a/src/features/serialize/load.ts +++ b/src/features/serialize/load.ts @@ -10,7 +10,7 @@ import { TYPES, isLocateable, } from "sprotty"; -import { Action, SModelRoot } from "sprotty-protocol"; +import { Action, SModelElement, SModelRoot } from "sprotty-protocol"; import { DynamicChildrenProcessor } from "../dfdElements/dynamicChildren"; import { inject, optional } from "inversify"; import { createDefaultFitToScreenAction } from "../../utils"; @@ -251,12 +251,8 @@ export class LoadDiagramCommand extends Command { * @param modelSchema The model schema to preprocess */ public static preprocessModelSchema(modelSchema: SModelRoot): void { - // These properties are all not included in the root typing. - "features" in modelSchema && delete modelSchema["features"]; - "canvasBounds" in modelSchema && delete modelSchema["canvasBounds"]; - if (modelSchema.children) { - modelSchema.children.forEach((child: any) => this.preprocessModelSchema(child)); + modelSchema.children.forEach((child: SModelElement) => this.preprocessModelSchema(child)); } } diff --git a/src/features/serialize/loadDFDandDD.ts b/src/features/serialize/loadDFDandDD.ts index a55f5db..09f5414 100644 --- a/src/features/serialize/loadDFDandDD.ts +++ b/src/features/serialize/loadDFDandDD.ts @@ -1,8 +1,9 @@ -import { Command, CommandExecutionContext, SModelRootImpl } from "sprotty"; +import { Command, CommandExecutionContext, ILogger, NullLogger, SModelRootImpl, TYPES } from "sprotty"; import { Action } from "sprotty-protocol"; import { sendMessage } from "./webSocketHandler"; import { setModelFileName } from "../../index"; import { setFileNameInPageTitle } from "./load"; +import { inject } from "inversify"; export interface LoadDFDandDDAction extends Action { kind: typeof LoadDFDandDDAction.KIND; @@ -22,6 +23,9 @@ export namespace LoadDFDandDDAction { export class LoadDFDandDDCommand extends Command { static readonly KIND = LoadDFDandDDAction.KIND; + @inject(TYPES.ILogger) + private readonly logger: ILogger = new NullLogger(); + constructor() { super(); } @@ -84,7 +88,7 @@ export class LoadDFDandDDCommand extends Command { setFileNameInPageTitle(dataflowFile.name); return context.root; } catch (error) { - console.error(error); + this.logger.error(this, (error as Error).message); return context.root; } } diff --git a/src/features/serialize/loadPalladio.ts b/src/features/serialize/loadPalladio.ts index 5abcbcd..98e770c 100644 --- a/src/features/serialize/loadPalladio.ts +++ b/src/features/serialize/loadPalladio.ts @@ -1,7 +1,8 @@ -import { Command, CommandExecutionContext, SModelRootImpl } from "sprotty"; +import { Command, CommandExecutionContext, ILogger, NullLogger, SModelRootImpl, TYPES } from "sprotty"; import { Action } from "sprotty-protocol"; import { setModelFileName } from "../../index"; import { sendMessage } from "./webSocketHandler"; +import { inject } from "inversify"; export interface LoadPalladioAction extends Action { kind: typeof LoadPalladioAction.KIND; @@ -21,6 +22,9 @@ export namespace LoadPalladioAction { export class LoadPalladioCommand extends Command { static readonly KIND = LoadPalladioAction.KIND; + @inject(TYPES.ILogger) + private readonly logger: ILogger = new NullLogger(); + constructor() { super(); } @@ -89,9 +93,7 @@ export class LoadPalladioCommand extends Command { ); // Construct the message format for WebSocket - const message = [ - ...fileContents.map(({ name, content }) => `${name}:${content}`), - ].join("---FILE---"); + const message = [...fileContents.map(({ name, content }) => `${name}:${content}`)].join("---FILE---"); // Send the structured message over WebSocket sendMessage(message); @@ -101,7 +103,7 @@ export class LoadPalladioCommand extends Command { return context.root; } catch (error) { - console.error(error); + this.logger.error(this, (error as Error).message); return context.root; } } diff --git a/src/features/serialize/webSocketHandler.ts b/src/features/serialize/webSocketHandler.ts index 5772e8c..fa341eb 100644 --- a/src/features/serialize/webSocketHandler.ts +++ b/src/features/serialize/webSocketHandler.ts @@ -1,4 +1,4 @@ -import { getModelFileName, setModelSource } from "../../index"; +import { getModelFileName, logger, setModelSource } from "../../index"; import { SaveDFDandDD } from "./saveDFDandDD"; const webSocketAdress = `wss://websocket.dataflowanalysis.org/events/`; @@ -13,22 +13,22 @@ function initWebSocket() { ws = new WebSocket(webSocketAdress); ws.onopen = () => { - console.log("WebSocket connection established."); + logger.log(ws, "WebSocket connection established."); }; ws.onclose = () => { - console.log("WebSocket connection closed. Reconnecting..."); + logger.log(ws, "WebSocket connection closed. Reconnecting..."); initWebSocket(); }; ws.onerror = () => { - console.log("WebSocket encountered an error. Reconnecting..."); + logger.log(ws, "WebSocket encountered an error. Reconnecting..."); initWebSocket(); }; ws.onmessage = (event) => { - console.log("WebSocketID:", wsId); - console.log(event.data); + logger.log(ws, "WebSocketID:", wsId); + logger.log(ws, event.data); // Example of specific handling for certain messages: if (event.data === "Error:Cycle") { diff --git a/src/features/toolPalette/creationTool.ts b/src/features/toolPalette/creationTool.ts index 2ee45e3..4068113 100644 --- a/src/features/toolPalette/creationTool.ts +++ b/src/features/toolPalette/creationTool.ts @@ -109,6 +109,7 @@ export abstract class CreationTool extends Mou root = this.element.root as SGraphImpl; } catch (error) { // element has no assigned root + void error; } // Remove element from graph diff --git a/src/features/toolPalette/toolPalette.tsx b/src/features/toolPalette/toolPalette.tsx index 07abe07..78becb0 100644 --- a/src/features/toolPalette/toolPalette.tsx +++ b/src/features/toolPalette/toolPalette.tsx @@ -2,6 +2,7 @@ import { injectable, inject, multiInject, optional } from "inversify"; import { VNode } from "snabbdom"; import { + // eslint-disable-next-line @typescript-eslint/no-unused-vars svg, AbstractUIExtension, IActionDispatcher, @@ -267,7 +268,7 @@ export class ToolPaletteUI extends AbstractUIExtension implements IActionHandler return []; } - keyUp(_element: SModelElementImpl, _event: KeyboardEvent): Action[] { + keyUp(): Action[] { // ignored return []; } diff --git a/src/index.ts b/src/index.ts index 2f5fe26..efed3ac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import { AbstractUIExtension, ActionDispatcher, CommitModelAction, + ILogger, LocalModelSource, SetUIExtensionVisibilityAction, TYPES, @@ -60,6 +61,7 @@ container.load( const dispatcher = container.get(TYPES.IActionDispatcher); const defaultUIElements = container.getAll(EDITOR_TYPES.DefaultUIElement); const modelSource = container.get(TYPES.ModelSource); +export const logger = container.get(TYPES.ILogger); let modelFileName = "diagram"; @@ -101,7 +103,7 @@ export function setModelSource(file: File): void { sprottySvgContainer?.focus(); }) .catch((error) => { - console.error("Failed to show default UIs and load default diagram", error); + logger.error(null, "Failed to show default UIs and load default diagram", error); }); } @@ -137,5 +139,5 @@ modelSource sprottySvgContainer?.focus(); }) .catch((error) => { - console.error("Failed to show default UIs and load default diagram", error); + logger.error(null, "Failed to show default UIs and load default diagram", error); }); From 31fa26ded42a137c1fbe08591b4b1da3274c6d62 Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Mon, 31 Mar 2025 12:56:48 +0200 Subject: [PATCH 3/7] add workflows --- .github/workflows/checkFormat.yaml | 26 ++++++++++++++++++++++++++ .github/workflows/checkLint.yaml | 21 +++++++++++++++++++++ package.json | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/checkFormat.yaml create mode 100644 .github/workflows/checkLint.yaml diff --git a/.github/workflows/checkFormat.yaml b/.github/workflows/checkFormat.yaml new file mode 100644 index 0000000..7f5ee09 --- /dev/null +++ b/.github/workflows/checkFormat.yaml @@ -0,0 +1,26 @@ +name: Check Prettier Format + +on: + workflow_dispatch: + push: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install and Lint + run: | + npm install + npx prettier --check ./**/*.html + npx prettier --check ./**/*.css + npx prettier --check ./**/*.ts + npx prettier --check ./**/*.tsx + npx prettier --check ./**/*.json + npx prettier --check ./**/*.md diff --git a/.github/workflows/checkLint.yaml b/.github/workflows/checkLint.yaml new file mode 100644 index 0000000..9fe3d61 --- /dev/null +++ b/.github/workflows/checkLint.yaml @@ -0,0 +1,21 @@ +name: Check ESLint + +on: + workflow_dispatch: + push: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install and Lint + run: | + npm install + npm run lint \ No newline at end of file diff --git a/package.json b/package.json index 7397a2e..498fa99 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,6 @@ "prepare": "husky" }, "lint-staged": { - "*.{html,css,ts,tsx,json,yaml,md}": "prettier --write" + "*.{html,css,ts,tsx,json,md}": ["npm run lint", "npm run format"] } } From db270337d46b0d2ee08da5e695067fc30d65d08a Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Mon, 31 Mar 2025 12:57:10 +0200 Subject: [PATCH 4/7] fix format --- .github/workflows/checkFormat.yaml | 42 ++++++++++---------- .github/workflows/checkLint.yaml | 32 +++++++-------- package.json | 5 ++- src/features/dfdElements/outputPortEditUi.ts | 3 +- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/.github/workflows/checkFormat.yaml b/.github/workflows/checkFormat.yaml index 7f5ee09..7108d93 100644 --- a/.github/workflows/checkFormat.yaml +++ b/.github/workflows/checkFormat.yaml @@ -1,26 +1,26 @@ name: Check Prettier Format on: - workflow_dispatch: - push: - + workflow_dispatch: + push: + jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: "22" + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" - - name: Install and Lint - run: | - npm install - npx prettier --check ./**/*.html - npx prettier --check ./**/*.css - npx prettier --check ./**/*.ts - npx prettier --check ./**/*.tsx - npx prettier --check ./**/*.json - npx prettier --check ./**/*.md + - name: Install and Lint + run: | + npm install + npx prettier --check ./**/*.html + npx prettier --check ./**/*.css + npx prettier --check ./**/*.ts + npx prettier --check ./**/*.tsx + npx prettier --check ./**/*.json + npx prettier --check ./**/*.md diff --git a/.github/workflows/checkLint.yaml b/.github/workflows/checkLint.yaml index 9fe3d61..a722541 100644 --- a/.github/workflows/checkLint.yaml +++ b/.github/workflows/checkLint.yaml @@ -1,21 +1,21 @@ name: Check ESLint on: - workflow_dispatch: - push: - + workflow_dispatch: + push: + jobs: - check: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: "22" + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" - - name: Install and Lint - run: | - npm install - npm run lint \ No newline at end of file + - name: Install and Lint + run: | + npm install + npm run lint diff --git a/package.json b/package.json index 498fa99..6611226 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,9 @@ "prepare": "husky" }, "lint-staged": { - "*.{html,css,ts,tsx,json,md}": ["npm run lint", "npm run format"] + "*.{html,css,ts,tsx,json,md}": [ + "npm run lint", + "npm run format" + ] } } diff --git a/src/features/dfdElements/outputPortEditUi.ts b/src/features/dfdElements/outputPortEditUi.ts index 47b6139..c8475ae 100644 --- a/src/features/dfdElements/outputPortEditUi.ts +++ b/src/features/dfdElements/outputPortEditUi.ts @@ -255,8 +255,7 @@ class MonacoEditorDfdBehaviorCompletionProvider implements monaco.languages.Comp case 1: // If there's only one part, we're completing the `Type` return this.getLabelTypeCompletions(model, position); - case 2: // If there's already a dot, we complete the `value` for the specific `Type` - { + case 2: { // If there's already a dot, we complete the `value` for the specific `Type` const labelTypeName = expressionParts[0]; return this.getLabelValueCompletions(model, position, labelTypeName); } From f62f493a26196338219697dbf42a0f693d562424 Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Mon, 31 Mar 2025 13:05:16 +0200 Subject: [PATCH 5/7] Merge remote-tracking branch 'origin/main' into enhance-maintainability --- Documentation.md | 6 +- package-lock.json | 488 +++++++++--------- package.json | 8 +- src/common/commandPalette.ts | 9 +- src/common/di.config.ts | 5 - src/common/lightDarkSwitch.css | 20 - src/common/lightDarkSwitch.ts | 56 -- src/features/autoLayout/command.ts | 12 +- src/features/autoLayout/di.config.ts | 5 +- src/features/autoLayout/layouter.ts | 356 ++++++++++++- src/features/constraintMenu/ConstraintMenu.ts | 2 +- src/features/constraintMenu/di.config.ts | 2 +- src/features/dfdElements/di.config.ts | 2 +- src/features/dfdElements/edges.tsx | 35 +- src/features/dfdElements/nodes.tsx | 13 +- src/features/dfdElements/outputPortEditUi.ts | 7 +- src/features/editorMode/command.ts | 4 +- src/features/editorMode/di.config.ts | 9 +- .../editorMode/editorModeController.ts | 2 +- src/features/editorMode/modeSwitchUi.ts | 30 +- src/features/editorMode/sprottyHooks.ts | 32 -- src/features/labels/labelRenderer.tsx | 7 +- src/features/serialize/analyze.ts | 2 +- src/features/serialize/defaultDiagram.json | 2 +- src/features/serialize/di.config.ts | 2 + src/features/serialize/image.ts | 50 ++ src/features/serialize/load.ts | 6 +- src/features/serialize/loadDefaultDiagram.ts | 8 +- src/features/serialize/save.ts | 4 +- src/features/serialize/saveDFDandDD.ts | 2 +- src/features/settingsMenu/LayoutMethod.ts | 5 + src/features/settingsMenu/SettingsManager.ts | 77 +++ src/features/settingsMenu/actions.ts | 67 +++ src/features/settingsMenu/commands.ts | 272 ++++++++++ src/features/settingsMenu/di.config.ts | 28 + src/features/settingsMenu/settingsMenu.css | 109 ++++ src/features/settingsMenu/settingsMenu.ts | 113 ++++ src/features/settingsMenu/themeManager.ts | 68 +++ src/index.ts | 2 + src/utils.ts | 6 +- 40 files changed, 1463 insertions(+), 470 deletions(-) delete mode 100644 src/common/lightDarkSwitch.css delete mode 100644 src/common/lightDarkSwitch.ts create mode 100644 src/features/serialize/image.ts create mode 100644 src/features/settingsMenu/LayoutMethod.ts create mode 100644 src/features/settingsMenu/SettingsManager.ts create mode 100644 src/features/settingsMenu/actions.ts create mode 100644 src/features/settingsMenu/commands.ts create mode 100644 src/features/settingsMenu/di.config.ts create mode 100644 src/features/settingsMenu/settingsMenu.css create mode 100644 src/features/settingsMenu/settingsMenu.ts create mode 100644 src/features/settingsMenu/themeManager.ts diff --git a/Documentation.md b/Documentation.md index f10a83a..8863ff8 100644 --- a/Documentation.md +++ b/Documentation.md @@ -234,13 +234,11 @@ This editor currently has three different modes: - `edit`: The default mode, allows to view and edit the diagram. Creation of new elements is possible. Existing elements can be moved, modified, and deleted. Newly created diagrams are always in this mode. -- `annotated`: In this mode the diagram is read-only. The node annotations (refer to the DFD elements module) +- `view`: In this mode the diagram is read-only. The node annotations (refer to the DFD elements module) are displayed and can be viewed to get information about e.g. analysis validation errors. The user can still zoom and pan the diagram. Creation, deletion, and modification of elements is not possible. However the user can click a button to switch to the `edit` mode. Doing so will remove all node annotations and allow the user to edit the diagram again. -- `readonly`: This mode is similar to the `annotated` mode but does not allow switching back to the `edit` mode. - It is intended to be used when the diagram is from a generated source and should only be viewed. Diagrams with modes other than `edit` are not creatable using the editor. Diagrams with these modes are intended to be generated from some other source. @@ -249,7 +247,7 @@ This module contains the `EditorModeController` which manages the global editor All other modules that want to behave differently depending on the editor mode use this as a source of truth and subscribe to changes of the editor mode. Additionally, this module contains a UI that shows when the editor mode is not `edit` -and allows switching from `annotated` to `edit` mode. +and allows switching from `view` to `edit` mode. ### (DFD) Label diff --git a/package-lock.json b/package-lock.json index 3f963ee..53ee445 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,22 +16,22 @@ "eslint-config-prettier": "^10.0.2", "husky": "^9.1.7", "inversify": "^6.2.2", - "lint-staged": "^15.4.3", + "lint-staged": "^15.5.0", "monaco-editor": "^0.45.0", - "prettier": "^3.5.0", + "prettier": "^3.5.3", "reflect-metadata": "^0.2.2", "sprotty": "^1.4.0", "sprotty-elk": "^1.4.0", "sprotty-protocol": "^1.4.0", - "typescript": "^5.7.3", + "typescript": "^5.8.2", "typescript-eslint": "^8.25.0", - "vite": "^6.1.0" + "vite": "^6.2.3" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "cpu": [ "ppc64" ], @@ -46,9 +46,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", "cpu": [ "arm" ], @@ -63,9 +63,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", "cpu": [ "arm64" ], @@ -80,9 +80,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", "cpu": [ "x64" ], @@ -97,9 +97,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", "cpu": [ "arm64" ], @@ -114,9 +114,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", "cpu": [ "x64" ], @@ -131,9 +131,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", "cpu": [ "arm64" ], @@ -148,9 +148,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", "cpu": [ "x64" ], @@ -165,9 +165,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", "cpu": [ "arm" ], @@ -182,9 +182,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", "cpu": [ "arm64" ], @@ -199,9 +199,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", "cpu": [ "ia32" ], @@ -216,9 +216,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", "cpu": [ "loong64" ], @@ -233,9 +233,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", "cpu": [ "mips64el" ], @@ -250,9 +250,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", "cpu": [ "ppc64" ], @@ -267,9 +267,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", "cpu": [ "riscv64" ], @@ -284,9 +284,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", "cpu": [ "s390x" ], @@ -301,9 +301,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "cpu": [ "x64" ], @@ -318,9 +318,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", "cpu": [ "arm64" ], @@ -335,9 +335,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", "cpu": [ "x64" ], @@ -352,9 +352,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", "cpu": [ "arm64" ], @@ -369,9 +369,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", "cpu": [ "x64" ], @@ -386,9 +386,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", "cpu": [ "x64" ], @@ -403,9 +403,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", "cpu": [ "arm64" ], @@ -420,9 +420,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", "cpu": [ "ia32" ], @@ -437,9 +437,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", "cpu": [ "x64" ], @@ -1550,9 +1550,9 @@ } }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1563,31 +1563,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "node_modules/escape-string-regexp": { @@ -2222,9 +2222,9 @@ } }, "node_modules/lint-staged": { - "version": "15.4.3", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.4.3.tgz", - "integrity": "sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g==", + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.0.tgz", + "integrity": "sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg==", "dev": true, "license": "MIT", "dependencies": { @@ -2607,9 +2607,9 @@ } }, "node_modules/postcss": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", - "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "funding": [ { @@ -2645,9 +2645,9 @@ } }, "node_modules/prettier": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", - "integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", "bin": { @@ -3098,9 +3098,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3143,14 +3143,14 @@ } }, "node_modules/vite": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz", - "integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz", + "integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.5.1", + "esbuild": "^0.25.0", + "postcss": "^8.5.3", "rollup": "^4.30.1" }, "bin": { @@ -3284,177 +3284,177 @@ }, "dependencies": { "@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "dev": true, "optional": true }, "@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", "dev": true, "optional": true }, "@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", "dev": true, "optional": true }, "@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", "dev": true, "optional": true }, "@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", "dev": true, "optional": true }, "@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", "dev": true, "optional": true }, "@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", "dev": true, "optional": true }, "@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", "dev": true, "optional": true }, "@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", "dev": true, "optional": true }, "@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", "dev": true, "optional": true }, "@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", "dev": true, "optional": true }, "@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", "dev": true, "optional": true }, "@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", "dev": true, "optional": true }, "@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", "dev": true, "optional": true }, "@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", "dev": true, "optional": true }, "@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", "dev": true, "optional": true }, "@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "dev": true, "optional": true }, "@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", "dev": true, "optional": true }, "@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", "dev": true, "optional": true }, "@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", "dev": true, "optional": true }, "@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", "dev": true, "optional": true }, "@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", "dev": true, "optional": true }, "@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", "dev": true, "optional": true }, "@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", "dev": true, "optional": true }, "@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", "dev": true, "optional": true }, @@ -4169,36 +4169,36 @@ "dev": true }, "esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "requires": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "escape-string-regexp": { @@ -4640,9 +4640,9 @@ "dev": true }, "lint-staged": { - "version": "15.4.3", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.4.3.tgz", - "integrity": "sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g==", + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.0.tgz", + "integrity": "sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg==", "dev": true, "requires": { "chalk": "^5.4.1", @@ -4893,9 +4893,9 @@ "dev": true }, "postcss": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", - "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "requires": { "nanoid": "^3.3.8", @@ -4910,9 +4910,9 @@ "dev": true }, "prettier": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz", - "integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true }, "punycode": { @@ -5203,9 +5203,9 @@ } }, "typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true }, "typescript-eslint": { @@ -5229,14 +5229,14 @@ } }, "vite": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz", - "integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz", + "integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==", "dev": true, "requires": { - "esbuild": "^0.24.2", + "esbuild": "^0.25.0", "fsevents": "~2.3.3", - "postcss": "^8.5.1", + "postcss": "^8.5.3", "rollup": "^4.30.1" } }, diff --git a/package.json b/package.json index 6611226..cf61f98 100644 --- a/package.json +++ b/package.json @@ -15,16 +15,16 @@ "eslint-config-prettier": "^10.0.2", "husky": "^9.1.7", "inversify": "^6.2.2", - "lint-staged": "^15.4.3", + "lint-staged": "^15.5.0", "monaco-editor": "^0.45.0", - "prettier": "^3.5.0", + "prettier": "^3.5.3", "reflect-metadata": "^0.2.2", "sprotty": "^1.4.0", "sprotty-elk": "^1.4.0", "sprotty-protocol": "^1.4.0", - "typescript": "^5.7.3", + "typescript": "^5.8.2", "typescript-eslint": "^8.25.0", - "vite": "^6.1.0" + "vite": "^6.2.3" }, "scripts": { "dev": "vite", diff --git a/src/common/commandPalette.ts b/src/common/commandPalette.ts index 8afca70..33b3f4d 100644 --- a/src/common/commandPalette.ts +++ b/src/common/commandPalette.ts @@ -1,4 +1,4 @@ -import { injectable } from "inversify"; +import { inject, injectable } from "inversify"; import { ICommandPaletteActionProvider, LabeledAction, SModelRootImpl, CommitModelAction } from "sprotty"; import { LoadDiagramAction } from "../features/serialize/load"; import { createDefaultFitToScreenAction } from "../utils"; @@ -12,12 +12,16 @@ import "./commandPalette.css"; import { SaveDFDandDDAction } from "../features/serialize/saveDFDandDD"; import { LoadDFDandDDAction } from "../features/serialize/loadDFDandDD"; import { LoadPalladioAction } from "../features/serialize/loadPalladio"; +import { SaveImageAction } from "../features/serialize/image"; +import { SettingsManager } from "../features/settingsMenu/SettingsManager"; /** * Provides possible actions for the command palette. */ @injectable() export class ServerCommandPaletteActionProvider implements ICommandPaletteActionProvider { + constructor(@inject(SettingsManager) protected readonly settings: SettingsManager) {} + async getActions(root: Readonly): Promise { const fitToScreenAction = createDefaultFitToScreenAction(root); const commitAction = CommitModelAction.create(); @@ -28,10 +32,11 @@ export class ServerCommandPaletteActionProvider implements ICommandPaletteAction new LabeledAction("Load Palladio", [LoadPalladioAction.create(), commitAction], "go-to-file"), new LabeledAction("Save diagram as JSON", [SaveDiagramAction.create()], "save"), new LabeledAction("Save diagram as DFD and DD", [SaveDFDandDDAction.create(), commitAction], "save"), + new LabeledAction("Save viewport as image", [SaveImageAction.create()], "save"), new LabeledAction("Load default diagram", [LoadDefaultDiagramAction.create(), commitAction], "clear-all"), new LabeledAction("Fit to Screen", [fitToScreenAction], "layout"), new LabeledAction( - "Layout diagram", + "Layout diagram (Method: " + this.settings.layoutMethod + ")", [LayoutModelAction.create(), commitAction, fitToScreenAction], "layout", ), diff --git a/src/common/di.config.ts b/src/common/di.config.ts index bf6d548..c99d220 100644 --- a/src/common/di.config.ts +++ b/src/common/di.config.ts @@ -19,7 +19,6 @@ import { FitToScreenKeyListener as CenterDiagramKeyListener } from "./fitToScree import { DiagramModificationCommandStack } from "./customCommandStack"; import "./commonStyling.css"; -import { LightDarkSwitch } from "./lightDarkSwitch"; export const commonModule = new ContainerModule((bind, unbind, isBound, rebind) => { bind(ServerCommandPaletteActionProvider).toSelf().inSingletonScope(); @@ -34,10 +33,6 @@ export const commonModule = new ContainerModule((bind, unbind, isBound, rebind) bind(TYPES.IUIExtension).toService(HelpUI); bind(EDITOR_TYPES.DefaultUIElement).toService(HelpUI); - bind(LightDarkSwitch).toSelf().inSingletonScope(); - bind(TYPES.IUIExtension).toService(LightDarkSwitch); - bind(EDITOR_TYPES.DefaultUIElement).toService(LightDarkSwitch); - bind(DynamicChildrenProcessor).toSelf().inSingletonScope(); unbind(TYPES.ICommandStack); diff --git a/src/common/lightDarkSwitch.css b/src/common/lightDarkSwitch.css deleted file mode 100644 index 7e5f62d..0000000 --- a/src/common/lightDarkSwitch.css +++ /dev/null @@ -1,20 +0,0 @@ -div.light-dark-switch { - left: 20px; - bottom: 70px; - padding: 10px 10px; -} - -#light-dark-label #light-dark-button::before { - content: ""; - background-image: url("@fortawesome/fontawesome-free/svgs/regular/moon.svg"); - display: inline-block; - filter: invert(var(--dark-mode)); - height: 16px; - width: 16px; - background-size: 16px 16px; - vertical-align: text-top; -} - -#light-dark-switch:checked ~ label #light-dark-button::before { - background-image: url("@fortawesome/fontawesome-free/svgs/regular/sun.svg"); -} diff --git a/src/common/lightDarkSwitch.ts b/src/common/lightDarkSwitch.ts deleted file mode 100644 index 31ac999..0000000 --- a/src/common/lightDarkSwitch.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { injectable, multiInject } from "inversify"; -import "./lightDarkSwitch.css"; -import { AbstractUIExtension } from "sprotty"; - -export const SWITCHABLE = Symbol("Switchable"); - -export interface Switchable { - switchTheme(useDark: boolean): void; -} - -@injectable() -export class LightDarkSwitch extends AbstractUIExtension { - static readonly ID = "light-dark-switch"; - static useDarkMode = false; - - constructor(@multiInject(SWITCHABLE) protected switchables: Switchable[]) { - super(); - } - - id(): string { - return LightDarkSwitch.ID; - } - containerClass(): string { - return LightDarkSwitch.ID; - } - protected initializeContents(containerElement: HTMLElement): void { - containerElement.classList.add("ui-float"); - containerElement.innerHTML = ` - - - `; - - const checkbox = containerElement.querySelector("#light-dark-switch") as HTMLInputElement; - checkbox.addEventListener("change", () => { - this.changeDarkMode(checkbox.checked); - }); - - // use the default browser theme - if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) { - checkbox.checked = true; - this.changeDarkMode(true); - } - } - - private changeDarkMode(useDark: boolean) { - const rootElement = document.querySelector(":root") as HTMLElement; - const sprottyElement = document.querySelector("#sprotty") as HTMLElement; - - const value = useDark ? "dark" : "light"; - rootElement.setAttribute("data-theme", value); - sprottyElement.setAttribute("data-theme", value); - this.switchables.forEach((s) => s.switchTheme(useDark)); - } -} diff --git a/src/features/autoLayout/command.ts b/src/features/autoLayout/command.ts index a03337b..4a680bf 100644 --- a/src/features/autoLayout/command.ts +++ b/src/features/autoLayout/command.ts @@ -1,8 +1,7 @@ -import { inject, optional } from "inversify"; +import { inject } from "inversify"; import { Command, CommandExecutionContext, SModelRootImpl, TYPES } from "sprotty"; import { Action, IModelLayoutEngine, SGraph, SModelRoot } from "sprotty-protocol"; import { LoadDiagramCommand } from "../serialize/load"; -import { EditorModeController } from "../editorMode/editorModeController"; export interface LayoutModelAction extends Action { kind: typeof LayoutModelAction.KIND; @@ -20,10 +19,6 @@ export namespace LayoutModelAction { export class LayoutModelCommand extends Command { static readonly KIND = LayoutModelAction.KIND; - @inject(EditorModeController) - @optional() - private editorModeController?: EditorModeController; - @inject(TYPES.IModelLayoutEngine) private readonly layoutEngine?: IModelLayoutEngine; @@ -31,11 +26,6 @@ export class LayoutModelCommand extends Command { private newModel?: SModelRootImpl; async execute(context: CommandExecutionContext): Promise { - if (this.editorModeController?.isReadOnly()) { - // We don't want to layout the model in read-only mode. - return context.root; - } - this.oldModelSchema = context.modelFactory.createSchema(context.root); if (!this.layoutEngine) throw new Error("Missing injects"); diff --git a/src/features/autoLayout/di.config.ts b/src/features/autoLayout/di.config.ts index dcc0121..23414a2 100644 --- a/src/features/autoLayout/di.config.ts +++ b/src/features/autoLayout/di.config.ts @@ -1,14 +1,15 @@ import { ContainerModule } from "inversify"; import { TYPES, configureCommand } from "sprotty"; -import { ElkFactory, ILayoutConfigurator } from "sprotty-elk"; +import { ElkFactory, ILayoutConfigurator, ILayoutPostprocessor } from "sprotty-elk"; import { LayoutModelCommand } from "./command"; -import { DfdElkLayoutEngine, DfdLayoutConfigurator, elkFactory } from "./layouter"; +import { CircleLayoutPostProcessor, DfdElkLayoutEngine, DfdLayoutConfigurator, elkFactory } from "./layouter"; import { AutoLayoutKeyListener } from "./keyListener"; export const autoLayoutModule = new ContainerModule((bind, unbind, isBound, rebind) => { bind(DfdElkLayoutEngine).toSelf().inSingletonScope(); bind(TYPES.IModelLayoutEngine).toService(DfdElkLayoutEngine); rebind(ILayoutConfigurator).to(DfdLayoutConfigurator); + bind(ILayoutPostprocessor).to(CircleLayoutPostProcessor).inSingletonScope(); bind(ElkFactory).toConstantValue(elkFactory); bind(TYPES.KeyListener).to(AutoLayoutKeyListener).inSingletonScope(); diff --git a/src/features/autoLayout/layouter.ts b/src/features/autoLayout/layouter.ts index a3fb8db..62c0de7 100644 --- a/src/features/autoLayout/layouter.ts +++ b/src/features/autoLayout/layouter.ts @@ -1,4 +1,4 @@ -import ElkConstructor from "elkjs/lib/elk.bundled"; +import ElkConstructor, { ElkExtendedEdge, ElkNode } from "elkjs/lib/elk.bundled"; import { injectable, inject } from "inversify"; import { DefaultLayoutConfigurator, @@ -6,31 +6,63 @@ import { ElkLayoutEngine, IElementFilter, ILayoutConfigurator, + ILayoutPostprocessor, } from "sprotty-elk"; import { SChildElementImpl, SShapeElementImpl, isBoundsAware } from "sprotty"; -import { SShapeElement, SModelIndex } from "sprotty-protocol"; +import { SShapeElement, SModelIndex, SEdge } from "sprotty-protocol"; import { ElkShape, LayoutOptions } from "elkjs"; +import { SettingsManager } from "../settingsMenu/SettingsManager"; +import { LayoutMethod } from "../settingsMenu/LayoutMethod"; export class DfdLayoutConfigurator extends DefaultLayoutConfigurator { + constructor(@inject(SettingsManager) protected readonly settings: SettingsManager) { + super(); + } + protected override graphOptions(): LayoutOptions { // Elk settings. See https://eclipse.dev/elk/reference.html for available options. return { - "org.eclipse.elk.algorithm": "org.eclipse.elk.layered", - "org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers": "30.0", - "org.eclipse.elk.layered.spacing.edgeNodeBetweenLayers": "20.0", - "org.eclipse.elk.port.borderOffset": "14.0", - // Do not do micro layout for nodes, which includes the node dimensions etc. - // These are all automatically determined by our dfd node views - "org.eclipse.elk.omitNodeMicroLayout": "true", - // Balanced graph > straight edges - "org.eclipse.elk.layered.nodePlacement.favorStraightEdges": "false", - }; + [LayoutMethod.LINES]: { + "org.eclipse.elk.algorithm": "org.eclipse.elk.layered", + "org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers": "30.0", + "org.eclipse.elk.layered.spacing.edgeNodeBetweenLayers": "20.0", + "org.eclipse.elk.port.borderOffset": "14.0", + // Do not do micro layout for nodes, which includes the node dimensions etc. + // These are all automatically determined by our dfd node views + "org.eclipse.elk.omitNodeMicroLayout": "true", + // Balanced graph > straight edges + "org.eclipse.elk.layered.nodePlacement.favorStraightEdges": "false", + }, + [LayoutMethod.WRAPPING]: { + "org.eclipse.elk.algorithm": "org.eclipse.elk.layered", + "org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers": "10.0", //Save more space between layers (long names might break this!) + "org.eclipse.elk.layered.spacing.edgeNodeBetweenLayers": "5.0", //Save more space between layers (long names might break this!) + "org.eclipse.elk.edgeRouting": "ORTHOGONAL", //Edges should be routed orthogonal to each another + "org.eclipse.elk.layered.layering.strategy": "COFFMAN_GRAHAM", + "org.eclipse.elk.layered.compaction.postCompaction.strategy": "LEFT_RIGHT_CONSTRAINT_LOCKING", //Compact the resulting graph horizontally + "org.eclipse.elk.layered.wrapping.strategy": "MULTI_EDGE", //Allow wrapping of multiple edges + "org.eclipse.elk.layered.wrapping.correctionFactor": "2.0", //Allow the wrapping to occur earlier + // Do not do micro layout for nodes, which includes the node dimensions etc. + // These are all automatically determined by our dfd node views + "org.eclipse.elk.omitNodeMicroLayout": "true", + "org.eclipse.elk.port.borderOffset": "14.0", + }, + [LayoutMethod.CIRCLES]: { + "org.eclipse.elk.algorithm": "org.eclipse.elk.stress", + "org.eclipse.elk.force.repulsion": "5.0", + "org.eclipse.elk.force.iterations": "100", //Reduce iterations for faster formatting, did not notice differences with more iterations + "org.eclipse.elk.force.repulsivePower": "1", //Edges should repel vertices as well + // Do not do micro layout for nodes, which includes the node dimensions etc. + // These are all automatically determined by our dfd node views + "org.eclipse.elk.omitNodeMicroLayout": "true", + }, + }[this.settings.layoutMethod]; } } export const elkFactory = () => new ElkConstructor({ - algorithms: ["layered"], + algorithms: ["layered", "stress"], }); /** @@ -48,8 +80,10 @@ export class DfdElkLayoutEngine extends ElkLayoutEngine { @inject(ElkFactory) elkFactory: ElkFactory, @inject(IElementFilter) elementFilter: IElementFilter, @inject(ILayoutConfigurator) configurator: ILayoutConfigurator, + @inject(SettingsManager) protected readonly settings: SettingsManager, + @inject(ILayoutPostprocessor) protected readonly postprocessor: ILayoutPostprocessor, ) { - super(elkFactory, elementFilter, configurator); + super(elkFactory, elementFilter, configurator, undefined, postprocessor); } protected override transformShape(elkShape: ElkShape, sshape: SShapeElementImpl | SShapeElement): void { @@ -63,6 +97,13 @@ export class DfdElkLayoutEngine extends ElkLayoutEngine { } } + protected override transformEdge(sedge: SEdge, index: SModelIndex): ElkExtendedEdge { + // remove all middle points of edge and only keep source and target + const elkEdge = super.transformEdge(sedge, index); + elkEdge.sections = []; + return elkEdge; + } + protected override applyShape(sshape: SShapeElement, elkShape: ElkShape, index: SModelIndex): void { // Check if this is a port, if yes we want to center it on the node edge instead of putting it right next to the node at the edge if (this.getBasicType(sshape) === "port") { @@ -70,28 +111,289 @@ export class DfdElkLayoutEngine extends ElkLayoutEngine { // we can access the parent property and the bounds of the parent which is the node of this port. if (sshape instanceof SChildElementImpl && isBoundsAware(sshape.parent)) { const parent = sshape.parent; - if (elkShape.x && elkShape.width && elkShape.y && elkShape.height) { + if ( + elkShape.x !== undefined && + elkShape.width !== undefined && + elkShape.y !== undefined && + elkShape.height !== undefined + ) { // Note that the port x and y coordinates are relative to the parent node. // Move inwards from being adjacent to the node edge by half of the port width/height // depending on which edge the port is on. - if (elkShape.x <= 0) - // Left edge - elkShape.x += elkShape.width / 2; - if (elkShape.y <= 0) - // Top edge - elkShape.y += elkShape.height / 2; - if (elkShape.x >= parent.bounds.width) - // Right edge - elkShape.x -= elkShape.width / 2; - if (elkShape.y >= parent.bounds.height) - // Bottom edge - elkShape.y -= elkShape.height / 2; + // depending on the mode the ports may be placed differently + if (this.settings.layoutMethod === LayoutMethod.CIRCLES) { + if (elkShape.x <= 0) + // Left edge + elkShape.x -= elkShape.width / 2; + if (elkShape.y <= 0) + // Top edge + elkShape.y -= elkShape.height / 2; + if (elkShape.x >= parent.bounds.width) + // Right edge + elkShape.x -= elkShape.width / 2; + if (elkShape.y >= parent.bounds.height) + // Bottom edge + elkShape.y -= elkShape.height / 2; + } else { + if (elkShape.x <= 0) + // Left edge + elkShape.x += elkShape.width / 2; + if (elkShape.y <= 0) + // Top edge + elkShape.y += elkShape.height / 2; + if (elkShape.x >= parent.bounds.width) + // Right edge + elkShape.x -= elkShape.width / 2; + if (elkShape.y >= parent.bounds.height) + // Bottom edge + elkShape.y -= elkShape.height / 2; + } } } } super.applyShape(sshape, elkShape, index); } + + protected applyEdge(sedge: SEdge, elkEdge: ElkExtendedEdge, index: SModelIndex): void { + if (this.settings.layoutMethod === LayoutMethod.CIRCLES) { + // In the circles layout method, we want to make sure that the edge is not straight + // This is because the circles layout method does not support straight edges + elkEdge.sections = []; + } + super.applyEdge(sedge, elkEdge, index); + } +} + +@injectable() +export class CircleLayoutPostProcessor implements ILayoutPostprocessor { + private portToNodes: Map = new Map(); + private connectedPorts: Map = new Map(); + private nodeSquares: Map = new Map(); + + constructor(@inject(SettingsManager) protected readonly settings: SettingsManager) {} + + postprocess(elkGraph: ElkNode): void { + if (this.settings.layoutMethod !== LayoutMethod.CIRCLES) { + return; + } + this.connectedPorts = new Map(); + if (!elkGraph.edges || !elkGraph.children) { + return; + } + for (const edge of elkGraph.edges) { + for (const source of edge.sources) { + if (!this.connectedPorts.has(source)) { + this.connectedPorts.set(source, []); + } + for (const target of edge.targets) { + if (!this.connectedPorts.has(target)) { + this.connectedPorts.set(target, []); + } + this.connectedPorts.get(source)?.push(target); + this.connectedPorts.get(target)?.push(source); + } + } + } + + this.portToNodes = new Map(); + this.nodeSquares = new Map(); + for (const node of elkGraph.children) { + if (node.ports) { + for (const port of node.ports) { + this.portToNodes.set(port.id, node.id); + } + this.nodeSquares.set(node.id, this.getNodeSquare(node)); + } + } + + for (const [port, connected] of this.connectedPorts) { + if (connected.length === 0) { + continue; + } + const intersections = connected.map((connection) => { + const line = this.getLine(port, connection); + const node = this.portToNodes.get(port); + if (!node) { + return { x: 0, y: 0 }; + } + const square = this.nodeSquares.get(node); + if (!square) { + return { x: 0, y: 0 }; + } + const intersection = this.getIntersection(square, line); + return intersection; + }); + const average = { + x: intersections.reduce((sum, intersection) => sum + intersection.x, 0) / intersections.length, + y: intersections.reduce((sum, intersection) => sum + intersection.y, 0) / intersections.length, + }; + + const node = this.portToNodes.get(port); + if (!node) { + continue; + } + const square = this.nodeSquares.get(node); + if (!square) { + continue; + } + const closestPointOnEdge = { + x: average.x, + y: average.y, + }; + + const topEdge = { x1: square.x, y1: square.y, x2: square.x + square.width, y2: square.y }; + const bottomEdge = { + x1: square.x, + y1: square.y + square.height, + x2: square.x + square.width, + y2: square.y + square.height, + }; + const leftEdge = { x1: square.x, y1: square.y, x2: square.x, y2: square.y + square.height }; + const rightEdge = { + x1: square.x + square.width, + y1: square.y, + x2: square.x + square.width, + y2: square.y + square.height, + }; + const distances = [ + { distance: Math.abs(average.y - square.y), dimension: "y", edge: topEdge }, + { distance: Math.abs(average.y - (square.y + square.height)), dimension: "y", edge: bottomEdge }, + { distance: Math.abs(average.x - square.x), dimension: "x", edge: leftEdge }, + { distance: Math.abs(average.x - (square.x + square.width)), dimension: "x", edge: rightEdge }, + ]; + distances.sort((a, b) => a.distance - b.distance); + const closestEdge = distances[0].edge; + if (distances[0].dimension === "y") { + closestPointOnEdge.x = clamp(average.x, closestEdge.x1, closestEdge.x2); + closestPointOnEdge.y = closestEdge.y1; + } else { + closestPointOnEdge.x = closestEdge.x1; + closestPointOnEdge.y = clamp(average.y, closestEdge.y1, closestEdge.y2); + } + + const nodeElk = elkGraph.children.find((child) => child.id === node); + if (!nodeElk) { + continue; + } + const portElk = nodeElk.ports?.find((p) => p.id === port); + if (!portElk) { + continue; + } + portElk.x = closestPointOnEdge.x - (nodeElk.x ?? 0); + portElk.y = closestPointOnEdge.y - (nodeElk.y ?? 0); + } + } + + getNodeSquare(node: ElkNode): Square { + return { + x: node.x ?? 0, + y: node.y ?? 0, + width: node.width ?? 0, + height: node.height ?? 0, + }; + } + + getCenter(square: Square): { x: number; y: number } { + return { + x: square.x + square.width / 2, + y: square.y + square.height / 2, + }; + } + + getLine(port1: string, port2: string): Line { + const node1 = this.portToNodes.get(port1); + const node2 = this.portToNodes.get(port2); + if (!node1 || !node2) { + return { + x1: 0, + y1: 0, + x2: 0, + y2: 0, + }; + } + const square1 = this.nodeSquares.get(node1)!; + const square2 = this.nodeSquares.get(node2)!; + const center1 = this.getCenter(square1); + const center2 = this.getCenter(square2); + + return { + x1: center1.x, + y1: center1.y, + x2: center2.x, + y2: center2.y, + }; + } + + getIntersection(square: Square, line: Line): { x: number; y: number } { + const topLeft = { x: square.x, y: square.y }; + const topRight = { x: square.x + square.width, y: square.y }; + const bottomLeft = { x: square.x, y: square.y + square.height }; + const bottomRight = { x: square.x + square.width, y: square.y + square.height }; + + const intersections = [ + this.getLineIntersection(line, { x1: topLeft.x, y1: topLeft.y, x2: topRight.x, y2: topRight.y }), + this.getLineIntersection(line, { x1: topRight.x, y1: topRight.y, x2: bottomRight.x, y2: bottomRight.y }), + this.getLineIntersection(line, { + x1: bottomRight.x, + y1: bottomRight.y, + x2: bottomLeft.x, + y2: bottomLeft.y, + }), + this.getLineIntersection(line, { x1: bottomLeft.x, y1: bottomLeft.y, x2: topLeft.x, y2: topLeft.y }), + ]; + + const inLineBounds = intersections.filter((intersection) => { + return ( + intersection.x >= Math.min(line.x1, line.x2) && + intersection.x <= Math.max(line.x1, line.x2) && + intersection.y >= Math.min(line.y1, line.y2) && + intersection.y <= Math.max(line.y1, line.y2) + ); + }); + return inLineBounds[0] ?? { x: 0, y: 0 }; + } + + private getLineIntersection(line1: Line, line2: Line): { x: number; y: number } { + const x1 = line1.x1; + const y1 = line1.y1; + const x2 = line1.x2; + const y2 = line1.y2; + const x3 = line2.x1; + const y3 = line2.y1; + const x4 = line2.x2; + const y4 = line2.y2; + + const denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + if (denominator === 0) { + return { x: 0, y: 0 }; + } + + const x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denominator; + const y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denominator; + + return { x, y }; + } +} + +interface Square { + x: number; + y: number; + width: number; + height: number; +} + +interface Line { + x1: number; + y1: number; + x2: number; + y2: number; +} + +function clamp(value: number, l1: number, l2: number): number { + const min = Math.min(l1, l2); + const max = Math.max(l1, l2); + return Math.max(min, Math.min(max, value)); } diff --git a/src/features/constraintMenu/ConstraintMenu.ts b/src/features/constraintMenu/ConstraintMenu.ts index f515aa5..91d3291 100644 --- a/src/features/constraintMenu/ConstraintMenu.ts +++ b/src/features/constraintMenu/ConstraintMenu.ts @@ -18,7 +18,7 @@ import { AutoCompleteTree } from "./AutoCompletion"; import { TreeBuilder } from "./DslLanguage"; import { LabelTypeRegistry } from "../labels/labelTypeRegistry"; import { EditorModeController } from "../editorMode/editorModeController"; -import { Switchable } from "../../common/lightDarkSwitch"; +import { Switchable } from "../settingsMenu/themeManager"; import { AnalyzeDiagramAction } from "../serialize/analyze"; @injectable() diff --git a/src/features/constraintMenu/di.config.ts b/src/features/constraintMenu/di.config.ts index 7e2d4ac..a08ac1a 100644 --- a/src/features/constraintMenu/di.config.ts +++ b/src/features/constraintMenu/di.config.ts @@ -3,7 +3,7 @@ import { EDITOR_TYPES } from "../../utils"; import { ConstraintMenu } from "./ConstraintMenu"; import { TYPES } from "sprotty"; import { ConstraintRegistry } from "./constraintRegistry"; -import { SWITCHABLE } from "../../common/lightDarkSwitch"; +import { SWITCHABLE } from "../settingsMenu/themeManager"; // This module contains an UI extension that adds a tool palette to the editor. // This tool palette allows the user to create new nodes and edges. diff --git a/src/features/dfdElements/di.config.ts b/src/features/dfdElements/di.config.ts index 9b188cb..3ce2543 100644 --- a/src/features/dfdElements/di.config.ts +++ b/src/features/dfdElements/di.config.ts @@ -23,7 +23,7 @@ import { DfdNodeAnnotationUI, DfdNodeAnnotationUIMouseListener } from "./nodeAnn import { DFDBehaviorRefactorer, RefactorInputNameInDFDBehaviorCommand } from "./behaviorRefactorer"; import "./elementStyles.css"; -import { SWITCHABLE } from "../../common/lightDarkSwitch"; +import { SWITCHABLE } from "../settingsMenu/themeManager"; export const dfdElementsModule = new ContainerModule((bind, unbind, isBound, rebind) => { const context = { bind, unbind, isBound, rebind }; diff --git a/src/features/dfdElements/edges.tsx b/src/features/dfdElements/edges.tsx index d81db60..363eaf5 100644 --- a/src/features/dfdElements/edges.tsx +++ b/src/features/dfdElements/edges.tsx @@ -1,5 +1,5 @@ /** @jsx svg */ -import { injectable } from "inversify"; +import { inject, injectable } from "inversify"; import { PolylineEdgeViewWithGapsOnIntersections, SEdgeImpl, @@ -14,12 +14,15 @@ import { import { VNode } from "snabbdom"; import { Point, angleOfPoint, toDegrees, SEdge, SLabel } from "sprotty-protocol"; import { DynamicChildrenEdge } from "./dynamicChildren"; +import { SettingsManager } from "../settingsMenu/SettingsManager"; export interface ArrowEdge extends SEdge { text?: string; } export class ArrowEdgeImpl extends DynamicChildrenEdge implements WithEditableLabel { + text?: string; + setChildren(schema: ArrowEdge): void { schema.children = [ { @@ -53,6 +56,10 @@ export class ArrowEdgeImpl extends DynamicChildrenEdge implements WithEditableLa @injectable() export class ArrowEdgeView extends PolylineEdgeViewWithGapsOnIntersections { + constructor(@inject(SettingsManager) protected readonly settings: SettingsManager) { + super(); + } + override render(edge: Readonly, context: RenderingContext, args?: IViewArgs): VNode | undefined { // In the default implementation children of the edge are always rendered, because they // may be visible when the rest of the edge is not. @@ -64,7 +71,31 @@ export class ArrowEdgeView extends PolylineEdgeViewWithGapsOnIntersections { return undefined; } - return super.render(edge, context, args); + return this.superRender(edge, context, args); + } + + superRender(edge: Readonly, context: RenderingContext, args?: IViewArgs): VNode | undefined { + const route = this.edgeRouterRegistry.route(edge, args); + if (route.length === 0) { + return this.renderDanglingEdge("Cannot compute route", edge, context); + } + if (!this.isVisible(edge, route, context)) { + if (edge.children.length === 0) { + return undefined; + } + // The children of an edge are not necessarily inside the bounding box of the route, + // so we need to render a group to ensure the children have a chance to be rendered. + return {this.settings.hideEdgeLabels ? [] : context.renderChildren(edge, { route })}; + } + + return ( + + {this.renderLine(edge, route, context, args)} + {this.renderAdditionals(edge, route, context)} + {this.renderJunctionPoints(edge, route, context, args)} + {this.settings.hideEdgeLabels ? [] : context.renderChildren(edge, { route })} + + ); } /** diff --git a/src/features/dfdElements/nodes.tsx b/src/features/dfdElements/nodes.tsx index 30d1c1e..55001a9 100644 --- a/src/features/dfdElements/nodes.tsx +++ b/src/features/dfdElements/nodes.tsx @@ -42,6 +42,8 @@ export abstract class DfdNodeImpl extends DynamicChildrenNode implements WithEdi text: string = ""; labels: LabelAssignment[] = []; ports: SPort[] = []; + hideLabels: boolean = false; + minimumWidth: number = DfdNodeImpl.DEFAULT_WIDTH; annotation?: DfdNodeAnnotation; override setChildren(schema: DfdNode): void { @@ -84,7 +86,10 @@ export abstract class DfdNodeImpl extends DynamicChildrenNode implements WithEdi } protected calculateWidth(): number { - const textWidth = calculateTextSize(this.editableLabel?.text).width; + if (this.hideLabels) { + return this.minimumWidth + DfdNodeImpl.WIDTH_PADDING; + } + const textWidth = calculateTextSize(this.text).width; const labelWidths = this.labels.map( (labelAssignment) => DfdNodeLabelRenderer.computeLabelContent(labelAssignment)[1], ); @@ -155,7 +160,7 @@ export abstract class DfdNodeImpl extends DynamicChildrenNode implements WithEdi export class StorageNodeImpl extends DfdNodeImpl { protected override calculateHeight(): number { const hasLabels = this.labels.length > 0; - if (hasLabels) { + if (hasLabels && !this.hideLabels) { return ( StorageNodeImpl.LABEL_START_HEIGHT + this.labels.length * DfdNodeLabelRenderer.LABEL_SPACING_HEIGHT + @@ -206,7 +211,7 @@ export class StorageNodeView extends ShapeView { export class FunctionNodeImpl extends DfdNodeImpl { protected override calculateHeight(): number { const hasLabels = this.labels.length > 0; - if (hasLabels) { + if (hasLabels && !this.hideLabels) { return ( // height for text FunctionNodeImpl.LABEL_START_HEIGHT + @@ -259,7 +264,7 @@ export class FunctionNodeView extends ShapeView { export class IONodeImpl extends DfdNodeImpl { protected override calculateHeight(): number { const hasLabels = this.labels.length > 0; - if (hasLabels) { + if (hasLabels && !this.hideLabels) { return ( IONodeImpl.LABEL_START_HEIGHT + this.labels.length * DfdNodeLabelRenderer.LABEL_SPACING_HEIGHT + diff --git a/src/features/dfdElements/outputPortEditUi.ts b/src/features/dfdElements/outputPortEditUi.ts index c8475ae..18d9425 100644 --- a/src/features/dfdElements/outputPortEditUi.ts +++ b/src/features/dfdElements/outputPortEditUi.ts @@ -32,7 +32,7 @@ import "monaco-editor/esm/vs/editor/contrib/hover/browser/hover"; import "monaco-editor/esm/vs/editor/contrib/inlineCompletions/browser/inlineCompletions.contribution.js"; import "./outputPortEditUi.css"; -import { LightDarkSwitch, Switchable } from "../../common/lightDarkSwitch"; +import { ThemeManager, Switchable } from "../settingsMenu/themeManager"; /** * Detects when a dfd output port is double clicked and shows the OutputPortEditUI @@ -255,7 +255,8 @@ class MonacoEditorDfdBehaviorCompletionProvider implements monaco.languages.Comp case 1: // If there's only one part, we're completing the `Type` return this.getLabelTypeCompletions(model, position); - case 2: { // If there's already a dot, we complete the `value` for the specific `Type` + case 2: { + // If there's already a dot, we complete the `value` for the specific `Type` const labelTypeName = expressionParts[0]; return this.getLabelValueCompletions(model, position, labelTypeName); } @@ -418,7 +419,7 @@ export class OutputPortEditUI extends AbstractUIExtension implements Switchable new MonacoEditorDfdBehaviorCompletionProvider(this, this.labelTypeRegistry), ); - const monacoTheme = (LightDarkSwitch?.useDarkMode ?? true) ? "vs-dark" : "vs"; + const monacoTheme = (ThemeManager?.useDarkMode ?? true) ? "vs-dark" : "vs"; this.editor = monaco.editor.create(this.editorContainer, { minimap: { // takes too much space, not useful for our use case diff --git a/src/features/editorMode/command.ts b/src/features/editorMode/command.ts index b1acd4e..a1e67c1 100644 --- a/src/features/editorMode/command.ts +++ b/src/features/editorMode/command.ts @@ -60,7 +60,7 @@ export class ChangeEditorModeCommand extends Command { } private postModeSwitch(context: CommandExecutionContext): void { - if (this.oldMode === "annotated" && this.action.newMode === "edit") { + if (this.oldMode === "view" && this.action.newMode === "edit") { // Remove annotations when enabling editing this.oldNodeAnnotations.clear(); @@ -74,7 +74,7 @@ export class ChangeEditorModeCommand extends Command { } private undoPostModeSwitch(context: CommandExecutionContext): void { - if (this.oldMode === "annotated" && this.action.newMode === "edit") { + if (this.oldMode === "view" && this.action.newMode === "edit") { // Restore annotations when disabling editing this.oldNodeAnnotations.forEach((annotation, id) => { const element = context.root.index.getById(id); diff --git a/src/features/editorMode/di.config.ts b/src/features/editorMode/di.config.ts index 7c7acec..4920a48 100644 --- a/src/features/editorMode/di.config.ts +++ b/src/features/editorMode/di.config.ts @@ -1,13 +1,9 @@ import { ContainerModule } from "inversify"; -import { DeleteElementCommand, EditLabelMouseListener, MoveCommand, TYPES, configureCommand } from "sprotty"; +import { DeleteElementCommand, EditLabelMouseListener, TYPES, configureCommand } from "sprotty"; import { EditorModeController } from "./editorModeController"; import { EditorModeSwitchUi } from "./modeSwitchUi"; import { EDITOR_TYPES } from "../../utils"; -import { - EditorModeAwareDeleteElementCommand, - EditorModeAwareEditLabelMouseListener, - EditorModeAwareMoveCommand, -} from "./sprottyHooks"; +import { EditorModeAwareDeleteElementCommand, EditorModeAwareEditLabelMouseListener } from "./sprottyHooks"; import { ChangeEditorModeCommand } from "./command"; export const editorModeModule = new ContainerModule((bind, unbind, isBound, rebind) => { @@ -23,6 +19,5 @@ export const editorModeModule = new ContainerModule((bind, unbind, isBound, rebi // Sprotty hooks that hook into the edit label, move and edit module // to intercept model modifications to prevent them when the editor is in a read-only mode. rebind(EditLabelMouseListener).to(EditorModeAwareEditLabelMouseListener); - rebind(MoveCommand).to(EditorModeAwareMoveCommand); rebind(DeleteElementCommand).to(EditorModeAwareDeleteElementCommand); }); diff --git a/src/features/editorMode/editorModeController.ts b/src/features/editorMode/editorModeController.ts index 7ce217e..db4ac77 100644 --- a/src/features/editorMode/editorModeController.ts +++ b/src/features/editorMode/editorModeController.ts @@ -1,6 +1,6 @@ import { injectable } from "inversify"; -export type EditorMode = "edit" | "annotated" | "readonly"; +export type EditorMode = "edit" | "view"; /** * Holds the current editor mode in a central place. diff --git a/src/features/editorMode/modeSwitchUi.ts b/src/features/editorMode/modeSwitchUi.ts index bcba07e..26c976c 100644 --- a/src/features/editorMode/modeSwitchUi.ts +++ b/src/features/editorMode/modeSwitchUi.ts @@ -1,15 +1,12 @@ -import { AbstractUIExtension, ActionDispatcher, TYPES } from "sprotty"; +import { AbstractUIExtension } from "sprotty"; import { EditorMode, EditorModeController } from "./editorModeController"; import { inject, injectable } from "inversify"; -import { ChangeEditorModeAction } from "./command"; import "./modeSwitchUi.css"; /** * UI that shows the current editor mode (unless it is edit mode) * with details about the mode. - * For annotated mode the user can also choose to enable editing - * and switch the editor to edit mode. */ @injectable() export class EditorModeSwitchUi extends AbstractUIExtension { @@ -18,8 +15,6 @@ export class EditorModeSwitchUi extends AbstractUIExtension { constructor( @inject(EditorModeController) private readonly editorModeController: EditorModeController, - @inject(TYPES.IActionDispatcher) - private readonly actionDispatcher: ActionDispatcher, ) { super(); } @@ -44,34 +39,19 @@ export class EditorModeSwitchUi extends AbstractUIExtension { case "edit": this.containerElement.style.visibility = "hidden"; break; - case "readonly": + case "view": this.containerElement.style.visibility = "visible"; - this.renderReadonlyMode(); - break; - case "annotated": - this.containerElement.style.visibility = "visible"; - this.renderAnnotatedMode(); + this.renderViewMode(); break; default: throw new Error(`Unknown editor mode: ${mode}`); } } - private renderAnnotatedMode(): void { + private renderViewMode(): void { this.containerElement.innerHTML = ` - Currently viewing model annotations.
+ Currently viewing model in read only mode.
Enabling editing will remove the annotations.
- - `; - const enableEditingButton = this.containerElement.querySelector("#enableEditingButton"); - enableEditingButton?.addEventListener("click", () => { - this.actionDispatcher.dispatch(ChangeEditorModeAction.create("edit")); - }); - } - - private renderReadonlyMode(): void { - this.containerElement.innerHTML = ` - This diagram was generated and is readonly. `; } } diff --git a/src/features/editorMode/sprottyHooks.ts b/src/features/editorMode/sprottyHooks.ts index 1e2da90..59b070e 100644 --- a/src/features/editorMode/sprottyHooks.ts +++ b/src/features/editorMode/sprottyHooks.ts @@ -4,9 +4,7 @@ import { CommandReturn, DeleteElementCommand, EditLabelMouseListener, - MoveCommand, SModelElementImpl, - SModelRootImpl, } from "sprotty"; import { EditorModeController } from "./editorModeController"; import { Action } from "sprotty-protocol"; @@ -29,36 +27,6 @@ export class EditorModeAwareEditLabelMouseListener extends EditLabelMouseListene } } -@injectable() -export class EditorModeAwareMoveCommand extends MoveCommand { - @inject(EditorModeController) - private readonly editorModeController?: EditorModeController; - - execute(context: CommandExecutionContext): CommandReturn { - if (this.editorModeController?.isReadOnly()) { - return context.root; - } - - return super.execute(context); - } - - undo(context: CommandExecutionContext): Promise { - if (this.editorModeController?.isReadOnly()) { - return Promise.resolve(context.root); - } - - return super.undo(context); - } - - redo(context: CommandExecutionContext): Promise { - if (this.editorModeController?.isReadOnly()) { - return Promise.resolve(context.root); - } - - return super.redo(context); - } -} - @injectable() export class EditorModeAwareDeleteElementCommand extends DeleteElementCommand { @inject(EditorModeController) diff --git a/src/features/labels/labelRenderer.tsx b/src/features/labels/labelRenderer.tsx index e55d130..cc970d4 100644 --- a/src/features/labels/labelRenderer.tsx +++ b/src/features/labels/labelRenderer.tsx @@ -7,6 +7,7 @@ import { calculateTextSize } from "../../utils"; import { LabelAssignment, LabelTypeRegistry, globalLabelTypeRegistry } from "./labelTypeRegistry"; import { DeleteLabelAssignmentAction } from "./commands"; import { ContainsDfdLabels } from "./elementFeature"; +import { SettingsManager } from "../settingsMenu/SettingsManager"; @injectable() export class DfdNodeLabelRenderer { @@ -17,6 +18,7 @@ export class DfdNodeLabelRenderer { constructor( @inject(TYPES.IActionDispatcher) private readonly actionDispatcher: IActionDispatcher, + @inject(SettingsManager) private readonly settingsManager: SettingsManager, @inject(LabelTypeRegistry) @optional() private readonly labelTypeRegistry?: LabelTypeRegistry, ) {} @@ -105,7 +107,10 @@ export class DfdNodeLabelRenderer { baseY: number, xOffset = 0, labelSpacing = DfdNodeLabelRenderer.LABEL_SPACING_HEIGHT, - ): VNode { + ): VNode | undefined { + if (this.settingsManager.simplifyNodeNames) { + return undefined; + } this.sortLabels(node.labels); return ( diff --git a/src/features/serialize/analyze.ts b/src/features/serialize/analyze.ts index 65a69cb..0433044 100644 --- a/src/features/serialize/analyze.ts +++ b/src/features/serialize/analyze.ts @@ -56,7 +56,7 @@ export class AnalyzeDiagramCommand extends Command { model: modelCopy, labelTypes: this.labelTypeRegistry?.getLabelTypes(), constraints: this.constraintRegistry?.getConstraints(), - editorMode: this.editorModeController?.getCurrentMode(), + mode: this.editorModeController?.getCurrentMode(), }; const diagramJson = JSON.stringify(diagram, undefined, 4); sendMessage("Json:" + diagramJson); diff --git a/src/features/serialize/defaultDiagram.json b/src/features/serialize/defaultDiagram.json index 2c4b322..6766dcd 100644 --- a/src/features/serialize/defaultDiagram.json +++ b/src/features/serialize/defaultDiagram.json @@ -612,5 +612,5 @@ ] } ], - "editorMode": "edit" + "mode": "edit" } diff --git a/src/features/serialize/di.config.ts b/src/features/serialize/di.config.ts index 90ab59a..9ac28f3 100644 --- a/src/features/serialize/di.config.ts +++ b/src/features/serialize/di.config.ts @@ -9,6 +9,7 @@ import { AnalyzeDiagramCommand } from "./analyze"; import { LoadDFDandDDCommand } from "./loadDFDandDD"; import { SaveDFDandDDCommand } from "./saveDFDandDD"; import { LoadPalladioCommand } from "./loadPalladio"; +import { SaveImageCommand } from "./image"; export const serializeModule = new ContainerModule((bind, unbind, isBound, rebind) => { const context = { bind, unbind, isBound, rebind }; @@ -19,6 +20,7 @@ export const serializeModule = new ContainerModule((bind, unbind, isBound, rebin configureCommand(context, LoadDFDandDDCommand); configureCommand(context, SaveDFDandDDCommand); configureCommand(context, LoadPalladioCommand); + configureCommand(context, SaveImageCommand); bind(TYPES.KeyListener).to(SerializeKeyListener).inSingletonScope(); bind(TYPES.MouseListener).to(SerializeDropHandler).inSingletonScope(); diff --git a/src/features/serialize/image.ts b/src/features/serialize/image.ts new file mode 100644 index 0000000..a77bc20 --- /dev/null +++ b/src/features/serialize/image.ts @@ -0,0 +1,50 @@ +import { Command, CommandExecutionContext, CommandReturn } from "sprotty"; +// typescript does not recognize css files as modules +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +import themeCss from "../../theme.css?raw"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +import elementCss from "../dfdElements/elementStyles.css?raw"; +import { Action } from "sprotty-protocol"; +import { getModelFileName } from "../.."; + +export interface SaveImageAction extends Action { + kind: typeof SaveImageAction.KIND; +} +export namespace SaveImageAction { + export const KIND = "save-image"; + + export function create(): SaveImageAction { + return { + kind: KIND, + }; + } +} + +export class SaveImageCommand extends Command { + static readonly KIND = SaveImageAction.KIND; + execute(context: CommandExecutionContext): CommandReturn { + const root = document.getElementById("sprotty_root"); + if (!root) return context.root; + const firstChild = root.children[0]; + if (!firstChild) return context.root; + const innerSvg = firstChild.innerHTML; + const svg = `${innerSvg}`; + + const blob = new Blob([svg], { type: "image/svg+xml" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = getModelFileName() + ".svg"; + link.click(); + + return context.root; + } + undo(context: CommandExecutionContext): CommandReturn { + return context.root; + } + redo(context: CommandExecutionContext): CommandReturn { + return context.root; + } +} diff --git a/src/features/serialize/load.ts b/src/features/serialize/load.ts index b401ae7..602c1f2 100644 --- a/src/features/serialize/load.ts +++ b/src/features/serialize/load.ts @@ -194,9 +194,9 @@ export class LoadDiagramCommand extends Command { if (this.editorModeController) { // Load editor mode this.oldEditorMode = this.editorModeController.getCurrentMode(); - this.newEditorMode = newDiagram?.editorMode; - if (newDiagram?.editorMode) { - this.editorModeController.setMode(newDiagram.editorMode); + this.newEditorMode = newDiagram?.mode; + if (newDiagram?.mode) { + this.editorModeController.setMode(newDiagram.mode); } else { this.editorModeController.setDefaultMode(); } diff --git a/src/features/serialize/loadDefaultDiagram.ts b/src/features/serialize/loadDefaultDiagram.ts index a771fc6..3112ead 100644 --- a/src/features/serialize/loadDefaultDiagram.ts +++ b/src/features/serialize/loadDefaultDiagram.ts @@ -78,8 +78,8 @@ export class LoadDefaultDiagramCommand extends Command { if (this.editorModeController) { this.oldEditorMode = this.editorModeController.getCurrentMode(); - if (defaultDiagram.editorMode) { - this.editorModeController.setMode(defaultDiagram.editorMode); + if (defaultDiagram.mode) { + this.editorModeController.setMode(defaultDiagram.mode); } else { this.editorModeController.setDefaultMode(); } @@ -112,8 +112,8 @@ export class LoadDefaultDiagramCommand extends Command { this.labelTypeRegistry?.registerLabelType(labelType); }); if (this.editorModeController) { - if (defaultDiagram.editorMode) { - this.editorModeController.setMode(defaultDiagram.editorMode); + if (defaultDiagram.mode) { + this.editorModeController.setMode(defaultDiagram.mode); } else { this.editorModeController.setDefaultMode(); } diff --git a/src/features/serialize/save.ts b/src/features/serialize/save.ts index 1eb681f..6a20e79 100644 --- a/src/features/serialize/save.ts +++ b/src/features/serialize/save.ts @@ -14,7 +14,7 @@ export interface SavedDiagram { model: SModelRoot; labelTypes?: LabelType[]; constraints?: Constraint[]; - editorMode?: EditorMode; + mode?: EditorMode; } export interface SaveDiagramAction extends Action { @@ -65,7 +65,7 @@ export class SaveDiagramCommand extends Command { model: modelCopy, labelTypes: this.labelTypeRegistry?.getLabelTypes(), constraints: this.constraintRegistry?.getConstraints(), - editorMode: this.editorModeController?.getCurrentMode(), + mode: this.editorModeController?.getCurrentMode(), }; const diagramJson = JSON.stringify(diagram, undefined, 4); const jsonBlob = new Blob([diagramJson], { type: "application/json" }); diff --git a/src/features/serialize/saveDFDandDD.ts b/src/features/serialize/saveDFDandDD.ts index 5d7d13c..91573d9 100644 --- a/src/features/serialize/saveDFDandDD.ts +++ b/src/features/serialize/saveDFDandDD.ts @@ -57,7 +57,7 @@ export class SaveDFDandDDCommand extends Command { model: modelCopy, labelTypes: this.labelTypeRegistry?.getLabelTypes(), constraints: this.constraintRegistry?.getConstraints(), - editorMode: this.editorModeController?.getCurrentMode(), + mode: this.editorModeController?.getCurrentMode(), }; const diagramJson = JSON.stringify(diagram, undefined, 4); sendMessage("Json2DFD:" + getModelFileName() + ":" + diagramJson); diff --git a/src/features/settingsMenu/LayoutMethod.ts b/src/features/settingsMenu/LayoutMethod.ts new file mode 100644 index 0000000..c2890be --- /dev/null +++ b/src/features/settingsMenu/LayoutMethod.ts @@ -0,0 +1,5 @@ +export enum LayoutMethod { + LINES = "Lines", + WRAPPING = "Wrapping Lines", + CIRCLES = "Circles", +} diff --git a/src/features/settingsMenu/SettingsManager.ts b/src/features/settingsMenu/SettingsManager.ts new file mode 100644 index 0000000..88d73db --- /dev/null +++ b/src/features/settingsMenu/SettingsManager.ts @@ -0,0 +1,77 @@ +import { inject, injectable } from "inversify"; +import { ActionDispatcher, TYPES } from "sprotty"; +import { ChangeEdgeLabelVisibilityAction, CompleteLayoutProcessAction, SimplifyNodeNamesAction } from "./actions"; +import { LayoutMethod } from "./LayoutMethod"; + +@injectable() +export class SettingsManager { + private _layoutMethod: LayoutMethod = LayoutMethod.LINES; + private _layoutMethodSelect?: HTMLSelectElement; + private _hideEdgeLabels = false; + private _hideEdgeLabelsCheckbox?: HTMLInputElement; + private _simplifyNodeNames = false; + private _simplifyNodeNamesCheckbox?: HTMLInputElement; + + constructor(@inject(TYPES.IActionDispatcher) protected readonly dispatcher: ActionDispatcher) {} + + public get layoutMethod(): LayoutMethod { + return this._layoutMethod; + } + + public set layoutMethod(layoutMethod: LayoutMethod) { + this._layoutMethod = layoutMethod; + if (this._layoutMethodSelect) { + this._layoutMethodSelect.value = layoutMethod; + } + } + + public bindLayoutMethodSelect(select: HTMLSelectElement) { + this._layoutMethodSelect = select; + this._layoutMethodSelect.value = this._layoutMethod; + this._layoutMethodSelect.addEventListener("change", () => { + this.dispatcher.dispatch( + CompleteLayoutProcessAction.create(this._layoutMethodSelect!.value as LayoutMethod), + ); + }); + } + + public get hideEdgeLabels(): boolean { + return this._hideEdgeLabels; + } + + public set hideEdgeLabels(hideEdgeLabels: boolean) { + this._hideEdgeLabels = hideEdgeLabels; + if (this._hideEdgeLabelsCheckbox) { + this._hideEdgeLabelsCheckbox.checked = hideEdgeLabels; + } + } + + public bindHideEdgeLabelsCheckbox(checkbox: HTMLInputElement) { + this._hideEdgeLabelsCheckbox = checkbox; + this._hideEdgeLabelsCheckbox.checked = this._hideEdgeLabels; + this._hideEdgeLabelsCheckbox.addEventListener("change", () => { + this.dispatcher.dispatch(ChangeEdgeLabelVisibilityAction.create(this._hideEdgeLabelsCheckbox!.checked)); + }); + } + + public get simplifyNodeNames(): boolean { + return this._simplifyNodeNames; + } + + public set simplifyNodeNames(simplifyNodeNames: boolean) { + this._simplifyNodeNames = simplifyNodeNames; + if (this._simplifyNodeNamesCheckbox) { + this._simplifyNodeNamesCheckbox.checked = simplifyNodeNames; + } + } + + public bindSimplifyNodeNamesCheckbox(checkbox: HTMLInputElement) { + this._simplifyNodeNamesCheckbox = checkbox; + this._simplifyNodeNamesCheckbox.checked = this._simplifyNodeNames; + this._simplifyNodeNamesCheckbox.addEventListener("change", () => { + this.dispatcher.dispatch( + SimplifyNodeNamesAction.create(this._simplifyNodeNamesCheckbox!.checked ? "hide" : "show"), + ); + }); + } +} diff --git a/src/features/settingsMenu/actions.ts b/src/features/settingsMenu/actions.ts new file mode 100644 index 0000000..5a2c50d --- /dev/null +++ b/src/features/settingsMenu/actions.ts @@ -0,0 +1,67 @@ +import { Action } from "sprotty-protocol"; +import { LayoutMethod } from "./LayoutMethod"; +import { Theme } from "./themeManager"; + +export interface SimplifyNodeNamesAction extends Action { + kind: typeof SimplifyNodeNamesAction.KIND; + mode: SimplifyNodeNamesAction.Mode; +} +export namespace SimplifyNodeNamesAction { + export const KIND = "simplify-node-names"; + export type Mode = "hide" | "show"; + + export function create(mode?: SimplifyNodeNamesAction.Mode): SimplifyNodeNamesAction { + return { + kind: KIND, + mode: mode ?? "hide", + }; + } +} + +export interface ChangeEdgeLabelVisibilityAction extends Action { + kind: typeof ChangeEdgeLabelVisibilityAction.KIND; + hide: boolean; +} +export namespace ChangeEdgeLabelVisibilityAction { + export const KIND = "hide-edge-labels"; + + export function create(hide: boolean = true): ChangeEdgeLabelVisibilityAction { + return { kind: KIND, hide }; + } +} + +export interface CompleteLayoutProcessAction extends Action { + kind: typeof CompleteLayoutProcessAction.KIND; + method: LayoutMethod; +} +export namespace CompleteLayoutProcessAction { + export const KIND = "complete-layout-process"; + + export function create(method: LayoutMethod): CompleteLayoutProcessAction { + return { kind: KIND, method }; + } +} + +export interface ChangeThemeAction extends Action { + kind: typeof ChangeThemeAction.KIND; + theme: Theme; +} +export namespace ChangeThemeAction { + export const KIND = "change-theme"; + + export function create(theme: Theme = Theme.SYSTEM_DEFAULT): ChangeThemeAction { + return { kind: KIND, theme }; + } +} + +export interface ReSnapPortsAfterChangeAction extends Action { + kind: typeof ReSnapPortsAfterChangeAction.KIND; +} + +export namespace ReSnapPortsAfterChangeAction { + export const KIND = "resnap-ports-after-change"; + + export function create(): Action { + return { kind: KIND }; + } +} diff --git a/src/features/settingsMenu/commands.ts b/src/features/settingsMenu/commands.ts new file mode 100644 index 0000000..5f7ea41 --- /dev/null +++ b/src/features/settingsMenu/commands.ts @@ -0,0 +1,272 @@ +import { inject, injectable } from "inversify"; +import { + ActionDispatcher, + Command, + CommandExecutionContext, + CommandReturn, + CommitModelAction, + ILogger, + ISnapper, + NullLogger, + SLabelImpl, + SModelRootImpl, + SPortImpl, + TYPES, +} from "sprotty"; +import { getBasicType, RedoAction, UndoAction } from "sprotty-protocol"; +import { DfdNodeImpl } from "../dfdElements/nodes"; +import { SettingsManager } from "./SettingsManager"; +import { + ChangeEdgeLabelVisibilityAction, + ChangeThemeAction, + CompleteLayoutProcessAction, + ReSnapPortsAfterChangeAction, + SimplifyNodeNamesAction, +} from "./actions"; +import { ArrowEdgeImpl } from "../dfdElements/edges"; +import { createDefaultFitToScreenAction } from "../../utils"; +import { LayoutMethod } from "./LayoutMethod"; +import { Theme, ThemeManager } from "./themeManager"; +import { LayoutModelAction } from "../autoLayout/command"; +import { snapPortsOfNode } from "../dfdElements/portSnapper"; +import { EditorModeController } from "../editorMode/editorModeController"; + +@injectable() +export class NodeNameReplacementRegistry { + private registry: Map = new Map(); + private nextNumber = 1; + + public get(id: string) { + const v = this.registry.get(id); + if (v !== undefined) { + return v; + } + const newName = this.nextNumber.toString(); + this.nextNumber++; + this.registry.set(id, newName); + return newName; + } +} + +@injectable() +export class SimplifyNodeNamesCommand extends Command { + static readonly KIND = SimplifyNodeNamesAction.KIND; + private readonly portMove: ReSnapPortsAfterChangeCommand; + + constructor( + @inject(TYPES.Action) private action: SimplifyNodeNamesAction, + @inject(SettingsManager) private settings: SettingsManager, + @inject(NodeNameReplacementRegistry) private registry: NodeNameReplacementRegistry, + @inject(TYPES.ISnapper) snapper: ISnapper, + @inject(EditorModeController) private editorModeController: EditorModeController, + ) { + super(); + this.portMove = new ReSnapPortsAfterChangeCommand(snapper); + } + + execute(context: CommandExecutionContext): CommandReturn { + this.perform(context, this.action.mode); + return this.portMove.execute(context); + } + undo(context: CommandExecutionContext): CommandReturn { + this.perform(context, this.action.mode === "hide" ? "show" : "hide"); + return this.portMove.undo(context); + } + redo(context: CommandExecutionContext): CommandReturn { + this.perform(context, this.action.mode); + return this.portMove.redo(context); + } + + private perform(context: CommandExecutionContext, mode: SimplifyNodeNamesAction.Mode): CommandReturn { + this.settings.simplifyNodeNames = mode === "hide"; + const nodes = context.root.children.filter((node) => getBasicType(node) === "node") as DfdNodeImpl[]; + nodes.forEach((node) => { + const label = node.children.find((element) => element.type === "label:positional") as + | SLabelImpl + | undefined; + if (!label) { + return; + } + label.text = mode === "hide" ? this.registry.get(node.id) : (node.text ?? ""); + node.hideLabels = mode === "hide"; + node.minimumWidth = mode === "hide" ? DfdNodeImpl.DEFAULT_WIDTH / 2 : DfdNodeImpl.DEFAULT_WIDTH; + }); + if (mode === "hide") { + this.editorModeController.setMode("view"); + } + + return context.root; + } +} + +@injectable() +export class ChangeEdgeLabelVisibilityCommand extends Command { + static readonly KIND = ChangeEdgeLabelVisibilityAction.KIND; + + constructor( + @inject(TYPES.Action) private action: ChangeEdgeLabelVisibilityAction, + @inject(SettingsManager) private settings: SettingsManager, + @inject(EditorModeController) private editorModeController: EditorModeController, + ) { + super(); + } + + execute(context: CommandExecutionContext): CommandReturn { + return this.perform(context, this.action.hide); + } + undo(context: CommandExecutionContext): CommandReturn { + return this.perform(context, !this.action.hide); + } + redo(context: CommandExecutionContext): CommandReturn { + return this.perform(context, this.action.hide); + } + + private perform(context: CommandExecutionContext, hide: boolean): SModelRootImpl { + this.settings.hideEdgeLabels = hide; + const edges = context.root.children.filter((node) => getBasicType(node) === "edge") as ArrowEdgeImpl[]; + edges.forEach((edge) => { + const label = edge.children.find((element) => element.type === "label:filled-background") as + | SLabelImpl + | undefined; + if (!label) { + return; + } + label.text = hide ? "" : (edge.text ?? ""); + }); + if (hide) { + this.editorModeController.setMode("view"); + } + + return context.root; + } +} + +@injectable() +export class CompleteLayoutProcessCommand extends Command { + static readonly KIND = CompleteLayoutProcessAction.KIND; + private previousMethod?: LayoutMethod; + + @inject(TYPES.ILogger) + private readonly logger: ILogger = new NullLogger(); + + constructor( + @inject(TYPES.Action) private action: CompleteLayoutProcessAction, + @inject(TYPES.IActionDispatcher) private actionDispatcher: ActionDispatcher, + @inject(SettingsManager) private settings: SettingsManager, + ) { + super(); + } + + execute(context: CommandExecutionContext): CommandReturn { + this.logger.info(this, "CompleteLayoutProcessCommand", this.action.method); + this.previousMethod = this.settings.layoutMethod; + this.settings.layoutMethod = this.action.method; + this.actionDispatcher.dispatchAll([ + LayoutModelAction.create(), + CommitModelAction.create(), + createDefaultFitToScreenAction(context.root), + ]); + return context.root; + } + undo(context: CommandExecutionContext): CommandReturn { + this.settings.layoutMethod = this.previousMethod ?? LayoutMethod.LINES; + this.actionDispatcher.dispatch(UndoAction.create()); + return context.root; + } + redo(context: CommandExecutionContext): CommandReturn { + this.previousMethod = this.settings.layoutMethod; + this.settings.layoutMethod = this.action.method; + this.actionDispatcher.dispatch(RedoAction.create()); + return context.root; + } +} + +@injectable() +export class ChangeThemeCommand extends Command { + static readonly KIND = ChangeThemeAction.KIND; + private previousTheme?: Theme; + + constructor( + @inject(TYPES.Action) private action: ChangeThemeAction, + @inject(ThemeManager) private themeManager: ThemeManager, + ) { + super(); + } + + execute(context: CommandExecutionContext): CommandReturn { + this.previousTheme = this.themeManager.theme; + this.themeManager.theme = this.action.theme; + return context.root; + } + undo(context: CommandExecutionContext): CommandReturn { + this.themeManager.theme = this.previousTheme ?? Theme.SYSTEM_DEFAULT; + return context.root; + } + redo(context: CommandExecutionContext): CommandReturn { + this.previousTheme = this.themeManager.theme; + this.themeManager.theme = this.action.theme; + return context.root; + } +} + +@injectable() +export class ReSnapPortsAfterChangeCommand extends Command { + static readonly KIND = ReSnapPortsAfterChangeAction.KIND; + private previousPositions: Map = new Map(); + + constructor(@inject(TYPES.ISnapper) private readonly snapper: ISnapper) { + super(); + } + + execute(context: CommandExecutionContext): CommandReturn { + const model = context.root; + + model.children.forEach((node) => { + if (node instanceof DfdNodeImpl) { + this.savePortPositions(node); + } + }); + + model.children.forEach((node) => { + if (node instanceof DfdNodeImpl) { + snapPortsOfNode(node, this.snapper); + } + }); + return model; + } + undo(context: CommandExecutionContext): CommandReturn { + const model = context.root; + model.children.forEach((node) => { + if (node instanceof DfdNodeImpl) { + node.children.forEach((child) => { + if (child instanceof SPortImpl) { + const pos = this.previousPositions.get(child.id); + if (pos) { + child.position = pos; + } + } + }); + } + }); + return model; + } + redo(context: CommandExecutionContext): CommandReturn { + const model = context.root; + model.children.forEach((node) => { + if (node instanceof DfdNodeImpl) { + snapPortsOfNode(node, this.snapper); + } + }); + return model; + } + + private savePortPositions(element: DfdNodeImpl) { + element.children.forEach((child) => { + if (child instanceof SPortImpl) { + this.previousPositions.set(child.id, { x: child.position.x, y: child.position.y }); + } else if (child instanceof DfdNodeImpl) { + this.savePortPositions(child); + } + }); + } +} diff --git a/src/features/settingsMenu/di.config.ts b/src/features/settingsMenu/di.config.ts new file mode 100644 index 0000000..e299c6b --- /dev/null +++ b/src/features/settingsMenu/di.config.ts @@ -0,0 +1,28 @@ +import { ContainerModule } from "inversify"; +import { SettingsUI } from "./settingsMenu"; +import { ThemeManager } from "./themeManager"; +import { EDITOR_TYPES } from "../../utils"; +import { configureCommand, TYPES } from "sprotty"; +import { + ChangeEdgeLabelVisibilityCommand, + ChangeThemeCommand, + CompleteLayoutProcessCommand, + NodeNameReplacementRegistry, + SimplifyNodeNamesCommand, +} from "./commands"; +import { SettingsManager } from "./SettingsManager"; + +export const settingsModule = new ContainerModule((bind, unbind, isBound, rebind) => { + bind(SettingsManager).toSelf().inSingletonScope(); + bind(NodeNameReplacementRegistry).toSelf().inSingletonScope(); + bind(ThemeManager).toSelf().inSingletonScope(); + bind(SettingsUI).toSelf().inSingletonScope(); + bind(TYPES.IUIExtension).toService(SettingsUI); + bind(EDITOR_TYPES.DefaultUIElement).toService(SettingsUI); + const context = { bind, unbind, isBound, rebind }; + + configureCommand(context, SimplifyNodeNamesCommand); + configureCommand(context, ChangeEdgeLabelVisibilityCommand); + configureCommand(context, CompleteLayoutProcessCommand); + configureCommand(context, ChangeThemeCommand); +}); diff --git a/src/features/settingsMenu/settingsMenu.css b/src/features/settingsMenu/settingsMenu.css new file mode 100644 index 0000000..cc83959 --- /dev/null +++ b/src/features/settingsMenu/settingsMenu.css @@ -0,0 +1,109 @@ +div.settings-ui { + left: 20px; + bottom: 70px; + padding: 10px 10px; +} + +#settings-ui-accordion-label .accordion-button::before { + content: ""; + background-image: url("@fortawesome/fontawesome-free/svgs/solid/gear.svg"); + display: inline-block; + filter: invert(var(--dark-mode)); + height: 16px; + width: 16px; + background-size: 16px 16px; + vertical-align: text-top; +} + +#settings-content { + display: grid; + gap: 8px 6px; + + align-items: center; +} + +#settings-content > label { + grid-column-start: 1; +} + +#settings-content > input, +#settings-content > select, +#settings-content > label.switch { + grid-column-start: 2; +} + +#settings-content select { + background-color: var(--color-background); + color: var(--color-foreground); + border: 1px solid var(--color-foreground); + border-radius: 6px; +} + +.switch input:disabled + .slider { + background-color: color-mix(in srgb, var(--color-primary) 50%, #555 50%); +} + +.switch input:disabled + .slider:before { + background-color: color-mix(in srgb, var(--color-background) 50%, #555 50%); +} + +/* https://www.w3schools.com/HOWTO/howto_css_switch.asp */ +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 30px; + height: 17px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--color-background); + -webkit-transition: 0.4s; + transition: 0.4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 13px; + width: 13px; + left: 2px; + bottom: 2px; + background-color: var(--color-primary); + -webkit-transition: 0.3s; + transition: 0.3s; +} + +input:checked + .slider { + background-color: var(--color-background); +} + +input:checked + .slider:before { + -webkit-transform: translateX(13px); + -ms-transform: translateX(13px); + transform: translateX(13px); + background-color: var(--color-foreground); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 17px; +} + +.slider.round:before { + border-radius: 50%; +} diff --git a/src/features/settingsMenu/settingsMenu.ts b/src/features/settingsMenu/settingsMenu.ts new file mode 100644 index 0000000..9e743f8 --- /dev/null +++ b/src/features/settingsMenu/settingsMenu.ts @@ -0,0 +1,113 @@ +import { AbstractUIExtension, ActionDispatcher, TYPES } from "sprotty"; +import { inject, injectable } from "inversify"; + +import "./settingsMenu.css"; +import { Theme, ThemeManager } from "./themeManager"; +import { SettingsManager } from "./SettingsManager"; +import { LayoutMethod } from "./LayoutMethod"; +import { EditorModeController } from "../editorMode/editorModeController"; +import { ChangeEditorModeAction } from "../editorMode/command"; + +@injectable() +export class SettingsUI extends AbstractUIExtension { + static readonly ID = "settings-ui"; + + constructor( + @inject(SettingsManager) protected readonly settings: SettingsManager, + @inject(ThemeManager) protected readonly themeManager: ThemeManager, + @inject(EditorModeController) private editorModeController: EditorModeController, + @inject(TYPES.IActionDispatcher) protected readonly dispatcher: ActionDispatcher, + ) { + super(); + } + + id(): string { + return SettingsUI.ID; + } + + containerClass(): string { + return SettingsUI.ID; + } + + protected initializeContents(containerElement: HTMLElement): void { + containerElement.classList.add("ui-float"); + containerElement.innerHTML = ` + + +
+
+ + + + + + + + + + + + + +
+
+ `; + + // Set `settings-enabled` class on body element when keyboard shortcut overview is open. + const checkbox = containerElement.querySelector("#accordion-state-settings") as HTMLInputElement; + const bodyElement = document.querySelector("body") as HTMLBodyElement; + checkbox.addEventListener("change", () => { + if (checkbox.checked) { + bodyElement.classList.add("settings-enabled"); + } else { + bodyElement.classList.remove("settings-enabled"); + } + }); + + const layoutOptionSelect = containerElement.querySelector("#setting-layout-option") as HTMLSelectElement; + this.settings.bindLayoutMethodSelect(layoutOptionSelect); + + const themeOptionSelect = containerElement.querySelector("#setting-theme") as HTMLSelectElement; + this.themeManager.bindThemeSelect(themeOptionSelect); + + const hideEdgeLabelsCheckbox = containerElement.querySelector("#setting-hide-edge-labels") as HTMLInputElement; + this.settings.bindHideEdgeLabelsCheckbox(hideEdgeLabelsCheckbox); + + const simplifyNodeNamesCheckbox = containerElement.querySelector( + "#setting-simplify-node-names", + ) as HTMLInputElement; + this.settings.bindSimplifyNodeNamesCheckbox(simplifyNodeNamesCheckbox); + + const readOnlyCheckbox = containerElement.querySelector("#setting-read-only") as HTMLInputElement; + this.editorModeController.onModeChange((mode) => { + readOnlyCheckbox.checked = mode !== "edit"; + }); + if (this.editorModeController.isReadOnly()) { + readOnlyCheckbox.checked = true; + } + readOnlyCheckbox.addEventListener("change", () => { + this.dispatcher.dispatch(ChangeEditorModeAction.create(readOnlyCheckbox.checked ? "view" : "edit")); + }); + } +} diff --git a/src/features/settingsMenu/themeManager.ts b/src/features/settingsMenu/themeManager.ts new file mode 100644 index 0000000..df03c4d --- /dev/null +++ b/src/features/settingsMenu/themeManager.ts @@ -0,0 +1,68 @@ +import { inject, injectable, multiInject } from "inversify"; +import { ActionDispatcher, TYPES } from "sprotty"; +import { ChangeThemeAction } from "./actions"; + +export enum Theme { + LIGHT = "Light", + DARK = "Dark", + SYSTEM_DEFAULT = "System Default", +} + +export const SWITCHABLE = Symbol("Switchable"); + +export interface Switchable { + switchTheme(useDark: boolean): void; +} + +@injectable() +export class ThemeManager { + private static _theme: Theme = Theme.SYSTEM_DEFAULT; + private static SYSTEM_DEFAULT = + window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? Theme.DARK : Theme.LIGHT; + private themeSelect?: HTMLSelectElement; + + constructor( + @multiInject(SWITCHABLE) protected switchables: Switchable[], + @inject(TYPES.IActionDispatcher) protected readonly dispatcher: ActionDispatcher, + ) { + this.theme = ThemeManager.SYSTEM_DEFAULT; + } + + get useDarkMode(): boolean { + return ThemeManager.useDarkMode; + } + + static get useDarkMode(): boolean { + if (ThemeManager._theme == Theme.SYSTEM_DEFAULT) { + return ThemeManager.SYSTEM_DEFAULT == Theme.DARK; + } + return ThemeManager._theme == Theme.DARK; + } + + get theme(): Theme { + return ThemeManager._theme; + } + + set theme(theme: Theme) { + ThemeManager._theme = theme; + if (this.themeSelect) { + this.themeSelect.value = theme; + } + + const rootElement = document.querySelector(":root") as HTMLElement; + const sprottyElement = document.querySelector("#sprotty") as HTMLElement; + + const value = this.useDarkMode ? "dark" : "light"; + rootElement.setAttribute("data-theme", value); + sprottyElement.setAttribute("data-theme", value); + + this.switchables.forEach((s) => s.switchTheme(this.useDarkMode)); + } + + bindThemeSelect(themeSelect: HTMLSelectElement) { + this.themeSelect = themeSelect; + this.themeSelect.addEventListener("change", () => { + this.dispatcher.dispatch(ChangeThemeAction.create(themeSelect.value as Theme)); + }); + } +} diff --git a/src/index.ts b/src/index.ts index efed3ac..512cfac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ import "sprotty/css/sprotty.css"; import "sprotty/css/edit-label.css"; import "./theme.css"; import "./page.css"; +import { settingsModule } from "./features/settingsMenu/di.config"; import { LoadDiagramAction } from "./features/serialize/load"; const container = new Container(); @@ -47,6 +48,7 @@ container.load(elkLayoutModule); // Custom modules that we provide ourselves container.load( commonModule, + settingsModule, noScrollLabelEditUiModule, autoLayoutModule, dfdElementsModule, diff --git a/src/utils.ts b/src/utils.ts index 27a5848..5f64cfa 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ import { SModelRootImpl } from "sprotty"; -import { FitToScreenAction, getBasicType } from "sprotty-protocol"; +import { FitToScreenAction, getBasicType, SModelRoot } from "sprotty-protocol"; /** * Type identifiers for use with inversify. @@ -18,8 +18,8 @@ export const FIT_TO_SCREEN_PADDING = 75; * Generates a fit to screen action that fits all nodes on the screen * with the default padding. */ -export function createDefaultFitToScreenAction(root: SModelRootImpl, animate = true): FitToScreenAction { - const elementIds = root.children.filter((child) => getBasicType(child) === "node").map((child) => child.id); +export function createDefaultFitToScreenAction(root: SModelRootImpl | SModelRoot, animate = true): FitToScreenAction { + const elementIds = root.children?.filter((child) => getBasicType(child) === "node").map((child) => child.id) ?? []; return FitToScreenAction.create(elementIds, { padding: FIT_TO_SCREEN_PADDING, From 7bb1ade33b7176a7f5b3d7f986caf23e023ac8bc Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Mon, 31 Mar 2025 13:09:54 +0200 Subject: [PATCH 6/7] fix linting of config files --- eslint.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 45f424e..3881982 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -7,7 +7,7 @@ export default [ ...tseslint.configs.recommended, eslintConfigPrettier, { - ignores: ['**/*.config.ts', 'node_modules/**', 'dist/**'] + ignores: ['node_modules/**', 'dist/**'] }, { files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'], From 9df08af272dff1c1c325a4ac900fc52974960a88 Mon Sep 17 00:00:00 2001 From: Alex | Kronox Date: Mon, 31 Mar 2025 13:11:05 +0200 Subject: [PATCH 7/7] fix build --- src/features/dfdElements/edges.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/dfdElements/edges.tsx b/src/features/dfdElements/edges.tsx index 363eaf5..5e36360 100644 --- a/src/features/dfdElements/edges.tsx +++ b/src/features/dfdElements/edges.tsx @@ -90,7 +90,7 @@ export class ArrowEdgeView extends PolylineEdgeViewWithGapsOnIntersections { return ( - {this.renderLine(edge, route, context, args)} + {this.renderLine(edge, route)} {this.renderAdditionals(edge, route, context)} {this.renderJunctionPoints(edge, route, context, args)} {this.settings.hideEdgeLabels ? [] : context.renderChildren(edge, { route })}