diff --git a/.babelrc b/.babelrc index 55de8382c..493f22b9c 100644 --- a/.babelrc +++ b/.babelrc @@ -6,7 +6,8 @@ "useBuiltIns": "entry", "corejs": "3.22" } - ] + ], + "@babel/preset-typescript" ], "plugins": [ "html-tag-js/jsx/jsx-to-tag.js", diff --git a/.vscode/settings.json b/.vscode/settings.json index ad71d61d3..1b8d58126 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -372,5 +372,8 @@ "wxss", "xquery", "Zeek" - ] + ], + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + } } \ No newline at end of file diff --git a/bun.lock b/bun.lock index aeb4d6a11..0cba7d950 100644 --- a/bun.lock +++ b/bun.lock @@ -1,11 +1,38 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "com.foxdebug.acode", "dependencies": { + "@codemirror/autocomplete": "^6.20.0", + "@codemirror/commands": "^6.10.0", + "@codemirror/lang-cpp": "^6.0.3", + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-go": "^6.0.1", + "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-java": "^6.0.2", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.2", + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-php": "^6.0.2", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/lang-rust": "^6.0.2", + "@codemirror/lang-sass": "^6.0.2", + "@codemirror/lang-vue": "^0.1.3", + "@codemirror/lang-xml": "^6.1.0", + "@codemirror/lang-yaml": "^6.1.2", + "@codemirror/language": "^6.11.3", + "@codemirror/language-data": "^6.5.2", + "@codemirror/legacy-modes": "^6.5.2", + "@codemirror/lint": "^6.9.2", + "@codemirror/lsp-client": "^6.2.1", + "@codemirror/search": "^6.5.11", + "@codemirror/state": "^6.5.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.38.8", "@deadlyjack/ajax": "^1.2.6", + "@emmetio/codemirror6-plugin": "^0.4.0", + "@lezer/highlight": "^1.2.3", "@ungap/custom-elements": "^1.3.0", "@xterm/addon-attach": "^0.11.0", "@xterm/addon-fit": "^0.10.0", @@ -15,52 +42,58 @@ "@xterm/addon-web-links": "^0.11.0", "@xterm/addon-webgl": "^0.18.0", "@xterm/xterm": "^5.5.0", + "acorn": "^8.15.0", "autosize": "^6.0.1", + "codemirror": "^6.0.2", "cordova": "13.0.0", - "core-js": "^3.45.0", + "core-js": "^3.47.0", "crypto-js": "^4.2.0", - "dompurify": "^3.2.6", + "dayjs": "^1.11.19", + "dompurify": "^3.3.0", "escape-string-regexp": "^5.0.0", "esprima": "^4.0.1", - "filesize": "^11.0.2", - "html-tag-js": "^2.4.15", - "js-base64": "^3.7.7", + "filesize": "^11.0.13", + "html-tag-js": "^2.4.16", + "js-base64": "^3.7.8", "jszip": "^3.10.1", - "markdown-it": "^14.1.0", + "markdown-it": "^14.1.1", "markdown-it-anchor": "^9.2.0", "markdown-it-footnote": "^4.0.0", "markdown-it-github-alerts": "^1.0.0", "markdown-it-task-lists": "^2.1.1", "mime-types": "^3.0.1", - "minimatch": "^10.0.3", - "moment": "^2.30.1", "mustache": "^4.2.0", + "picomatch": "^4.0.3", "url-parse": "^1.5.10", "vanilla-picker": "^2.12.3", "yargs": "^18.0.0", }, "devDependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-runtime": "^7.28.0", - "@babel/preset-env": "^7.28.0", - "@babel/runtime": "^7.28.2", - "@babel/runtime-corejs3": "^7.28.2", + "@babel/core": "^7.28.5", + "@babel/plugin-transform-runtime": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", + "@babel/runtime": "^7.28.4", + "@babel/runtime-corejs3": "^7.28.4", "@biomejs/biome": "2.1.4", + "@rspack/cli": "^1.7.0", + "@rspack/core": "^1.7.0", "@types/ace": "^0.0.52", "@types/url-parse": "^1.4.11", - "autoprefixer": "^10.4.21", + "autoprefixer": "^10.4.22", "babel-loader": "^10.0.0", "com.foxdebug.acode.rk.auth": "file:src/plugins/auth", "com.foxdebug.acode.rk.customtabs": "file:src/plugins/custom-tabs", "com.foxdebug.acode.rk.exec.proot": "file:src/plugins/proot", "com.foxdebug.acode.rk.exec.terminal": "file:src/plugins/terminal", + "com.foxdebug.acode.rk.plugin.plugincontext": "file:src/plugins/pluginContext", "cordova-android": "^14.0.1", "cordova-clipboard": "^1.3.0", "cordova-plugin-advanced-http": "^3.3.1", "cordova-plugin-browser": "file:src/plugins/browser", "cordova-plugin-buildinfo": "file:src/plugins/cordova-plugin-buildinfo", - "cordova-plugin-device": "^2.0.3", - "cordova-plugin-file": "^8.0.1", + "cordova-plugin-device": "^2.1.0", + "cordova-plugin-file": "^8.1.3", "cordova-plugin-ftp": "file:src/plugins/ftp", "cordova-plugin-iap": "file:src/plugins/iap", "cordova-plugin-sdcard": "file:src/plugins/sdcard", @@ -69,49 +102,50 @@ "cordova-plugin-system": "file:src/plugins/system", "cordova-plugin-websocket": "file:src/plugins/websocket", "css-loader": "^7.1.2", - "mini-css-extract-plugin": "^2.9.3", + "mini-css-extract-plugin": "^2.9.4", "path-browserify": "^1.0.1", - "postcss-loader": "^8.1.1", - "prettier": "^3.6.2", - "prettier-plugin-java": "^2.7.4", + "postcss-loader": "^8.2.0", + "prettier": "^3.7.4", + "prettier-plugin-java": "^2.7.7", "raw-loader": "^4.0.2", - "sass": "^1.90.0", - "sass-loader": "^16.0.5", + "sass": "^1.94.2", + "sass-loader": "^16.0.6", "style-loader": "^4.0.0", "terminal": "^0.1.4", - "webpack": "^5.101.0", + "ts-loader": "^9.5.4", + "typescript": "^5.9.3", + "vscode-languageserver-types": "^3.17.5", + "webpack": "^5.105.0", "webpack-cli": "^6.0.1", }, }, }, "packages": { - "@ampproject/remapping": ["@ampproject/remapping@2.2.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" } }, ""], - "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="], + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], - "@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], + "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], - "@babel/generator": ["@babel/generator@7.28.0", "", { "dependencies": { "@babel/parser": "^7.28.0", "@babel/types": "^7.28.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg=="], + "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], - "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A=="], + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ=="], - "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ=="], + "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="], "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.5", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "debug": "^4.4.1", "lodash.debounce": "^4.0.8", "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg=="], "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA=="], + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.27.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg=="], + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], @@ -125,17 +159,17 @@ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.27.1", "", { "dependencies": { "@babel/template": "^7.27.1", "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ=="], + "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2" } }, "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g=="], - "@babel/helpers": ["@babel/helpers@7.28.2", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw=="], + "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" } }, "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g=="], + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA=="], + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ["@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q=="], "@babel/plugin-bugfix-safari-class-field-initializer-scope": ["@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA=="], @@ -143,15 +177,19 @@ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ["@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw=="], - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw=="], + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ["@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw=="], - "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, ""], + "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2", "", { "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w=="], "@babel/plugin-syntax-import-assertions": ["@babel/plugin-syntax-import-assertions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg=="], "@babel/plugin-syntax-import-attributes": ["@babel/plugin-syntax-import-attributes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww=="], - "@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, ""], + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="], + + "@babel/plugin-syntax-unicode-sets-regex": ["@babel/plugin-syntax-unicode-sets-regex@7.18.6", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg=="], "@babel/plugin-transform-arrow-functions": ["@babel/plugin-transform-arrow-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA=="], @@ -161,17 +199,17 @@ "@babel/plugin-transform-block-scoped-functions": ["@babel/plugin-transform-block-scoped-functions@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg=="], - "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q=="], + "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g=="], "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], - "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA=="], + "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.3", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg=="], - "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.0", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA=="], + "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="], "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/template": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw=="], - "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A=="], + "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="], "@babel/plugin-transform-dotall-regex": ["@babel/plugin-transform-dotall-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw=="], @@ -183,7 +221,7 @@ "@babel/plugin-transform-explicit-resource-management": ["@babel/plugin-transform-explicit-resource-management@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ=="], - "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ=="], + "@babel/plugin-transform-exponentiation-operator": ["@babel/plugin-transform-exponentiation-operator@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw=="], "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="], @@ -195,7 +233,7 @@ "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="], - "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw=="], + "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA=="], "@babel/plugin-transform-member-expression-literals": ["@babel/plugin-transform-member-expression-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ=="], @@ -203,7 +241,7 @@ "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw=="], - "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA=="], + "@babel/plugin-transform-modules-systemjs": ["@babel/plugin-transform-modules-systemjs@7.28.5", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew=="], "@babel/plugin-transform-modules-umd": ["@babel/plugin-transform-modules-umd@7.27.1", "", { "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w=="], @@ -215,13 +253,13 @@ "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw=="], - "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.0", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA=="], + "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.4", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew=="], "@babel/plugin-transform-object-super": ["@babel/plugin-transform-object-super@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng=="], "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q=="], - "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg=="], + "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ=="], "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], @@ -231,13 +269,13 @@ "@babel/plugin-transform-property-literals": ["@babel/plugin-transform-property-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ=="], - "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg=="], + "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.28.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA=="], "@babel/plugin-transform-regexp-modifiers": ["@babel/plugin-transform-regexp-modifiers@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA=="], "@babel/plugin-transform-reserved-words": ["@babel/plugin-transform-reserved-words@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw=="], - "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.28.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-dGopk9nZrtCs2+nfIem25UuHyt5moSJamArzIoh9/vezUQPmYDOzjaHDCkAzuGJibCIkPup8rMT2+wYB6S73cA=="], + "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.28.5", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w=="], "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="], @@ -249,6 +287,8 @@ "@babel/plugin-transform-typeof-symbol": ["@babel/plugin-transform-typeof-symbol@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw=="], + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA=="], + "@babel/plugin-transform-unicode-escapes": ["@babel/plugin-transform-unicode-escapes@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg=="], "@babel/plugin-transform-unicode-property-regex": ["@babel/plugin-transform-unicode-property-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q=="], @@ -257,19 +297,21 @@ "@babel/plugin-transform-unicode-sets-regex": ["@babel/plugin-transform-unicode-sets-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw=="], - "@babel/preset-env": ["@babel/preset-env@7.28.0", "", { "dependencies": { "@babel/compat-data": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.0", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-classes": "^7.28.0", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.27.1", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.0", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.27.1", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.0", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg=="], + "@babel/preset-env": ["@babel/preset-env@7.28.5", "", { "dependencies": { "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", "@babel/plugin-transform-class-static-block": "^7.28.3", "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-spread": "^7.27.1", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", "@babel/plugin-transform-unicode-property-regex": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg=="], + + "@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA=="], - "@babel/preset-modules": ["@babel/preset-modules@0.1.6-no-external-plugins", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, ""], + "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="], - "@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], - "@babel/runtime-corejs3": ["@babel/runtime-corejs3@7.28.2", "", { "dependencies": { "core-js-pure": "^3.43.0" } }, "sha512-FVFaVs2/dZgD3Y9ZD+AKNKjyGKzwu0C54laAXWUXgLcVXcCX6YZ6GhK2cp7FogSN2OA0Fu+QT8dP3FUdo9ShSQ=="], + "@babel/runtime-corejs3": ["@babel/runtime-corejs3@7.28.4", "", { "dependencies": { "core-js-pure": "^3.43.0" } }, "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ=="], "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/types": "^7.28.0", "debug": "^4.3.1" } }, "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg=="], + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], - "@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="], + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], "@biomejs/biome": ["@biomejs/biome@2.1.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.1.4", "@biomejs/cli-darwin-x64": "2.1.4", "@biomejs/cli-linux-arm64": "2.1.4", "@biomejs/cli-linux-arm64-musl": "2.1.4", "@biomejs/cli-linux-x64": "2.1.4", "@biomejs/cli-linux-x64-musl": "2.1.4", "@biomejs/cli-win32-arm64": "2.1.4", "@biomejs/cli-win32-x64": "2.1.4" }, "bin": { "biome": "bin/biome" } }, "sha512-QWlrqyxsU0FCebuMnkvBIkxvPqH89afiJzjMl+z67ybutse590jgeaFdDurE9XYtzpjRGTI1tlUZPGWmbKsElA=="], @@ -299,9 +341,89 @@ "@chevrotain/utils": ["@chevrotain/utils@11.0.3", "", {}, "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ=="], - "@deadlyjack/ajax": ["@deadlyjack/ajax@1.2.6", "", {}, ""], + "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg=="], + + "@codemirror/commands": ["@codemirror/commands@6.10.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q=="], + + "@codemirror/lang-angular": ["@codemirror/lang-angular@0.1.4", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/lang-javascript": "^6.1.2", "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.3" } }, "sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g=="], + + "@codemirror/lang-cpp": ["@codemirror/lang-cpp@6.0.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/cpp": "^1.0.0" } }, "sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA=="], + + "@codemirror/lang-css": ["@codemirror/lang-css@6.3.1", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.2", "@lezer/css": "^1.1.7" } }, "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg=="], + + "@codemirror/lang-go": ["@codemirror/lang-go@6.0.1", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/go": "^1.0.0" } }, "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg=="], + + "@codemirror/lang-html": ["@codemirror/lang-html@6.4.11", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-javascript": "^6.0.0", "@codemirror/language": "^6.4.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/css": "^1.1.0", "@lezer/html": "^1.3.12" } }, "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw=="], + + "@codemirror/lang-java": ["@codemirror/lang-java@6.0.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/java": "^1.0.0" } }, "sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ=="], + + "@codemirror/lang-javascript": ["@codemirror/lang-javascript@6.2.4", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", "@codemirror/lint": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/javascript": "^1.0.0" } }, "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA=="], + + "@codemirror/lang-jinja": ["@codemirror/lang-jinja@6.0.0", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.2.0", "@lezer/lr": "^1.4.0" } }, "sha512-47MFmRcR8UAxd8DReVgj7WJN1WSAMT7OJnewwugZM4XiHWkOjgJQqvEM1NpMj9ALMPyxmlziEI1opH9IaEvmaw=="], + + "@codemirror/lang-json": ["@codemirror/lang-json@6.0.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/json": "^1.0.0" } }, "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ=="], + + "@codemirror/lang-less": ["@codemirror/lang-less@6.0.2", "", { "dependencies": { "@codemirror/lang-css": "^6.2.0", "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-EYdQTG22V+KUUk8Qq582g7FMnCZeEHsyuOJisHRft/mQ+ZSZ2w51NupvDUHiqtsOy7It5cHLPGfHQLpMh9bqpQ=="], + + "@codemirror/lang-liquid": ["@codemirror/lang-liquid@6.3.1", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.1" } }, "sha512-S/jE/D7iij2Pu70AC65ME6AYWxOOcX20cSJvaPgY5w7m2sfxsArAcUAuUgm/CZCVmqoi9KiOlS7gj/gyLipABw=="], + + "@codemirror/lang-markdown": ["@codemirror/lang-markdown@6.5.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.7.1", "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.3.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.2.1", "@lezer/markdown": "^1.0.0" } }, "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw=="], + + "@codemirror/lang-php": ["@codemirror/lang-php@6.0.2", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/php": "^1.0.0" } }, "sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA=="], + + "@codemirror/lang-python": ["@codemirror/lang-python@6.2.1", "", { "dependencies": { "@codemirror/autocomplete": "^6.3.2", "@codemirror/language": "^6.8.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.2.1", "@lezer/python": "^1.1.4" } }, "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw=="], + + "@codemirror/lang-rust": ["@codemirror/lang-rust@6.0.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/rust": "^1.0.0" } }, "sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA=="], + + "@codemirror/lang-sass": ["@codemirror/lang-sass@6.0.2", "", { "dependencies": { "@codemirror/lang-css": "^6.2.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.2", "@lezer/sass": "^1.0.0" } }, "sha512-l/bdzIABvnTo1nzdY6U+kPAC51czYQcOErfzQ9zSm9D8GmNPD0WTW8st/CJwBTPLO8jlrbyvlSEcN20dc4iL0Q=="], + + "@codemirror/lang-sql": ["@codemirror/lang-sql@6.10.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w=="], + + "@codemirror/lang-vue": ["@codemirror/lang-vue@0.1.3", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/lang-javascript": "^6.1.2", "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.1" } }, "sha512-QSKdtYTDRhEHCfo5zOShzxCmqKJvgGrZwDQSdbvCRJ5pRLWBS7pD/8e/tH44aVQT6FKm0t6RVNoSUWHOI5vNug=="], + + "@codemirror/lang-wast": ["@codemirror/lang-wast@6.0.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q=="], + + "@codemirror/lang-xml": ["@codemirror/lang-xml@6.1.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.4.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/xml": "^1.0.0" } }, "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg=="], + + "@codemirror/lang-yaml": ["@codemirror/lang-yaml@6.1.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.2.0", "@lezer/lr": "^1.0.0", "@lezer/yaml": "^1.0.0" } }, "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw=="], + + "@codemirror/language": ["@codemirror/language@6.12.1", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ=="], + + "@codemirror/language-data": ["@codemirror/language-data@6.5.2", "", { "dependencies": { "@codemirror/lang-angular": "^0.1.0", "@codemirror/lang-cpp": "^6.0.0", "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-go": "^6.0.0", "@codemirror/lang-html": "^6.0.0", "@codemirror/lang-java": "^6.0.0", "@codemirror/lang-javascript": "^6.0.0", "@codemirror/lang-jinja": "^6.0.0", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-less": "^6.0.0", "@codemirror/lang-liquid": "^6.0.0", "@codemirror/lang-markdown": "^6.0.0", "@codemirror/lang-php": "^6.0.0", "@codemirror/lang-python": "^6.0.0", "@codemirror/lang-rust": "^6.0.0", "@codemirror/lang-sass": "^6.0.0", "@codemirror/lang-sql": "^6.0.0", "@codemirror/lang-vue": "^0.1.1", "@codemirror/lang-wast": "^6.0.0", "@codemirror/lang-xml": "^6.0.0", "@codemirror/lang-yaml": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/legacy-modes": "^6.4.0" } }, "sha512-CPkWBKrNS8stYbEU5kwBwTf3JB1kghlbh4FSAwzGW2TEscdeHHH4FGysREW86Mqnj3Qn09s0/6Ea/TutmoTobg=="], + + "@codemirror/legacy-modes": ["@codemirror/legacy-modes@6.5.2", "", { "dependencies": { "@codemirror/language": "^6.0.0" } }, "sha512-/jJbwSTazlQEDOQw2FJ8LEEKVS72pU0lx6oM54kGpL8t/NJ2Jda3CZ4pcltiKTdqYSRk3ug1B3pil1gsjA6+8Q=="], + + "@codemirror/lint": ["@codemirror/lint@6.9.2", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ=="], + + "@codemirror/lsp-client": ["@codemirror/lsp-client@6.2.1", "", { "dependencies": { "@codemirror/autocomplete": "^6.20.0", "@codemirror/language": "^6.11.0", "@codemirror/lint": "^6.8.5", "@codemirror/state": "^6.5.2", "@codemirror/view": "^6.37.0", "@lezer/highlight": "^1.2.1", "marked": "^15.0.12", "vscode-languageserver-protocol": "^3.17.5" } }, "sha512-fjEkEc+H0kG60thaybj5+UpSnt49yAaTzOLSYZC2wlhwNAtDsWO2uZnE2AXiRGQxBVDQBvVj01MsX3F/0Vivjg=="], + + "@codemirror/search": ["@codemirror/search@6.5.11", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "crelt": "^1.0.5" } }, "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA=="], + + "@codemirror/state": ["@codemirror/state@6.5.3", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A=="], + + "@codemirror/theme-one-dark": ["@codemirror/theme-one-dark@6.1.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/highlight": "^1.0.0" } }, "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA=="], + + "@codemirror/view": ["@codemirror/view@6.39.9", "", { "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-miGSIfBOKC1s2oHoa80dp+BjtsL8sXsrgGlQnQuOcfvaedcQUtqddTmKbJSDkLl4mkgPvZyXuKic2HDNYcJLYA=="], + + "@deadlyjack/ajax": ["@deadlyjack/ajax@1.2.6", "", {}, "sha512-VwZU8YUflO2/V/dl3dluu+3jg8Ghz/W5fwxD5Z21OZXKeV73d+vStKVBe4wi+Av2KbTR35K7Z+5Q3iIpjB41MA=="], + + "@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.5.7", "", {}, "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="], + + "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], + + "@emmetio/codemirror6-plugin": ["@emmetio/codemirror6-plugin@0.4.0", "", { "dependencies": { "@emmetio/math-expression": "^1.0.5", "emmet": "^2.4.11" }, "peerDependencies": { "@codemirror/autocomplete": "^6.17.0", "@codemirror/commands": "^6.6.0", "@codemirror/lang-css": "^6.2.1", "@codemirror/lang-html": "^6.4.9", "@codemirror/language": "^6.10.2", "@codemirror/state": "^6.4.1", "@codemirror/view": "^6.29.1" } }, "sha512-ZP3W8JvN0cEFTdsrcKPIBg/K9sadE15g//TfubPXfM28ZxUp3SwNASbRfRLRQmPyP73+pAZzLqeOwACUUz/oAw=="], - "@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.6.3", "", {}, "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ=="], + "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], + + "@emmetio/math-expression": ["@emmetio/math-expression@1.0.5", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-qf5SXD/ViS04rXSeDg9CRGM10xLC9dVaKIbMHrrwxYr5LNB/C0rOfokhGSBwnVQKcidLmdRJeNWH1V1tppZ84Q=="], + + "@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="], + + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], @@ -311,29 +433,109 @@ "@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.1.1", "", { "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" } }, ""], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@jsonjoy.com/base64": ["@jsonjoy.com/base64@1.1.2", "", { "peerDependencies": { "tslib": "2" } }, "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA=="], + + "@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-eBrIXd0/Ld3p9lpDDlMaMn6IEfWqtHMD+z61u0JrIiPzsV1r7m6xDZFRxJyvIFTEO+SWdYF9EiQbXZGd8BzPfA=="], + + "@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@1.0.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g=="], + + "@jsonjoy.com/fs-core": ["@jsonjoy.com/fs-core@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-PyAEA/3cnHhsGcdY+AmIU+ZPqTuZkDhCXQ2wkXypdLitSpd6d5Ivxhnq4wa2ETRWFVJGabYynBWxIijOswSmOw=="], + + "@jsonjoy.com/fs-fsa": ["@jsonjoy.com/fs-fsa@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-/FVK63ysNzTPOnCCcPoPHt77TOmachdMS422txM4KhxddLdbW1fIbFMYH0AM0ow/YchCyS5gqEjKLNyv71j/5Q=="], + + "@jsonjoy.com/fs-node": ["@jsonjoy.com/fs-node@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "@jsonjoy.com/fs-print": "4.56.10", "@jsonjoy.com/fs-snapshot": "4.56.10", "glob-to-regex.js": "^1.0.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-7R4Gv3tkUdW3dXfXiOkqxkElxKNVdd8BDOWC0/dbERd0pXpPY+s2s1Mino+aTvkGrFPiY+mmVxA7zhskm4Ue4Q=="], + + "@jsonjoy.com/fs-node-builtins": ["@jsonjoy.com/fs-node-builtins@4.56.10", "", { "peerDependencies": { "tslib": "2" } }, "sha512-uUnKz8R0YJyKq5jXpZtkGV9U0pJDt8hmYcLRrPjROheIfjMXsz82kXMgAA/qNg0wrZ1Kv+hrg7azqEZx6XZCVw=="], + + "@jsonjoy.com/fs-node-to-fsa": ["@jsonjoy.com/fs-node-to-fsa@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-fsa": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10" }, "peerDependencies": { "tslib": "2" } }, "sha512-oH+O6Y4lhn9NyG6aEoFwIBNKZeYy66toP5LJcDOMBgL99BKQMUf/zWJspdRhMdn/3hbzQsZ8EHHsuekbFLGUWw=="], + + "@jsonjoy.com/fs-node-utils": ["@jsonjoy.com/fs-node-utils@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-node-builtins": "4.56.10" }, "peerDependencies": { "tslib": "2" } }, "sha512-8EuPBgVI2aDPwFdaNQeNpHsyqPi3rr+85tMNG/lHvQLiVjzoZsvxA//Xd8aB567LUhy4QS03ptT+unkD/DIsNg=="], + + "@jsonjoy.com/fs-print": ["@jsonjoy.com/fs-print@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-node-utils": "4.56.10", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-JW4fp5mAYepzFsSGrQ48ep8FXxpg4niFWHdF78wDrFGof7F3tKDJln72QFDEn/27M1yHd4v7sKHHVPh78aWcEw=="], + + "@jsonjoy.com/fs-snapshot": ["@jsonjoy.com/fs-snapshot@4.56.10", "", { "dependencies": { "@jsonjoy.com/buffers": "^17.65.0", "@jsonjoy.com/fs-node-utils": "4.56.10", "@jsonjoy.com/json-pack": "^17.65.0", "@jsonjoy.com/util": "^17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-DkR6l5fj7+qj0+fVKm/OOXMGfDFCGXLfyHkORH3DF8hxkpDgIHbhf/DwncBMs2igu/ST7OEkexn1gIqoU6Y+9g=="], + + "@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@1.21.0", "", { "dependencies": { "@jsonjoy.com/base64": "^1.1.2", "@jsonjoy.com/buffers": "^1.2.0", "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/json-pointer": "^1.0.2", "@jsonjoy.com/util": "^1.9.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg=="], + + "@jsonjoy.com/json-pointer": ["@jsonjoy.com/json-pointer@1.0.2", "", { "dependencies": { "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/util": "^1.9.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg=="], + + "@jsonjoy.com/util": ["@jsonjoy.com/util@1.9.0", "", { "dependencies": { "@jsonjoy.com/buffers": "^1.0.0", "@jsonjoy.com/codegen": "^1.0.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ=="], + + "@leichtgewicht/ip-codec": ["@leichtgewicht/ip-codec@2.0.5", "", {}, "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw=="], + + "@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/cpp": ["@lezer/cpp@1.1.5", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw=="], + + "@lezer/css": ["@lezer/css@1.3.0", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.0" } }, "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw=="], + + "@lezer/go": ["@lezer/go@1.0.1", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.0" } }, "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ=="], + + "@lezer/highlight": ["@lezer/highlight@1.2.3", "", { "dependencies": { "@lezer/common": "^1.3.0" } }, "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g=="], + + "@lezer/html": ["@lezer/html@1.3.13", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg=="], + + "@lezer/java": ["@lezer/java@1.1.3", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw=="], + + "@lezer/javascript": ["@lezer/javascript@1.5.4", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.1.3", "@lezer/lr": "^1.3.0" } }, "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA=="], + + "@lezer/json": ["@lezer/json@1.0.3", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ=="], + + "@lezer/lr": ["@lezer/lr@1.4.7", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-wNIFWdSUfX9Jc6ePMzxSPVgTVB4EOfDIwLQLWASyiUdHKaMsiilj9bYiGkGQCKVodd0x6bgQCV207PILGFCF9Q=="], + + "@lezer/markdown": ["@lezer/markdown@1.6.3", "", { "dependencies": { "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0" } }, "sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw=="], + + "@lezer/php": ["@lezer/php@1.0.5", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.1.0" } }, "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA=="], + + "@lezer/python": ["@lezer/python@1.1.18", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg=="], + + "@lezer/rust": ["@lezer/rust@1.0.2", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg=="], - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.0", "", {}, ""], + "@lezer/sass": ["@lezer/sass@1.1.0", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-3mMGdCTUZ/84ArHOuXWQr37pnf7f+Nw9ycPUeKX+wu19b7pSMcZGLbaXwvD2APMBDOGxPmpK/O6S1v1EvLoqgQ=="], - "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + "@lezer/xml": ["@lezer/xml@1.0.6", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww=="], - "@jridgewell/source-map": ["@jridgewell/source-map@0.3.10", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q=="], + "@lezer/yaml": ["@lezer/yaml@1.0.3", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.4.0" } }, "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA=="], - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="], + "@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], + "@module-federation/error-codes": ["@module-federation/error-codes@0.22.0", "", {}, "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug=="], - "@netflix/nerror": ["@netflix/nerror@1.1.3", "", { "dependencies": { "assert-plus": "^1.0.0", "extsprintf": "^1.4.0", "lodash": "^4.17.15" } }, ""], + "@module-federation/runtime": ["@module-federation/runtime@0.22.0", "", { "dependencies": { "@module-federation/error-codes": "0.22.0", "@module-federation/runtime-core": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA=="], - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, ""], + "@module-federation/runtime-core": ["@module-federation/runtime-core@0.22.0", "", { "dependencies": { "@module-federation/error-codes": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA=="], - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, ""], + "@module-federation/runtime-tools": ["@module-federation/runtime-tools@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/webpack-bundler-runtime": "0.22.0" } }, "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA=="], - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, ""], + "@module-federation/sdk": ["@module-federation/sdk@0.22.0", "", {}, "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g=="], + + "@module-federation/webpack-bundler-runtime": ["@module-federation/webpack-bundler-runtime@0.22.0", "", { "dependencies": { "@module-federation/runtime": "0.22.0", "@module-federation/sdk": "0.22.0" } }, "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.0.7", "", { "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", "@tybys/wasm-util": "^0.10.1" } }, "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw=="], + + "@netflix/nerror": ["@netflix/nerror@1.1.3", "", { "dependencies": { "assert-plus": "^1.0.0", "extsprintf": "^1.4.0", "lodash": "^4.17.15" } }, "sha512-b+MGNyP9/LXkapreJzNUzcvuzZslj/RGgdVVJ16P2wSlYatfLycPObImqVJSmNAdyeShvNeM/pl3sVZsObFueg=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], "@npmcli/agent": ["@npmcli/agent@4.0.0", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA=="], - "@npmcli/arborist": ["@npmcli/arborist@9.1.8", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^1.0.1", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-TYAzq0oaXQU+uLfXFbR2wYx62qHIOSg/TYhGWJSphJDypyjdNXC7B/+k29ElC2vWlWfX4OJnhmSY5DTwSFiNpg=="], + "@npmcli/arborist": ["@npmcli/arborist@9.1.9", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^1.0.1", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-O/rLeBo64mkUn1zU+1tFDWXvbAA9UXe9eUldwTwRLxOLFx9obqjNoozW65LmYqgWb0DG40i9lNZSv78VX2GKhw=="], "@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="], @@ -387,32 +589,82 @@ "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], + "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], + + "@rspack/binding": ["@rspack/binding@1.7.3", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.3", "@rspack/binding-darwin-x64": "1.7.3", "@rspack/binding-linux-arm64-gnu": "1.7.3", "@rspack/binding-linux-arm64-musl": "1.7.3", "@rspack/binding-linux-x64-gnu": "1.7.3", "@rspack/binding-linux-x64-musl": "1.7.3", "@rspack/binding-wasm32-wasi": "1.7.3", "@rspack/binding-win32-arm64-msvc": "1.7.3", "@rspack/binding-win32-ia32-msvc": "1.7.3", "@rspack/binding-win32-x64-msvc": "1.7.3" } }, "sha512-N943pbPktJPymiYZWZMZMVX/PeSU42cWGpBly82N+ibNCX/Oo4yKWE0v+TyIJm5JaUFhtF2NpvzRbrjg/6skqw=="], + + "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sXha3xG2KDkXLVjrmnw5kGhBriH2gFd9KAyD2ZBq0sH/gNIvqEaWhAFoO1YtrKU6rCgiSBrs0frfGc6DEqWfTA=="], + + "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-AUWMBgaPo7NgpW7arlw9laj9ZQxg7EjC5pnSCRH4BVPV+8egdoPCn5DZk05M25m73crKnGl8c7CrwTRNZeaPrw=="], + + "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-SodEX3+1/GLz0LobX9cY1QdjJ1NftSEh4C2vGpr71iA3MS9HyXuw4giqSeRQ4DpCybqpdS/3RLjVqFQEfGpcnw=="], + + "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-ydD2fNdEy+G7EYJ/a3FfdFZPfrLj/UnZocCNlZTTSHEhu+jURdQk0hwV11CvL+sjnKU5e/8IVMGUzhu3Gu8Ghg=="], + + "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.3", "", { "os": "linux", "cpu": "x64" }, "sha512-adnDbUqafSAI6/N6vZ+iONSo1W3yUpnNtJqP3rVp7+YdABhUpbOhtaY37qpIJ3uFajXctYFyISPrb4MWl1M9Yg=="], + + "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.3", "", { "os": "linux", "cpu": "x64" }, "sha512-5jnjdODk5HCUFPN6rTaFukynDU4Fn9eCL+4TSp6mqo6YAnfnJEuzDjfetA8t3aQFcAs7WriQfNwvdcA4HvYtbA=="], + + "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-WLQK0ksUzMkVeGoHAMIxenmeEU5tMvFDK36Aip7VRj7T6vZTcAwvbMwc38QrIAvlG7dqWoxgPQi35ba1igNNDw=="], + + "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-RAetPeY45g2NW6fID46VTV7mwY4Lqyw/flLbvCG28yrVOSkekw1KMCr1k335O3VNeqD+5dZDi1n+mwiAx/KMmA=="], + + "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-X3c1B609DxzW++FdWf7kkoXWwsC/DUEJ1N1qots4T0P2G2V+pDQfjdTRSC0YQ75toAvwZqpwGzToQJ9IwQ4Ayw=="], + + "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.3", "", { "os": "win32", "cpu": "x64" }, "sha512-f6AvZbJGIg+7NggHXv0+lyMzvIUfeCxcB5DNbo3H5AalIgwkoFpcBXLBqgMVIbqA0yNyP06eiK98rpzc9ulQQg=="], + + "@rspack/cli": ["@rspack/cli@1.7.3", "", { "dependencies": { "@discoveryjs/json-ext": "^0.5.7", "@rspack/dev-server": "~1.1.5", "exit-hook": "^4.0.0", "webpack-bundle-analyzer": "4.10.2" }, "peerDependencies": { "@rspack/core": "^1.0.0-alpha || ^1.x" }, "bin": { "rspack": "bin/rspack.js" } }, "sha512-6fb+cd1RjCK3ByN8oq7dIXZWFkbI7+y7VGlIvt/Nl2roGnL3IzXhEbyQzmXv9X+/fZ/pEKHWEyH05Rnqs3+VUQ=="], + + "@rspack/core": ["@rspack/core@1.7.3", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.3", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-GUiTRTz6+gbfM2g3ixXqrvPSeHmyAFu/qHEZZjbYFeDtZhpy1gVaVAHiZfaaIIm+vRlNi7JmULWFZQFKwpQB9Q=="], + + "@rspack/dev-server": ["@rspack/dev-server@1.1.5", "", { "dependencies": { "chokidar": "^3.6.0", "http-proxy-middleware": "^2.0.9", "p-retry": "^6.2.0", "webpack-dev-server": "5.2.2", "ws": "^8.18.0" }, "peerDependencies": { "@rspack/core": "*" } }, "sha512-cwz0qc6iqqoJhyWqxP7ZqE2wyYNHkBMQUXxoQ0tNoZ4YNRkDyQ4HVJ/3oPSmMKbvJk/iJ16u7xZmwG6sK47q/A=="], + + "@rspack/lite-tapable": ["@rspack/lite-tapable@1.1.0", "", {}, "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw=="], + "@sigstore/bundle": ["@sigstore/bundle@4.0.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A=="], - "@sigstore/core": ["@sigstore/core@3.0.0", "", {}, "sha512-NgbJ+aW9gQl/25+GIEGYcCyi8M+ng2/5X04BMuIgoDfgvp18vDcoNHOQjQsG9418HGNYRxG3vfEXaR1ayD37gg=="], + "@sigstore/core": ["@sigstore/core@3.1.0", "", {}, "sha512-o5cw1QYhNQ9IroioJxpzexmPjfCe7gzafd2RY3qnMpxr4ZEja+Jad/U8sgFpaue6bOaF+z7RVkyKVV44FN+N8A=="], "@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.5.0", "", {}, "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA=="], - "@sigstore/sign": ["@sigstore/sign@4.0.1", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.0.0", "@sigstore/protobuf-specs": "^0.5.0", "make-fetch-happen": "^15.0.2", "proc-log": "^5.0.0", "promise-retry": "^2.0.1" } }, "sha512-KFNGy01gx9Y3IBPG/CergxR9RZpN43N+lt3EozEfeoyqm8vEiLxwRl3ZO5sPx3Obv1ix/p7FWOlPc2Jgwfp9PA=="], + "@sigstore/sign": ["@sigstore/sign@4.1.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0", "make-fetch-happen": "^15.0.3", "proc-log": "^6.1.0", "promise-retry": "^2.0.1" } }, "sha512-Vx1RmLxLGnSUqx/o5/VsCjkuN5L7y+vxEEwawvc7u+6WtX2W4GNa7b9HEjmcRWohw/d6BpATXmvOwc78m+Swdg=="], - "@sigstore/tuf": ["@sigstore/tuf@4.0.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0", "tuf-js": "^4.0.0" } }, "sha512-0QFuWDHOQmz7t66gfpfNO6aEjoFrdhkJaej/AOqb4kqWZVbPWFZifXZzkxyQBB1OwTbkhdT3LNpMFxwkTvf+2w=="], + "@sigstore/tuf": ["@sigstore/tuf@4.0.1", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0", "tuf-js": "^4.1.0" } }, "sha512-OPZBg8y5Vc9yZjmWCHrlWPMBqW5yd8+wFNl+thMdtcWz3vjVSoJQutF8YkrzI0SLGnkuFof4HSsWUhXrf219Lw=="], - "@sigstore/verify": ["@sigstore/verify@3.0.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.0.0", "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-moXtHH33AobOhTZF8xcX1MpOFqdvfCk7v6+teJL8zymBiDXwEsQH6XG9HGx2VIxnJZNm4cNSzflTLDnQLmIdmw=="], + "@sigstore/verify": ["@sigstore/verify@3.1.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag=="], - "@sphinxxxx/color-conversion": ["@sphinxxxx/color-conversion@2.2.2", "", {}, ""], + "@sphinxxxx/color-conversion": ["@sphinxxxx/color-conversion@2.2.2", "", {}, "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw=="], "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], - "@tufjs/models": ["@tufjs/models@4.0.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^9.0.5" } }, "sha512-h5x5ga/hh82COe+GoD4+gKUeV4T3iaYOxqLt41GRKApinPI7DMidhCmNVTjKfhCWFJIGXaFJee07XczdT4jdZQ=="], + "@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/ace": ["@types/ace@0.0.52", "", {}, "sha512-YPF9S7fzpuyrxru+sG/rrTpZkC6gpHBPF14W3x70kqVOD+ks6jkYLapk4yceh36xej7K4HYxcyz9ZDQ2lTvwgQ=="], + "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], + + "@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="], + + "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], + + "@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.5.4", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw=="], + "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], "@types/eslint-scope": ["@types/eslint-scope@3.7.7", "", { "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@types/express": ["@types/express@4.17.25", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "^1" } }, "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw=="], + + "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.8", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA=="], + + "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], + + "@types/http-proxy": ["@types/http-proxy@1.17.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw=="], + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], "@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="], @@ -421,13 +673,33 @@ "@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], - "@types/node": ["@types/node@24.2.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ=="], + "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], + + "@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="], + + "@types/node-forge": ["@types/node-forge@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw=="], + + "@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="], + + "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], + + "@types/retry": ["@types/retry@0.12.2", "", {}, "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow=="], + + "@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], + + "@types/serve-index": ["@types/serve-index@1.9.4", "", { "dependencies": { "@types/express": "*" } }, "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug=="], + + "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], + + "@types/sockjs": ["@types/sockjs@0.3.36", "", { "dependencies": { "@types/node": "*" } }, "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q=="], "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], "@types/url-parse": ["@types/url-parse@1.4.11", "", {}, "sha512-FKvKIqRaykZtd4n47LbK/W/5fhQQ1X7cxxzG9A48h0BGN+S04NH7ervcCjM8tyR0lyGru83FAHSmw2ObgKoESg=="], - "@ungap/custom-elements": ["@ungap/custom-elements@1.3.0", "", {}, ""], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "@ungap/custom-elements": ["@ungap/custom-elements@1.3.0", "", {}, "sha512-f4q/s76+8nOy+fhrNHyetuoPDR01lmlZB5czfCG+OOnBw/Wf+x48DcCDPmMQY7oL8xYFL8qfenMoiS8DUkKBUw=="], "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], @@ -465,7 +737,7 @@ "@webpack-cli/serve": ["@webpack-cli/serve@3.0.1", "", { "peerDependencies": { "webpack": "^5.82.0", "webpack-cli": "6.x.x" } }, "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg=="], - "@xmldom/xmldom": ["@xmldom/xmldom@0.8.10", "", {}, "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw=="], + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="], "@xterm/addon-attach": ["@xterm/addon-attach@0.11.0", "", { "peerDependencies": { "@xterm/xterm": "^5.0.0" } }, "sha512-JboCN0QAY6ZLY/SSB/Zl2cQ5zW1Eh4X3fH7BnuR1NB7xGRhzbqU2Npmpiw/3zFlxDaU88vtKzok44JKi2L2V2Q=="], @@ -489,35 +761,45 @@ "abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], - "acorn": ["acorn@8.15.0", "", { "bin": "bin/acorn" }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], "acorn-import-phases": ["acorn-import-phases@1.0.4", "", { "peerDependencies": { "acorn": "^8.14.0" } }, "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ=="], + "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "ajv": ["ajv@8.12.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, ""], + "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" }, "peerDependencies": { "ajv": "^8.0.0" } }, ""], + "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], - "ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, ""], + "ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], "android-versions": ["android-versions@2.1.0", "", { "dependencies": { "semver": "^7.5.2" } }, "sha512-oCBvVs2uaL8ohQtesGs78/X7QvFDLbKgTosBRiOIBCss1a/yiakQm/ADuoG2k/AUaI0FfrsFeMl/a+GtEtjEeA=="], - "ansi": ["ansi@0.3.1", "", {}, ""], + "ansi": ["ansi@0.3.1", "", {}, "sha512-iFY7JCgHbepc0b82yLaw4IMortylNb6wG4kL+4R0C3iv6i+RHGHux/yUX5BTiRvSX/shMnngjR1YyNMnXEFh5A=="], + + "ansi-html-community": ["ansi-html-community@0.0.8", "", { "bin": { "ansi-html": "bin/ansi-html" } }, "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw=="], + + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], - "assert-plus": ["assert-plus@1.0.0", "", {}, ""], + "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], - "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": "bin/autoprefixer" }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="], + "autoprefixer": ["autoprefixer@10.4.23", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001760", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA=="], - "autosize": ["autosize@6.0.1", "", {}, ""], + "autosize": ["autosize@6.0.1", "", {}, "sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ=="], "babel-loader": ["babel-loader@10.0.0", "", { "dependencies": { "find-up": "^5.0.0" }, "peerDependencies": { "@babel/core": "^7.12.0", "webpack": ">=5.61.0" } }, "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA=="], @@ -527,31 +809,51 @@ "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.5", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, ""], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.9.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-WhtvB2NG2wjr04+h77sg3klAIwrgOqnjS49GGudnUPGFFgg7G17y7Qecqp+2Dr5kUDxNRBca0SK7cG8JwzkWDQ=="], - "base64-js": ["base64-js@1.5.1", "", {}, ""], + "batch": ["batch@0.6.1", "", {}, "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="], - "big-integer": ["big-integer@1.6.51", "", {}, ""], + "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="], - "big.js": ["big.js@5.2.2", "", {}, ""], + "big.js": ["big.js@5.2.2", "", {}, "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="], "bin-links": ["bin-links@6.0.0", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w=="], - "bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.x" } }, ""], + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="], + + "bonjour-service": ["bonjour-service@1.3.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA=="], + + "bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browserslist": ["browserslist@4.25.2", "", { "dependencies": { "caniuse-lite": "^1.0.30001733", "electron-to-chromium": "^1.5.199", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": "cli.js" }, "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA=="], + "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + "cacache": ["cacache@20.0.3", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0", "unique-filename": "^5.0.0" } }, "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw=="], - "callsites": ["callsites@3.1.0", "", {}, ""], + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - "caniuse-lite": ["caniuse-lite@1.0.30001733", "", {}, "sha512-e4QKw/O2Kavj2VQTKZWrwzkt3IxOmIlU6ajRb6LP64LHpBo1J67k2Hi4Vu/TgJWsNtynurfS0uK3MaUTCPfu5Q=="], + "caniuse-lite": ["caniuse-lite@1.0.30001763", "", {}, "sha512-mh/dGtq56uN98LlNX9qdbKnzINhX0QzhiWBFEkFfsFO4QyCvL8YegrJAazCwXIeqkIob8BlZPGM3xdnY+sgmvQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chevrotain": ["chevrotain@11.0.3", "", { "dependencies": { "@chevrotain/cst-dts-gen": "11.0.3", "@chevrotain/gast": "11.0.3", "@chevrotain/regexp-to-ast": "11.0.3", "@chevrotain/types": "11.0.3", "@chevrotain/utils": "11.0.3", "lodash-es": "4.17.21" } }, "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw=="], @@ -561,7 +863,7 @@ "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - "chrome-trace-event": ["chrome-trace-event@1.0.3", "", {}, ""], + "chrome-trace-event": ["chrome-trace-event@1.0.4", "", {}, "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ=="], "cli": ["cli@1.0.1", "", { "dependencies": { "exit": "0.1.2", "glob": "^7.1.1" } }, "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg=="], @@ -571,7 +873,13 @@ "cmd-shim": ["cmd-shim@8.0.0", "", {}, "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA=="], - "colorette": ["colorette@2.0.19", "", {}, ""], + "codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], "com.foxdebug.acode.rk.auth": ["com.foxdebug.acode.rk.auth@file:src/plugins/auth", {}], @@ -581,25 +889,41 @@ "com.foxdebug.acode.rk.exec.terminal": ["com.foxdebug.acode.rk.exec.terminal@file:src/plugins/terminal", {}], + "com.foxdebug.acode.rk.plugin.plugincontext": ["com.foxdebug.acode.rk.plugin.plugincontext@file:src/plugins/pluginContext", {}], + "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], - "concat-map": ["concat-map@0.0.1", "", {}, ""], + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], - "configstore": ["configstore@5.0.1", "", { "dependencies": { "dot-prop": "^5.2.0", "graceful-fs": "^4.1.2", "make-dir": "^3.0.0", "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" } }, ""], + "compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "configstore": ["configstore@5.0.1", "", { "dependencies": { "dot-prop": "^5.2.0", "graceful-fs": "^4.1.2", "make-dir": "^3.0.0", "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" } }, "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA=="], + + "connect-history-api-fallback": ["connect-history-api-fallback@2.0.0", "", {}, "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA=="], "console-browserify": ["console-browserify@1.1.0", "", { "dependencies": { "date-now": "^0.1.4" } }, "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg=="], + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "cordova": ["cordova@13.0.0", "", { "dependencies": { "configstore": "^5.0.1", "cordova-common": "^6.0.0", "cordova-create": "^6.0.0", "cordova-lib": "^13.0.0", "editor": "^1.0.0", "execa": "^5.1.1", "nopt": "^9.0.0", "semver": "^7.7.3", "systeminformation": "^5.27.11" }, "bin": "bin/cordova" }, "sha512-QAIMwmYLL0jHo4vauWSnRd2fr9l+wajG+F5aUkrC6e4ZQGSTv0wAiRmpqQUkIc1ZdELisKDQws/BjHz5nP/sLw=="], + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.0.7", "", {}, "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA=="], + + "cordova": ["cordova@13.0.0", "", { "dependencies": { "configstore": "^5.0.1", "cordova-common": "^6.0.0", "cordova-create": "^6.0.0", "cordova-lib": "^13.0.0", "editor": "^1.0.0", "execa": "^5.1.1", "nopt": "^9.0.0", "semver": "^7.7.3", "systeminformation": "^5.27.11" }, "bin": { "cordova": "bin/cordova" } }, "sha512-QAIMwmYLL0jHo4vauWSnRd2fr9l+wajG+F5aUkrC6e4ZQGSTv0wAiRmpqQUkIc1ZdELisKDQws/BjHz5nP/sLw=="], "cordova-android": ["cordova-android@14.0.1", "", { "dependencies": { "android-versions": "^2.1.0", "cordova-common": "^5.0.1", "dedent": "^1.5.3", "execa": "^5.1.1", "fast-glob": "^3.3.3", "is-path-inside": "^3.0.3", "nopt": "^8.1.0", "properties-parser": "^0.6.0", "semver": "^7.7.1", "string-argv": "^0.3.1", "untildify": "^4.0.0", "which": "^5.0.0" } }, "sha512-HMBMdGu/JlSQtmBuDEpKWf/pE75SpF3FksxZ+mqYuL3qSIN8lN/QsNurwYaPAP7zWXN2DNpvwlpOJItS5VhdLg=="], "cordova-app-hello-world": ["cordova-app-hello-world@7.0.0", "", {}, "sha512-uDTncFkI73ko+wEf6IEO9bw8lQRMQGnfdi5pPMei4P8+plChNcRW5fxjKlhM/8ZrT8OAWiHsQRrP4pIAn3HQ4g=="], - "cordova-clipboard": ["cordova-clipboard@1.3.0", "", {}, ""], + "cordova-clipboard": ["cordova-clipboard@1.3.0", "", {}, "sha512-IGk4LZm/DJ0Xk/jgakHm4wa+A/lrRP3QfzMAHDG7oWLJS4ISOpfI32Wez4ndnENItRslGyBVyJyKD83CxELCAw=="], "cordova-common": ["cordova-common@5.0.1", "", { "dependencies": { "@netflix/nerror": "^1.1.3", "ansi": "^0.3.1", "bplist-parser": "^0.3.2", "cross-spawn": "^7.0.6", "elementtree": "^0.1.7", "endent": "^2.1.0", "fast-glob": "^3.3.3", "lodash.zip": "^4.2.0", "plist": "^3.1.0", "q": "^1.5.1", "read-chunk": "^3.2.0", "strip-bom": "^4.0.0" } }, "sha512-OA2NQ6wvhNz4GytPYwTdlA9xfG7Yf7ufkj4u97m3rUfoL/AECwwj0GVT2CYpk/0Fk6HyuHA3QYCxfDPYsKzI1A=="], @@ -613,11 +937,11 @@ "cordova-plugin-browser": ["cordova-plugin-browser@file:src/plugins/browser", {}], - "cordova-plugin-buildinfo": ["/cordova-plugin-buildinfo@file:src/plugins/cordova-plugin-buildinfo", { "devDependencies": { "jshint": "^2.6.0" } }], + "cordova-plugin-buildinfo": ["cordova-plugin-buildinfo@file:src/plugins/cordova-plugin-buildinfo", { "devDependencies": { "jshint": "^2.6.0" } }], - "cordova-plugin-device": ["cordova-plugin-device@2.1.0", "", {}, ""], + "cordova-plugin-device": ["cordova-plugin-device@2.1.0", "", {}, "sha512-FU0Lw1jZpuKOgG4v80LrfMAOIMCGfAVPumn7AwaX9S1iU/X3OPZUyoKUgP09q4bxL35IeNPkqNWVKYduAXZ1sg=="], - "cordova-plugin-file": ["cordova-plugin-file@8.0.1", "", {}, "sha512-LgFLNQN58xguoJkNc8eGBmg/Vuaah9lY3Nye27OAfWCKalXPRjExIg5r8L3qlfiJxzmzupjrF0M4KdU2Lovm3Q=="], + "cordova-plugin-file": ["cordova-plugin-file@8.1.3", "", {}, "sha512-KlnP3CapNIsKncoWV5lYcIFYDPl0aZ1J3AH3QESlQX1Cb6Ct0p6GrAUvINyrFsjPbWHj8i0b6la6udVsghbATg=="], "cordova-plugin-ftp": ["cordova-plugin-ftp@file:src/plugins/ftp", {}], @@ -633,219 +957,323 @@ "cordova-plugin-websocket": ["cordova-plugin-websocket@file:src/plugins/websocket", {}], - "core-js": ["core-js@3.45.0", "", {}, "sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA=="], + "core-js": ["core-js@3.47.0", "", {}, "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg=="], - "core-js-compat": ["core-js-compat@3.45.0", "", { "dependencies": { "browserslist": "^4.25.1" } }, "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA=="], + "core-js-compat": ["core-js-compat@3.47.0", "", { "dependencies": { "browserslist": "^4.28.0" } }, "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ=="], - "core-js-pure": ["core-js-pure@3.45.0", "", {}, "sha512-OtwjqcDpY2X/eIIg1ol/n0y/X8A9foliaNt1dSK0gV3J2/zw+89FcNG3mPK+N8YWts4ZFUPxnrAzsxs/lf8yDA=="], + "core-js-pure": ["core-js-pure@3.47.0", "", {}, "sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw=="], - "core-util-is": ["core-util-is@1.0.3", "", {}, ""], + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], "cosmiconfig": ["cosmiconfig@9.0.0", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg=="], + "crelt": ["crelt@1.0.6", "", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], - "crypto-random-string": ["crypto-random-string@2.0.0", "", {}, ""], + "crypto-random-string": ["crypto-random-string@2.0.0", "", {}, "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="], - "css-loader": ["css-loader@7.1.2", "", { "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", "postcss-modules-extract-imports": "^3.1.0", "postcss-modules-local-by-default": "^4.0.5", "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "webpack": "^5.27.0" }, "optionalPeers": ["@rspack/core"] }, "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA=="], + "css-loader": ["css-loader@7.1.2", "", { "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", "postcss-modules-extract-imports": "^3.1.0", "postcss-modules-local-by-default": "^4.0.5", "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", "semver": "^7.5.4" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "webpack": "^5.27.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA=="], - "cssesc": ["cssesc@3.0.0", "", { "bin": "bin/cssesc" }, ""], + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], "date-now": ["date-now@0.1.4", "", {}, "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw=="], - "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + "dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="], + + "debounce": ["debounce@1.2.1", "", {}, "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "dedent": ["dedent@1.7.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ=="], + "dedent": ["dedent@1.7.1", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg=="], + + "default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="], + + "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], + + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], - "detect-libc": ["detect-libc@1.0.3", "", { "bin": "bin/detect-libc.js" }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], "detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="], + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + "dns-packet": ["dns-packet@5.6.1", "", { "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" } }, "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw=="], + "dom-serializer": ["dom-serializer@0.2.2", "", { "dependencies": { "domelementtype": "^2.0.1", "entities": "^2.0.0" } }, "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g=="], "domelementtype": ["domelementtype@1.3.1", "", {}, "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="], "domhandler": ["domhandler@2.3.0", "", { "dependencies": { "domelementtype": "1" } }, "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ=="], - "dompurify": ["dompurify@3.2.6", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ=="], + "dompurify": ["dompurify@3.3.1", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q=="], "domutils": ["domutils@1.5.1", "", { "dependencies": { "dom-serializer": "0", "domelementtype": "1" } }, "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw=="], - "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, ""], + "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "duplexer": ["duplexer@0.1.2", "", {}, "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="], - "editor": ["editor@1.0.0", "", {}, ""], + "editor": ["editor@1.0.0", "", {}, "sha512-SoRmbGStwNYHgKfjOrX2L0mUvp9bUVv0uPppZSOMAntEbcFtoC3MKF5b3T6HQPXKIV+QGY3xPO3JK5it5lVkuw=="], - "electron-to-chromium": ["electron-to-chromium@1.5.199", "", {}, "sha512-3gl0S7zQd88kCAZRO/DnxtBKuhMO4h0EaQIN3YgZfV6+pW+5+bf2AdQeHNESCoaQqo/gjGVYEf2YM4O5HJQqpQ=="], + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "elementtree": ["elementtree@0.1.7", "", { "dependencies": { "sax": "1.1.4" } }, ""], + "electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="], - "emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], + "elementtree": ["elementtree@0.1.7", "", { "dependencies": { "sax": "1.1.4" } }, "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg=="], - "emojis-list": ["emojis-list@3.0.0", "", {}, ""], + "emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "emojis-list": ["emojis-list@3.0.0", "", {}, "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="], - "endent": ["endent@2.1.0", "", { "dependencies": { "dedent": "^0.7.0", "fast-json-parse": "^1.0.3", "objectorarray": "^1.0.5" } }, ""], + "endent": ["endent@2.1.0", "", { "dependencies": { "dedent": "^0.7.0", "fast-json-parse": "^1.0.3", "objectorarray": "^1.0.5" } }, "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w=="], - "enhanced-resolve": ["enhanced-resolve@5.18.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww=="], + "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], - "env-paths": ["env-paths@2.2.1", "", {}, ""], + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], - "envinfo": ["envinfo@7.14.0", "", { "bin": "dist/cli.js" }, "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg=="], + "envinfo": ["envinfo@7.21.0", "", { "bin": { "envinfo": "dist/cli.js" } }, "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow=="], "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], - "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-module-lexer": ["es-module-lexer@1.2.1", "", {}, ""], + "es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, ""], + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], - "eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, ""], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], - "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" } }, ""], + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, ""], + "estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], - "estraverse": ["estraverse@4.3.0", "", {}, ""], + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - "esutils": ["esutils@2.0.3", "", {}, ""], + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], - "events": ["events@3.3.0", "", {}, ""], + "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], - "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, ""], + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], "exit": ["exit@0.1.2", "", {}, "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ=="], + "exit-hook": ["exit-hook@4.0.0", "", {}, "sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ=="], + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], - "extsprintf": ["extsprintf@1.4.1", "", {}, ""], + "express": ["express@4.22.1", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.3", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "~1.3.1", "fresh": "~0.5.2", "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", "serve-static": "~1.16.2", "setprototypeof": "1.2.0", "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, ""], + "extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-glob": ["fast-glob@3.3.3", "", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - "fast-json-parse": ["fast-json-parse@1.0.3", "", {}, ""], + "fast-json-parse": ["fast-json-parse@1.0.3", "", {}, "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, ""], + "fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", {}, "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="], - "fastest-levenshtein": ["fastest-levenshtein@1.0.16", "", {}, ""], + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], - "fastq": ["fastq@1.15.0", "", { "dependencies": { "reusify": "^1.0.4" } }, ""], + "faye-websocket": ["faye-websocket@0.11.4", "", { "dependencies": { "websocket-driver": ">=0.5.1" } }, "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g=="], - "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "filesize": ["filesize@11.0.2", "", {}, "sha512-s/iAeeWLk5BschUIpmdrF8RA8lhFZ/xDZgKw1Tan72oGws1/dFGB06nYEiyyssWUfjKNQTNRlrwMVjO9/hvXDw=="], + "filesize": ["filesize@11.0.13", "", {}, "sha512-mYJ/qXKvREuO0uH8LTQJ6v7GsUvVOguqxg2VTwQUkyTPXXRRWPdjuUPVqdBrJQhvci48OHlNGRnux+Slr2Rnvw=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + "finalhandler": ["finalhandler@1.3.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="], + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - "flat": ["flat@5.0.2", "", { "bin": "cli.js" }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], + "flat": ["flat@5.0.2", "", { "bin": { "flat": "cli.js" } }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], + + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], - "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], + + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], - "fs.realpath": ["fs.realpath@1.0.0", "", {}, ""], + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, ""], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], - "get-caller-file": ["get-caller-file@2.0.5", "", {}, ""], + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], - "get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-stream": ["get-stream@6.0.1", "", {}, ""], + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, ""], + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, ""], + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "glob-to-regex.js": ["glob-to-regex.js@1.2.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ=="], "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "gzip-size": ["gzip-size@6.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="], + + "handle-thing": ["handle-thing@2.0.1", "", {}, "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "hosted-git-info": ["hosted-git-info@9.0.2", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg=="], - "html-tag-js": ["html-tag-js@2.4.15", "", {}, "sha512-ll1CsDRYPQiUYv8DPUUnDy6k9CTwc7jMObXr7BYV6iuLm7ZUZ4ZSo5CjaU7qh1qL7S4TGaGT+JKqYXksa8dWrg=="], + "hpack.js": ["hpack.js@2.1.6", "", { "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", "readable-stream": "^2.0.1", "wbuf": "^1.1.0" } }, "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ=="], + + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], + + "html-tag-js": ["html-tag-js@2.4.16", "", {}, "sha512-emVNouMF3t2yXpnnjgxCgkMY2W1ZrVC47qsHIJpPKgaH94Nqv355T7E1ZRkV6mWa3vLImHklH7vEcSURDhfq/A=="], "htmlparser2": ["htmlparser2@3.8.3", "", { "dependencies": { "domelementtype": "1", "domhandler": "2.3", "domutils": "1.5", "entities": "1.0", "readable-stream": "1.1" } }, "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q=="], "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + "http-deceiver": ["http-deceiver@1.2.7", "", {}, "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw=="], + + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "http-parser-js": ["http-parser-js@0.5.10", "", {}, "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA=="], + + "http-proxy": ["http-proxy@1.18.1", "", { "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ=="], + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + "http-proxy-middleware": ["http-proxy-middleware@2.0.9", "", { "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", "micromatch": "^4.0.2" }, "peerDependencies": { "@types/express": "^4.17.13" }, "optionalPeers": ["@types/express"] }, "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q=="], + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "human-signals": ["human-signals@2.1.0", "", {}, ""], + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "hyperdyperid": ["hyperdyperid@1.2.0", "", {}, "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A=="], - "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "icss-utils": ["icss-utils@5.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, ""], + "icss-utils": ["icss-utils@5.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], - "immediate": ["immediate@3.0.6", "", {}, ""], + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], - "immutable": ["immutable@5.1.3", "", {}, "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg=="], + "immutable": ["immutable@5.1.4", "", {}, "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA=="], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - "import-local": ["import-local@3.1.0", "", { "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, ""], + "import-local": ["import-local@3.2.0", "", { "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA=="], - "imurmurhash": ["imurmurhash@0.1.4", "", {}, ""], + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, ""], + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], - "inherits": ["inherits@2.0.4", "", {}, ""], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], - "interpret": ["interpret@3.1.1", "", {}, ""], + "interpret": ["interpret@3.1.1", "", {}, "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ=="], "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="], + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - "is-extglob": ["is-extglob@2.1.1", "", {}, ""], + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, ""], + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + + "is-network-error": ["is-network-error@1.3.0", "", {}, "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-obj": ["is-obj@2.0.0", "", {}, ""], + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], "is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="], + "is-plain-obj": ["is-plain-obj@3.0.0", "", {}, "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA=="], + "is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="], - "is-stream": ["is-stream@2.0.1", "", {}, ""], + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], - "is-typedarray": ["is-typedarray@1.0.0", "", {}, ""], + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], - "isarray": ["isarray@1.0.0", "", {}, ""], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], "isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], @@ -855,29 +1283,29 @@ "jest-worker": ["jest-worker@27.5.1", "", { "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" } }, "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="], - "jiti": ["jiti@1.21.0", "", { "bin": "bin/jiti.js" }, "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q=="], + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="], + "js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="], "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], - "jsesc": ["jsesc@3.1.0", "", { "bin": "bin/jsesc" }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - "jshint": ["jshint@2.13.6", "", { "dependencies": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", "lodash": "~4.17.21", "minimatch": "~3.0.2", "strip-json-comments": "1.0.x" }, "bin": "bin/jshint" }, "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ=="], + "jshint": ["jshint@2.13.6", "", { "dependencies": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", "lodash": "~4.17.21", "minimatch": "~3.0.2", "strip-json-comments": "1.0.x" }, "bin": { "jshint": "bin/jshint" } }, "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ=="], - "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, ""], + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], - "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, ""], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], - "json5": ["json5@2.2.3", "", { "bin": "lib/cli.js" }, ""], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], - "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, ""], + "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="], "just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="], @@ -885,33 +1313,35 @@ "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], - "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, ""], + "launch-editor": ["launch-editor@2.12.0", "", { "dependencies": { "picocolors": "^1.1.1", "shell-quote": "^1.8.3" } }, "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg=="], + + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], - "loader-runner": ["loader-runner@4.3.0", "", {}, ""], + "loader-runner": ["loader-runner@4.3.1", "", {}, "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q=="], - "loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, ""], + "loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - "lodash": ["lodash@4.17.21", "", {}, ""], + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], - "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, ""], + "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], - "lodash.zip": ["lodash.zip@4.2.0", "", {}, ""], + "lodash.zip": ["lodash.zip@4.2.0", "", {}, "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg=="], "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, ""], + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], "make-fetch-happen": ["make-fetch-happen@15.0.3", "", { "dependencies": { "@npmcli/agent": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "promise-retry": "^2.0.1", "ssri": "^13.0.0" } }, "sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw=="], - "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": "bin/markdown-it.mjs" }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], + "markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], "markdown-it-anchor": ["markdown-it-anchor@9.2.0", "", { "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" } }, "sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg=="], @@ -921,23 +1351,39 @@ "markdown-it-task-lists": ["markdown-it-task-lists@2.1.1", "", {}, "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA=="], + "marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], - "merge-stream": ["merge-stream@2.0.0", "", {}, ""], + "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + + "memfs": ["memfs@4.56.10", "", { "dependencies": { "@jsonjoy.com/fs-core": "4.56.10", "@jsonjoy.com/fs-fsa": "4.56.10", "@jsonjoy.com/fs-node": "4.56.10", "@jsonjoy.com/fs-node-builtins": "4.56.10", "@jsonjoy.com/fs-node-to-fsa": "4.56.10", "@jsonjoy.com/fs-node-utils": "4.56.10", "@jsonjoy.com/fs-print": "4.56.10", "@jsonjoy.com/fs-snapshot": "4.56.10", "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", "thingies": "^2.5.0", "tree-dump": "^1.0.3", "tslib": "^2.0.0" } }, "sha512-eLvzyrwqLHnLYalJP7YZ3wBe79MXktMdfQbvMrVD80K+NhrIukCVBvgP30zTJYEEDh9hZ/ep9z0KOdD7FSHo7w=="], + + "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], - "merge2": ["merge2@1.4.1", "", {}, ""], + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "mimic-fn": ["mimic-fn@2.1.0", "", {}, ""], + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - "mini-css-extract-plugin": ["mini-css-extract-plugin@2.9.3", "", { "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" }, "peerDependencies": { "webpack": "^5.0.0" } }, "sha512-tRA0+PsS4kLVijnN1w9jUu5lkxBwUk9E8SbgEB5dBJqchE6pVYdawROG6uQtpmAri7tdCK9i7b1bULeVWqS6Ag=="], + "mini-css-extract-plugin": ["mini-css-extract-plugin@2.9.4", "", { "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" }, "peerDependencies": { "webpack": "^5.0.0" } }, "sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ=="], - "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], + + "minimatch": ["minimatch@3.0.8", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q=="], "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], @@ -953,27 +1399,31 @@ "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], - "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "mustache": ["mustache@4.2.0", "", { "bin": "bin/mustache" }, ""], + "multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": { "multicast-dns": "cli.js" } }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="], + + "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], - "nanoid": ["nanoid@3.3.7", "", { "bin": "bin/nanoid.cjs" }, "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="], + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], - "neo-async": ["neo-async@2.6.2", "", {}, ""], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], - "node-gyp": ["node-gyp@12.1.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^15.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.2", "tinyglobby": "^0.2.12", "which": "^6.0.0" }, "bin": "bin/node-gyp.js" }, "sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g=="], + "node-forge": ["node-forge@1.3.3", "", {}, "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg=="], - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + "node-gyp": ["node-gyp@12.1.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "make-fetch-happen": "^15.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.2", "tinyglobby": "^0.2.12", "which": "^6.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g=="], - "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": "bin/nopt.js" }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], - "normalize-range": ["normalize-range@0.1.2", "", {}, ""], + "nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], "npm-bundled": ["npm-bundled@5.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^5.0.0" } }, "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw=="], @@ -989,15 +1439,27 @@ "npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" } }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="], - "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, ""], + "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "objectorarray": ["objectorarray@1.0.5", "", {}, "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg=="], + + "obuf": ["obuf@1.1.2", "", {}, "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], - "objectorarray": ["objectorarray@1.0.5", "", {}, ""], + "on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="], - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, ""], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, ""], + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "p-finally": ["p-finally@1.0.0", "", {}, ""], + "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + + "opener": ["opener@1.5.2", "", { "bin": { "opener": "bin/opener-bin.js" } }, "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="], + + "p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="], "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], @@ -1005,67 +1467,73 @@ "p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="], - "p-try": ["p-try@2.2.0", "", {}, ""], + "p-retry": ["p-retry@6.2.1", "", { "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", "retry": "^0.13.1" } }, "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], - "pacote": ["pacote@21.0.4", "", { "dependencies": { "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "promise-retry": "^2.0.1", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": "bin/index.js" }, "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA=="], + "pacote": ["pacote@21.0.4", "", { "dependencies": { "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "promise-retry": "^2.0.1", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA=="], - "pako": ["pako@1.0.11", "", {}, ""], + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, ""], + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], "parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], - "path-browserify": ["path-browserify@1.0.1", "", {}, ""], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], - "path-exists": ["path-exists@4.0.0", "", {}, ""], + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], - "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, ""], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], "path-is-inside": ["path-is-inside@1.0.2", "", {}, "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w=="], - "path-key": ["path-key@3.1.1", "", {}, ""], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-parse": ["path-parse@1.0.7", "", {}, ""], + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], + "path-to-regexp": ["path-to-regexp@0.1.12", "", {}, "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="], + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@2.3.1", "", {}, ""], + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "pify": ["pify@4.0.1", "", {}, ""], + "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], - "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, ""], + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], - "postcss": ["postcss@8.4.33", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "postcss-loader": ["postcss-loader@8.1.1", "", { "dependencies": { "cosmiconfig": "^9.0.0", "jiti": "^1.20.0", "semver": "^7.5.4" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core"] }, "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ=="], + "postcss-loader": ["postcss-loader@8.2.0", "", { "dependencies": { "cosmiconfig": "^9.0.0", "jiti": "^2.5.1", "semver": "^7.6.2" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core", "webpack"] }, "sha512-tHX+RkpsXVcc7st4dSdDGliI+r4aAQDuv+v3vFYHixb6YgjreG5AG4SEB0kDK8u2s6htqEEpKlkhSBUTvWKYnA=="], "postcss-modules-extract-imports": ["postcss-modules-extract-imports@3.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q=="], - "postcss-modules-local-by-default": ["postcss-modules-local-by-default@4.0.5", "", { "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", "postcss-value-parser": "^4.1.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw=="], + "postcss-modules-local-by-default": ["postcss-modules-local-by-default@4.2.0", "", { "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw=="], - "postcss-modules-scope": ["postcss-modules-scope@3.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.0.4" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ=="], + "postcss-modules-scope": ["postcss-modules-scope@3.2.1", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA=="], - "postcss-modules-values": ["postcss-modules-values@4.0.0", "", { "dependencies": { "icss-utils": "^5.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, ""], + "postcss-modules-values": ["postcss-modules-values@4.0.0", "", { "dependencies": { "icss-utils": "^5.0.0" }, "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ=="], - "postcss-selector-parser": ["postcss-selector-parser@6.0.11", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, ""], + "postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], - "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, ""], + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - "prettier": ["prettier@3.6.2", "", { "bin": "bin/prettier.cjs" }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="], - "prettier-plugin-java": ["prettier-plugin-java@2.7.4", "", { "dependencies": { "java-parser": "3.0.1" }, "peerDependencies": { "prettier": "^3.0.0" } }, "sha512-RiRNkumIW9vaDpxirgIPI+oLSRmuCmoVZuTax9i3cWzWnxd+uKyAfDe4efS+ce00owAeh0a1DI5eFaH1xYWNPg=="], + "prettier-plugin-java": ["prettier-plugin-java@2.8.1", "", { "dependencies": { "java-parser": "3.0.1" }, "peerDependencies": { "prettier": "^3.0.0" } }, "sha512-tkteH5OSCEb0E7wKnhhUSitr1pGUCUt9M//CwerSNhoalL/qv0jXTeSVBPZ36KC+kZl3nbq4dxh144NuGchACg=="], "proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="], - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, ""], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "proggy": ["proggy@4.0.0", "", {}, "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ=="], @@ -1077,95 +1545,131 @@ "properties-parser": ["properties-parser@0.6.0", "", {}, "sha512-qvr2cSmoA0dln0MARAKwBzPkkXn7FqwX+RVVNpMdMJc7rt9mqO2cXwluxtux9fHrLhjnPFaQkS8BM0kFrTCnSw=="], - "punycode": ["punycode@2.3.0", "", {}, ""], + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], - "q": ["q@1.5.1", "", {}, ""], + "q": ["q@1.5.1", "", {}, "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw=="], + + "qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="], - "querystringify": ["querystringify@2.2.0", "", {}, ""], + "querystringify": ["querystringify@2.2.0", "", {}, "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="], - "queue-microtask": ["queue-microtask@1.2.3", "", {}, ""], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], - "raw-loader": ["raw-loader@4.0.2", "", { "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" }, "peerDependencies": { "webpack": "^4.0.0 || ^5.0.0" } }, ""], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="], - "read-chunk": ["read-chunk@3.2.0", "", { "dependencies": { "pify": "^4.0.1", "with-open-file": "^0.1.6" } }, ""], + "raw-loader": ["raw-loader@4.0.2", "", { "dependencies": { "loader-utils": "^2.0.0", "schema-utils": "^3.0.0" }, "peerDependencies": { "webpack": "^4.0.0 || ^5.0.0" } }, "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA=="], + + "read-chunk": ["read-chunk@3.2.0", "", { "dependencies": { "pify": "^4.0.1", "with-open-file": "^0.1.6" } }, "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ=="], "read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="], - "readable-stream": ["readable-stream@2.3.7", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, ""], + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, ""], + "rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="], "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], - "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.0", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA=="], + "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "^1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="], - "regexpu-core": ["regexpu-core@6.2.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" } }, "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA=="], + "regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="], "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], - "regjsparser": ["regjsparser@0.12.0", "", { "dependencies": { "jsesc": "~3.0.2" }, "bin": "bin/parser" }, "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ=="], + "regjsparser": ["regjsparser@0.13.0", "", { "dependencies": { "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - "require-from-string": ["require-from-string@2.0.2", "", {}, ""], + "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], - "requires-port": ["requires-port@1.0.0", "", {}, ""], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="], - "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, ""], + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "resolve-from": ["resolve-from@4.0.0", "", {}, ""], + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], - "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "reusify": ["reusify@1.0.4", "", {}, ""], + "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, ""], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - "safe-buffer": ["safe-buffer@5.1.2", "", {}, ""], + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "sass": ["sass@1.90.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": "sass.js" }, "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q=="], + "sass": ["sass@1.97.2", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-y5LWb0IlbO4e97Zr7c3mlpabcbBtS+ieiZ9iwDooShpFKWXf62zz5pEPdwrLYm+Bxn1fnbwFGzHuCLSA9tBmrw=="], - "sass-loader": ["sass-loader@16.0.5", "", { "dependencies": { "neo-async": "^2.6.2" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core", "node-sass", "sass-embedded"] }, "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw=="], + "sass-loader": ["sass-loader@16.0.6", "", { "dependencies": { "neo-async": "^2.6.2" }, "peerDependencies": { "@rspack/core": "0.x || 1.x", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "optionalPeers": ["@rspack/core", "node-sass", "sass", "sass-embedded", "webpack"] }, "sha512-sglGzId5gmlfxNs4gK2U3h7HlVRfx278YK6Ono5lwzuvi1jxig80YiuHkaDBVsYIKFhx8wN7XSCI0M2IDS/3qA=="], - "sax": ["sax@1.1.4", "", {}, ""], + "sax": ["sax@1.1.4", "", {}, "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg=="], - "schema-utils": ["schema-utils@4.3.2", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ=="], + "schema-utils": ["schema-utils@4.3.3", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.1.0" } }, "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA=="], - "semver": ["semver@6.3.1", "", { "bin": "bin/semver.js" }, ""], + "select-hose": ["select-hose@2.0.0", "", {}, "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg=="], + + "selfsigned": ["selfsigned@2.4.1", "", { "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" } }, "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q=="], + + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "~0.5.2", "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "~2.4.1", "range-parser": "~1.2.1", "statuses": "~2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], - "setimmediate": ["setimmediate@1.0.5", "", {}, ""], + "serve-index": ["serve-index@1.9.2", "", { "dependencies": { "accepts": "~1.3.8", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", "http-errors": "~1.8.0", "mime-types": "~2.1.35", "parseurl": "~1.3.3" } }, "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ=="], + + "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], + + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], "shallow-clone": ["shallow-clone@3.0.1", "", { "dependencies": { "kind-of": "^6.0.2" } }, "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA=="], - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, ""], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], - "shebang-regex": ["shebang-regex@3.0.0", "", {}, ""], + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], - "signal-exit": ["signal-exit@3.0.7", "", {}, ""], + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - "sigstore": ["sigstore@4.0.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.0.0", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.0.0", "@sigstore/tuf": "^4.0.0", "@sigstore/verify": "^3.0.0" } }, "sha512-Gw/FgHtrLM9WP8P5lLcSGh9OQcrTruWCELAiS48ik1QbL0cH+dfjomiRTUE9zzz+D1N6rOLkwXUvVmXZAsNE0Q=="], + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "sigstore": ["sigstore@4.1.0", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.1.0", "@sigstore/tuf": "^4.0.1", "@sigstore/verify": "^3.1.0" } }, "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA=="], + + "sirv": ["sirv@2.0.4", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ=="], "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + "sockjs": ["sockjs@0.3.24", "", { "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" } }, "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ=="], + "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], - "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], - "source-map-js": ["source-map-js@1.0.2", "", {}, ""], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], @@ -1177,43 +1681,55 @@ "spdx-license-ids": ["spdx-license-ids@3.0.22", "", {}, "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ=="], + "spdy": ["spdy@4.0.2", "", { "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", "http-deceiver": "^1.2.7", "select-hose": "^2.0.0", "spdy-transport": "^3.0.0" } }, "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA=="], + + "spdy-transport": ["spdy-transport@3.0.0", "", { "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", "hpack.js": "^2.1.6", "obuf": "^1.1.2", "readable-stream": "^3.0.6", "wbuf": "^1.7.3" } }, "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw=="], + "sprintf": ["sprintf@0.1.5", "", {}, "sha512-4X5KsuXFQ7f+d7Y+bi4qSb6eI+YoifDTGr0MQJXRoYO7BO7evfRCjds6kk3z7l5CiJYxgDN1x5Er4WiyCt+zTQ=="], "ssri": ["ssri@13.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, ""], + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], "stringify-package": ["stringify-package@1.0.1", "", {}, "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg=="], - "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - "strip-bom": ["strip-bom@4.0.0", "", {}, ""], + "strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], - "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, ""], + "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], - "strip-json-comments": ["strip-json-comments@1.0.4", "", { "bin": "cli.js" }, "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg=="], + "strip-json-comments": ["strip-json-comments@1.0.4", "", { "bin": { "strip-json-comments": "cli.js" } }, "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg=="], "style-loader": ["style-loader@4.0.0", "", { "peerDependencies": { "webpack": "^5.27.0" } }, "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA=="], - "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, ""], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "systeminformation": ["systeminformation@5.27.14", "", { "os": "!aix", "bin": "lib/cli.js" }, "sha512-3DoNDYSZBLxBwaJtQGWNpq0fonga/VZ47HY1+7/G3YoIPaPz93Df6egSzzTKbEMmlzUpy3eQ0nR9REuYIycXGg=="], + "systeminformation": ["systeminformation@5.30.2", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-Rrt5oFTWluUVuPlbtn3o9ja+nvjdF3Um4DG0KxqfYvpzcx7Q9plZBTjJiJy9mAouua4+OI7IUGBaG9Zyt9NgxA=="], - "tapable": ["tapable@2.2.1", "", {}, ""], + "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], "tar": ["tar@7.5.2", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg=="], "terminal": ["terminal@0.1.4", "", { "dependencies": { "sprintf": ">= 0.1.1" } }, "sha512-w6OAFpUO+TimZUdQ46dK3fYYOCCBIsS2QUfIEkzX21oJ8tvJOJvJkcmrbleLH5KG02SNohYFDj81bL3VPaULsQ=="], - "terser": ["terser@5.43.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": "bin/terser" }, "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg=="], + "terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="], + + "terser-webpack-plugin": ["terser-webpack-plugin@5.3.16", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q=="], + + "thingies": ["thingies@2.5.0", "", { "peerDependencies": { "tslib": "^2" } }, "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw=="], - "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="], + "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -1221,77 +1737,123 @@ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "totalist": ["totalist@3.0.1", "", {}, "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ=="], + + "tree-dump": ["tree-dump@1.1.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA=="], + "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], - "tuf-js": ["tuf-js@4.0.0", "", { "dependencies": { "@tufjs/models": "4.0.0", "debug": "^4.4.1", "make-fetch-happen": "^15.0.0" } }, "sha512-Lq7ieeGvXDXwpoSmOSgLWVdsGGV9J4a77oDTAPe/Ltrqnnm/ETaRlBAQTH5JatEh8KXuE6sddf9qAv1Q2282Hg=="], + "ts-loader": ["ts-loader@9.5.4", "", { "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", "semver": "^7.3.4", "source-map": "^0.7.4" }, "peerDependencies": { "typescript": "*", "webpack": "^5.0.0" } }, "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="], - "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, ""], + "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + + "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], - "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], "unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="], - "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.0", "", {}, "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg=="], + "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="], - "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.1.0", "", {}, "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w=="], + "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.2.0", "", {}, "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ=="], "unique-filename": ["unique-filename@5.0.0", "", { "dependencies": { "unique-slug": "^6.0.0" } }, "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg=="], "unique-slug": ["unique-slug@6.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw=="], - "unique-string": ["unique-string@2.0.0", "", { "dependencies": { "crypto-random-string": "^2.0.0" } }, ""], + "unique-string": ["unique-string@2.0.0", "", { "dependencies": { "crypto-random-string": "^2.0.0" } }, "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "untildify": ["untildify@4.0.0", "", {}, "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw=="], - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": "cli.js" }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "url-parse": ["url-parse@1.5.10", "", { "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ=="], - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, ""], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - "url-parse": ["url-parse@1.5.10", "", { "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, ""], + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], - "util-deprecate": ["util-deprecate@1.0.2", "", {}, ""], + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], "valid-identifier": ["valid-identifier@0.0.2", "", {}, "sha512-zaSmOW6ykXwrkX0YTuFUSoALNEKGaQHpxBJQLb3TXspRNDpBwbfrIQCZqAQ0LKBlKuyn2YOq7NNd6415hvZ33g=="], "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], - "validate-npm-package-name": ["validate-npm-package-name@7.0.0", "", {}, "sha512-bwVk/OK+Qu108aJcMAEiU4yavHUI7aN20TgZNBj9MR2iU1zPUl1Z1Otr7771ExfYTPTvfN8ZJ1pbr5Iklgt4xg=="], + "validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="], "vanilla-picker": ["vanilla-picker@2.12.3", "", { "dependencies": { "@sphinxxxx/color-conversion": "^2.2.2" } }, "sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + + "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], + + "vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + + "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], + "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], - "watchpack": ["watchpack@2.4.1", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg=="], + "watchpack": ["watchpack@2.5.1", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg=="], - "webpack": ["webpack@5.101.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", "webpack-sources": "^3.3.3" }, "bin": "bin/webpack.js" }, "sha512-B4t+nJqytPeuZlHuIKTbalhljIFXeNRqrUGAQgTGlfOl2lXXKXw+yZu6bicycP+PUlM44CxBjCFD6aciKFT3LQ=="], + "wbuf": ["wbuf@1.7.3", "", { "dependencies": { "minimalistic-assert": "^1.0.0" } }, "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA=="], - "webpack-cli": ["webpack-cli@6.0.1", "", { "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", "@webpack-cli/info": "^3.0.1", "@webpack-cli/serve": "^3.0.1", "colorette": "^2.0.14", "commander": "^12.1.0", "cross-spawn": "^7.0.3", "envinfo": "^7.14.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^3.1.1", "rechoir": "^0.8.0", "webpack-merge": "^6.0.1" }, "peerDependencies": { "webpack": "^5.82.0" }, "bin": "bin/cli.js" }, "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw=="], + "webpack": ["webpack@5.105.0", "", { "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.19.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.16", "watchpack": "^2.5.1", "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" } }, "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw=="], + + "webpack-bundle-analyzer": ["webpack-bundle-analyzer@4.10.2", "", { "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", "commander": "^7.2.0", "debounce": "^1.2.1", "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", "html-escaper": "^2.0.2", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", "ws": "^7.3.1" }, "bin": { "webpack-bundle-analyzer": "lib/bin/analyzer.js" } }, "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw=="], + + "webpack-cli": ["webpack-cli@6.0.1", "", { "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", "@webpack-cli/info": "^3.0.1", "@webpack-cli/serve": "^3.0.1", "colorette": "^2.0.14", "commander": "^12.1.0", "cross-spawn": "^7.0.3", "envinfo": "^7.14.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^3.1.1", "rechoir": "^0.8.0", "webpack-merge": "^6.0.1" }, "peerDependencies": { "webpack": "^5.82.0" }, "bin": { "webpack-cli": "./bin/cli.js" } }, "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw=="], + + "webpack-dev-middleware": ["webpack-dev-middleware@7.4.5", "", { "dependencies": { "colorette": "^2.0.10", "memfs": "^4.43.1", "mime-types": "^3.0.1", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "peerDependencies": { "webpack": "^5.0.0" }, "optionalPeers": ["webpack"] }, "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA=="], + + "webpack-dev-server": ["webpack-dev-server@5.2.2", "", { "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", "@types/express": "^4.17.21", "@types/express-serve-static-core": "^4.17.21", "@types/serve-index": "^1.9.4", "@types/serve-static": "^1.15.5", "@types/sockjs": "^0.3.36", "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.2.1", "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "express": "^4.21.2", "graceful-fs": "^4.2.6", "http-proxy-middleware": "^2.0.9", "ipaddr.js": "^2.1.0", "launch-editor": "^2.6.1", "open": "^10.0.3", "p-retry": "^6.2.0", "schema-utils": "^4.2.0", "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", "webpack-dev-middleware": "^7.4.2", "ws": "^8.18.0" }, "peerDependencies": { "webpack": "^5.0.0" }, "optionalPeers": ["webpack"], "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" } }, "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg=="], "webpack-merge": ["webpack-merge@6.0.1", "", { "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", "wildcard": "^2.0.1" } }, "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg=="], "webpack-sources": ["webpack-sources@3.3.3", "", {}, "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg=="], + "websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="], + + "websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="], + "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], "wildcard": ["wildcard@2.0.1", "", {}, "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ=="], - "with-open-file": ["with-open-file@0.1.7", "", { "dependencies": { "p-finally": "^1.0.0", "p-try": "^2.1.0", "pify": "^4.0.1" } }, ""], + "with-open-file": ["with-open-file@0.1.7", "", { "dependencies": { "p-finally": "^1.0.0", "p-try": "^2.1.0", "pify": "^4.0.1" } }, "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA=="], + + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "wrap-ansi": ["wrap-ansi@9.0.0", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q=="], + "write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], - "wrappy": ["wrappy@1.0.2", "", {}, ""], + "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], - "write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, ""], + "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], - "xdg-basedir": ["xdg-basedir@4.0.0", "", {}, ""], + "xdg-basedir": ["xdg-basedir@4.0.0", "", {}, "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="], "xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], - "y18n": ["y18n@5.0.8", "", {}, ""], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -1301,101 +1863,133 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="], + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@17.65.0", "", { "dependencies": { "@jsonjoy.com/base64": "17.65.0", "@jsonjoy.com/buffers": "17.65.0", "@jsonjoy.com/codegen": "17.65.0", "@jsonjoy.com/json-pointer": "17.65.0", "@jsonjoy.com/util": "17.65.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-e0SG/6qUCnVhHa0rjDJHgnXnbsacooHVqQHxspjvlYQSkHm+66wkHw6Gql+3u/WxI/b1VsOdUi0M+fOtkgKGdQ=="], + + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/util": ["@jsonjoy.com/util@17.65.0", "", { "dependencies": { "@jsonjoy.com/buffers": "17.65.0", "@jsonjoy.com/codegen": "17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-cWiEHZccQORf96q2y6zU3wDeIVPeidmGqd9cNKJRYoVHTV0S1eHPy5JTbHpMnGfDvtvujQwQozOqgO9ABu6h0w=="], + + "@jsonjoy.com/json-pack/@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA=="], - "@jridgewell/source-map/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="], + "@jsonjoy.com/util/@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA=="], - "@npmcli/agent/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "@npmcli/agent/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], - "@npmcli/arborist/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "@npmcli/arborist/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], - "@npmcli/arborist/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": "bin/nopt.js" }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], + "@npmcli/arborist/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], - "@npmcli/arborist/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@npmcli/arborist/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], - "@npmcli/fs/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@npmcli/arborist/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "@npmcli/git/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "@npmcli/fs/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "@npmcli/git/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@npmcli/git/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], + + "@npmcli/git/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@npmcli/git/which": ["which@6.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg=="], "@npmcli/map-workspaces/glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], + "@npmcli/map-workspaces/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "@npmcli/metavuln-calculator/json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="], - "@npmcli/metavuln-calculator/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@npmcli/metavuln-calculator/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@npmcli/package-json/glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], "@npmcli/package-json/json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="], - "@npmcli/package-json/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "@npmcli/package-json/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@npmcli/promise-spawn/which": ["which@6.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg=="], - "@npmcli/query/postcss-selector-parser": ["postcss-selector-parser@7.1.0", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA=="], - "@npmcli/run-script/which": ["which@6.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg=="], - "@sigstore/sign/proc-log": ["proc-log@5.0.0", "", {}, "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ=="], + "@rspack/dev-server/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "@tufjs/models/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + + "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "@tufjs/models/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "android-versions/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "android-versions/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "bin-links/write-file-atomic": ["write-file-atomic@7.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg=="], + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "cacache/glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], - "cacache/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "cacache/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], + + "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "compression/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "content-disposition/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "cordova/cordova-common": ["cordova-common@6.0.0", "", { "dependencies": { "@netflix/nerror": "^1.1.3", "ansi": "^0.3.1", "bplist-parser": "^0.3.2", "elementtree": "^0.1.7", "endent": "^2.1.0", "fast-glob": "^3.3.3", "plist": "^3.1.0" } }, "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg=="], - "cordova/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": "bin/nopt.js" }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], + "cordova/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], - "cordova/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "cordova/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "cordova-android/semver": ["semver@7.7.2", "", { "bin": "bin/semver.js" }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "cordova-android/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "cordova-create/cordova-common": ["cordova-common@6.0.0", "", { "dependencies": { "@netflix/nerror": "^1.1.3", "ansi": "^0.3.1", "bplist-parser": "^0.3.2", "elementtree": "^0.1.7", "endent": "^2.1.0", "fast-glob": "^3.3.3", "plist": "^3.1.0" } }, "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg=="], "cordova-fetch/cordova-common": ["cordova-common@6.0.0", "", { "dependencies": { "@netflix/nerror": "^1.1.3", "ansi": "^0.3.1", "bplist-parser": "^0.3.2", "elementtree": "^0.1.7", "endent": "^2.1.0", "fast-glob": "^3.3.3", "plist": "^3.1.0" } }, "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg=="], - "cordova-fetch/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "cordova-fetch/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "cordova-lib/cordova-common": ["cordova-common@6.0.0", "", { "dependencies": { "@netflix/nerror": "^1.1.3", "ansi": "^0.3.1", "bplist-parser": "^0.3.2", "elementtree": "^0.1.7", "endent": "^2.1.0", "fast-glob": "^3.3.3", "plist": "^3.1.0" } }, "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg=="], - "cordova-lib/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "cordova-lib/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "cordova-lib/write-file-atomic": ["write-file-atomic@7.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg=="], - "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, ""], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "css-loader/semver": ["semver@7.5.4", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": "bin/semver.js" }, ""], + "css-loader/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "dom-serializer/domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], "dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], - "endent/dedent": ["dedent@0.7.0", "", {}, ""], + "encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "endent/dedent": ["dedent@0.7.0", "", {}, "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="], + + "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, ""], + "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "fdir/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "express/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - "glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, ""], + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "hosted-git-info/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "hosted-git-info/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], "htmlparser2/entities": ["entities@1.0.0", "", {}, "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ=="], "htmlparser2/readable-stream": ["readable-stream@1.1.14", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ=="], + "ignore-walk/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + "is-plain-object/isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="], - "jshint/minimatch": ["minimatch@3.0.8", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q=="], + "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "make-fetch-happen/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], @@ -1403,53 +1997,105 @@ "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "node-gyp/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": "bin/nopt.js" }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], + "node-gyp/nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], - "node-gyp/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "node-gyp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "node-gyp/which": ["which@6.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg=="], - "npm-install-checks/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "npm-install-checks/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "npm-package-arg/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "npm-package-arg/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "npm-pick-manifest/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "npm-pick-manifest/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "parse-conflict-json/json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="], - "path-scurry/lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "path-scurry/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], + + "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "postcss-loader/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "promise-retry/retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], - "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, ""], + "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], - "postcss-loader/semver": ["semver@7.5.4", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": "bin/semver.js" }, ""], + "raw-loader/schema-utils": ["schema-utils@3.3.0", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg=="], - "raw-loader/schema-utils": ["schema-utils@3.1.1", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, ""], + "resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "regjsparser/jsesc": ["jsesc@3.0.2", "", { "bin": "bin/jsesc" }, "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g=="], + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "resolve-cwd/resolve-from": ["resolve-from@5.0.0", "", {}, ""], + "serve-index/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "serve-index/http-errors": ["http-errors@1.8.1", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.1" } }, "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="], + + "serve-index/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "spdy-transport/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "ts-loader/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "webpack/enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="], "webpack/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "webpack-bundle-analyzer/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + + "webpack-bundle-analyzer/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "webpack-bundle-analyzer/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + + "webpack-cli/@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.6.3", "", {}, "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ=="], + + "webpack-dev-server/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "websocket-driver/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/base64": ["@jsonjoy.com/base64@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-Xrh7Fm/M0QAYpekSgmskdZYnFdSGnsxJ/tHaolA4bNwWdG9i65S8m83Meh7FOxyJyQAdo4d4J97NOomBLEfkDQ=="], + + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA=="], + + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/json-pack/@jsonjoy.com/json-pointer": ["@jsonjoy.com/json-pointer@17.65.0", "", { "dependencies": { "@jsonjoy.com/util": "17.65.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-uhTe+XhlIZpWOxgPcnO+iSCDgKKBpwkDVTyYiXX9VayGV8HSFVJM67M6pUE71zdnXF1W0Da21AvnhlmdwYPpow=="], + + "@jsonjoy.com/fs-snapshot/@jsonjoy.com/util/@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@17.65.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA=="], + "@npmcli/arborist/nopt/abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], - "@tufjs/models/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@npmcli/package-json/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + + "@rspack/dev-server/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "bin-links/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "cacache/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + + "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "cordova-lib/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], "cordova/nopt/abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], - "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, ""], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "css-loader/semver/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, ""], + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "htmlparser2/readable-stream/isarray": ["isarray@0.0.1", "", {}, "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="], @@ -1463,24 +2109,36 @@ "node-gyp/nopt/abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], - "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, ""], + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "raw-loader/schema-utils/ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "raw-loader/schema-utils/ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], + + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "serve-index/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], + + "serve-index/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], - "postcss-loader/semver/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, ""], + "serve-index/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "raw-loader/schema-utils/ajv": ["ajv@6.12.6", "", { "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" } }, ""], + "type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "raw-loader/schema-utils/ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, ""], + "webpack-dev-server/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "webpack/mime-types/mime-db": ["mime-db@1.52.0", "", {}, ""], + "webpack/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "css-loader/semver/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "@rspack/dev-server/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, ""], + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], - "postcss-loader/semver/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "raw-loader/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "raw-loader/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, ""], + "webpack-dev-server/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, ""], + "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], } } diff --git a/package-lock.json b/package-lock.json index e3e2d64f2..18eae6229 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,35 @@ "version": "1.11.8", "license": "MIT", "dependencies": { + "@codemirror/autocomplete": "^6.20.0", + "@codemirror/commands": "^6.10.0", + "@codemirror/lang-cpp": "^6.0.3", + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-go": "^6.0.1", + "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-java": "^6.0.2", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.2", + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-php": "^6.0.2", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/lang-rust": "^6.0.2", + "@codemirror/lang-sass": "^6.0.2", + "@codemirror/lang-vue": "^0.1.3", + "@codemirror/lang-xml": "^6.1.0", + "@codemirror/lang-yaml": "^6.1.2", + "@codemirror/language": "^6.11.3", + "@codemirror/language-data": "^6.5.2", + "@codemirror/legacy-modes": "^6.5.2", + "@codemirror/lint": "^6.9.2", + "@codemirror/lsp-client": "^6.2.1", + "@codemirror/search": "^6.5.11", + "@codemirror/state": "^6.5.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.38.8", "@deadlyjack/ajax": "^1.2.6", + "@emmetio/codemirror6-plugin": "^0.4.0", + "@lezer/highlight": "^1.2.3", "@ungap/custom-elements": "^1.3.0", "@xterm/addon-attach": "^0.11.0", "@xterm/addon-fit": "^0.10.0", @@ -21,15 +49,17 @@ "@xterm/xterm": "^5.5.0", "acorn": "^8.15.0", "autosize": "^6.0.1", + "codemirror": "^6.0.2", "cordova": "13.0.0", - "core-js": "^3.45.0", + "core-js": "^3.47.0", "crypto-js": "^4.2.0", "dayjs": "^1.11.19", - "dompurify": "^3.2.6", + "dompurify": "^3.3.0", "escape-string-regexp": "^5.0.0", - "filesize": "^11.0.2", - "html-tag-js": "^2.4.15", - "js-base64": "^3.7.7", + "esprima": "^4.0.1", + "filesize": "^11.0.13", + "html-tag-js": "^2.4.16", + "js-base64": "^3.7.8", "jszip": "^3.10.1", "markdown-it": "^14.1.1", "markdown-it-anchor": "^9.2.0", @@ -44,15 +74,18 @@ "yargs": "^18.0.0" }, "devDependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-runtime": "^7.28.0", - "@babel/preset-env": "^7.28.0", - "@babel/runtime": "^7.28.2", - "@babel/runtime-corejs3": "^7.28.2", + "@babel/core": "^7.28.5", + "@babel/plugin-transform-runtime": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", + "@babel/runtime": "^7.28.4", + "@babel/runtime-corejs3": "^7.28.4", "@biomejs/biome": "2.1.4", + "@rspack/cli": "^1.7.0", + "@rspack/core": "^1.7.0", "@types/ace": "^0.0.52", "@types/url-parse": "^1.4.11", - "autoprefixer": "^10.4.21", + "autoprefixer": "^10.4.22", "babel-loader": "^10.0.0", "com.foxdebug.acode.rk.auth": "file:src/plugins/auth", "com.foxdebug.acode.rk.customtabs": "file:src/plugins/custom-tabs", @@ -64,8 +97,8 @@ "cordova-plugin-advanced-http": "^3.3.1", "cordova-plugin-browser": "file:src/plugins/browser", "cordova-plugin-buildinfo": "file:src/plugins/cordova-plugin-buildinfo", - "cordova-plugin-device": "^2.0.3", - "cordova-plugin-file": "^8.0.1", + "cordova-plugin-device": "^2.1.0", + "cordova-plugin-file": "^8.1.3", "cordova-plugin-ftp": "file:src/plugins/ftp", "cordova-plugin-iap": "file:src/plugins/iap", "cordova-plugin-sdcard": "file:src/plugins/sdcard", @@ -74,36 +107,25 @@ "cordova-plugin-system": "file:src/plugins/system", "cordova-plugin-websocket": "file:src/plugins/websocket", "css-loader": "^7.1.2", - "mini-css-extract-plugin": "^2.9.3", + "mini-css-extract-plugin": "^2.9.4", "path-browserify": "^1.0.1", - "postcss-loader": "^8.1.1", - "prettier": "^3.6.2", - "prettier-plugin-java": "^2.7.4", + "postcss-loader": "^8.2.0", + "prettier": "^3.7.4", + "prettier-plugin-java": "^2.7.7", "raw-loader": "^4.0.2", - "sass": "^1.90.0", - "sass-loader": "^16.0.5", + "sass": "^1.94.2", + "sass-loader": "^16.0.6", "style-loader": "^4.0.0", "terminal": "^0.1.4", + "ts-loader": "^9.5.4", + "typescript": "^5.9.3", + "vscode-languageserver-types": "^3.17.5", "webpack": "^5.105.0", "webpack-cli": "^6.0.1" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { @@ -116,9 +138,7 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", - "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "version": "7.28.5", "dev": true, "license": "MIT", "engines": { @@ -126,22 +146,20 @@ } }, "node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -157,14 +175,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -173,21 +189,8 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, "license": "MIT", "dependencies": { @@ -199,8 +202,6 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { @@ -215,18 +216,16 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", - "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.27.1", + "@babel/traverse": "^7.28.5", "semver": "^6.3.1" }, "engines": { @@ -237,14 +236,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", - "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "regexpu-core": "^6.2.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, "engines": { @@ -256,8 +253,6 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "dev": true, "license": "MIT", "dependencies": { @@ -273,8 +268,6 @@ }, "node_modules/@babel/helper-globals": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, "license": "MIT", "engines": { @@ -282,14 +275,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", - "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -297,8 +288,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { @@ -310,15 +299,13 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -329,8 +316,6 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, "license": "MIT", "dependencies": { @@ -342,8 +327,6 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -352,8 +335,6 @@ }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "dev": true, "license": "MIT", "dependencies": { @@ -370,8 +351,6 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "dev": true, "license": "MIT", "dependencies": { @@ -388,8 +367,6 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, "license": "MIT", "dependencies": { @@ -402,8 +379,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -411,9 +386,7 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", "dev": true, "license": "MIT", "engines": { @@ -422,8 +395,6 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -431,42 +402,36 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", - "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "version": "7.28.3", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", - "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "version": "7.28.4", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.28.2" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.0" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -476,14 +441,12 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", - "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -494,8 +457,6 @@ }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "dev": true, "license": "MIT", "dependencies": { @@ -510,8 +471,6 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "dev": true, "license": "MIT", "dependencies": { @@ -526,8 +485,6 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "dev": true, "license": "MIT", "dependencies": { @@ -543,14 +500,12 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", - "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", + "version": "7.28.3", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -572,8 +527,6 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "dev": true, "license": "MIT", "dependencies": { @@ -588,8 +541,34 @@ }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", "dev": true, "license": "MIT", "dependencies": { @@ -619,8 +598,6 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "dev": true, "license": "MIT", "dependencies": { @@ -635,8 +612,6 @@ }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -653,8 +628,6 @@ }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", "dev": true, "license": "MIT", "dependencies": { @@ -671,8 +644,6 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "dev": true, "license": "MIT", "dependencies": { @@ -686,9 +657,7 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", - "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { @@ -703,8 +672,6 @@ }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "dev": true, "license": "MIT", "dependencies": { @@ -719,13 +686,11 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", - "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", + "version": "7.28.3", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { @@ -736,9 +701,7 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz", - "integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==", + "version": "7.28.4", "dev": true, "license": "MIT", "dependencies": { @@ -747,7 +710,7 @@ "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -758,8 +721,6 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", "dev": true, "license": "MIT", "dependencies": { @@ -774,14 +735,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -792,8 +751,6 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "dev": true, "license": "MIT", "dependencies": { @@ -809,8 +766,6 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "dev": true, "license": "MIT", "dependencies": { @@ -825,8 +780,6 @@ }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "dev": true, "license": "MIT", "dependencies": { @@ -842,8 +795,6 @@ }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "dev": true, "license": "MIT", "dependencies": { @@ -858,8 +809,6 @@ }, "node_modules/@babel/plugin-transform-explicit-resource-management": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -874,9 +823,7 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", - "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { @@ -891,8 +838,6 @@ }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -907,8 +852,6 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "dev": true, "license": "MIT", "dependencies": { @@ -924,8 +867,6 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -942,8 +883,6 @@ }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -958,8 +897,6 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "dev": true, "license": "MIT", "dependencies": { @@ -973,9 +910,7 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { @@ -990,8 +925,6 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1006,8 +939,6 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "dev": true, "license": "MIT", "dependencies": { @@ -1023,8 +954,6 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "dev": true, "license": "MIT", "dependencies": { @@ -1039,16 +968,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", - "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1059,8 +986,6 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "dev": true, "license": "MIT", "dependencies": { @@ -1076,8 +1001,6 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "dev": true, "license": "MIT", "dependencies": { @@ -1093,8 +1016,6 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1109,8 +1030,6 @@ }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "dev": true, "license": "MIT", "dependencies": { @@ -1125,8 +1044,6 @@ }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "dev": true, "license": "MIT", "dependencies": { @@ -1140,9 +1057,7 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", - "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", + "version": "7.28.4", "dev": true, "license": "MIT", "dependencies": { @@ -1150,7 +1065,7 @@ "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -1161,8 +1076,6 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, "license": "MIT", "dependencies": { @@ -1178,8 +1091,6 @@ }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1193,9 +1104,7 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", - "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { @@ -1211,8 +1120,6 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, "license": "MIT", "dependencies": { @@ -1227,8 +1134,6 @@ }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "dev": true, "license": "MIT", "dependencies": { @@ -1244,8 +1149,6 @@ }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1262,8 +1165,6 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1277,9 +1178,7 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz", - "integrity": "sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==", + "version": "7.28.4", "dev": true, "license": "MIT", "dependencies": { @@ -1294,8 +1193,6 @@ }, "node_modules/@babel/plugin-transform-regexp-modifiers": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "dev": true, "license": "MIT", "dependencies": { @@ -1311,8 +1208,6 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, "license": "MIT", "dependencies": { @@ -1326,9 +1221,7 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.0.tgz", - "integrity": "sha512-dGopk9nZrtCs2+nfIem25UuHyt5moSJamArzIoh9/vezUQPmYDOzjaHDCkAzuGJibCIkPup8rMT2+wYB6S73cA==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { @@ -1348,8 +1241,6 @@ }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1364,8 +1255,6 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1381,8 +1270,6 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "dev": true, "license": "MIT", "dependencies": { @@ -1397,8 +1284,6 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, "license": "MIT", "dependencies": { @@ -1413,8 +1298,6 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, "license": "MIT", "dependencies": { @@ -1427,10 +1310,26 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, "license": "MIT", "dependencies": { @@ -1445,8 +1344,6 @@ }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1462,8 +1359,6 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "dev": true, "license": "MIT", "dependencies": { @@ -1479,8 +1374,6 @@ }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "dev": true, "license": "MIT", "dependencies": { @@ -1495,21 +1388,19 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.0.tgz", - "integrity": "sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.0", + "@babel/compat-data": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.27.1", "@babel/plugin-syntax-import-attributes": "^7.27.1", @@ -1518,42 +1409,42 @@ "@babel/plugin-transform-async-generator-functions": "^7.28.0", "@babel/plugin-transform-async-to-generator": "^7.27.1", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-block-scoping": "^7.28.5", "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.28.0", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-dotall-regex": "^7.27.1", "@babel/plugin-transform-duplicate-keys": "^7.27.1", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-dynamic-import": "^7.27.1", "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", "@babel/plugin-transform-json-strings": "^7.27.1", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", "@babel/plugin-transform-object-super": "^7.27.1", "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/plugin-transform-private-methods": "^7.27.1", "@babel/plugin-transform-private-property-in-object": "^7.27.1", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.0", + "@babel/plugin-transform-regenerator": "^7.28.4", "@babel/plugin-transform-regexp-modifiers": "^7.27.1", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", @@ -1592,10 +1483,26 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", - "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "version": "7.28.4", "dev": true, "license": "MIT", "engines": { @@ -1603,9 +1510,7 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.2.tgz", - "integrity": "sha512-FVFaVs2/dZgD3Y9ZD+AKNKjyGKzwu0C54laAXWUXgLcVXcCX6YZ6GhK2cp7FogSN2OA0Fu+QT8dP3FUdo9ShSQ==", + "version": "7.28.4", "dev": true, "license": "MIT", "dependencies": { @@ -1617,8 +1522,6 @@ }, "node_modules/@babel/template": { "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { @@ -1631,18 +1534,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -1650,14 +1551,12 @@ } }, "node_modules/@babel/types": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "version": "7.28.5", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1665,8 +1564,6 @@ }, "node_modules/@biomejs/biome": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.1.4.tgz", - "integrity": "sha512-QWlrqyxsU0FCebuMnkvBIkxvPqH89afiJzjMl+z67ybutse590jgeaFdDurE9XYtzpjRGTI1tlUZPGWmbKsElA==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -1692,8 +1589,6 @@ }, "node_modules/@biomejs/cli-darwin-arm64": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.1.4.tgz", - "integrity": "sha512-sCrNENE74I9MV090Wq/9Dg7EhPudx3+5OiSoQOkIe3DLPzFARuL1dOwCWhKCpA3I5RHmbrsbNSRfZwCabwd8Qg==", "cpu": [ "arm64" ], @@ -1707,129 +1602,8 @@ "node": ">=14.21.3" } }, - "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.1.4.tgz", - "integrity": "sha512-gOEICJbTCy6iruBywBDcG4X5rHMbqCPs3clh3UQ+hRKlgvJTk4NHWQAyHOXvaLe+AxD1/TNX1jbZeffBJzcrOw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.1.4.tgz", - "integrity": "sha512-juhEkdkKR4nbUi5k/KRp1ocGPNWLgFRD4NrHZSveYrD6i98pyvuzmS9yFYgOZa5JhaVqo0HPnci0+YuzSwT2fw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.1.4.tgz", - "integrity": "sha512-nYr7H0CyAJPaLupFE2cH16KZmRC5Z9PEftiA2vWxk+CsFkPZQ6dBRdcC6RuS+zJlPc/JOd8xw3uCCt9Pv41WvQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.1.4.tgz", - "integrity": "sha512-Eoy9ycbhpJVYuR+LskV9s3uyaIkp89+qqgqhGQsWnp/I02Uqg2fXFblHJOpGZR8AxdB9ADy87oFVxn9MpFKUrw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.1.4.tgz", - "integrity": "sha512-lvwvb2SQQHctHUKvBKptR6PLFCM7JfRjpCCrDaTmvB7EeZ5/dQJPhTYBf36BE/B4CRWR2ZiBLRYhK7hhXBCZAg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.1.4.tgz", - "integrity": "sha512-3WRYte7orvyi6TRfIZkDN9Jzoogbv+gSvR+b9VOXUg1We1XrjBg6WljADeVEaKTvOcpVdH0a90TwyOQ6ue4fGw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-x64": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.1.4.tgz", - "integrity": "sha512-tBc+W7anBPSFXGAoQW+f/+svkpt8/uXfRwDzN1DvnatkRMt16KIYpEi/iw8u9GahJlFv98kgHcIrSsZHZTR0sw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, "node_modules/@chevrotain/cst-dts-gen": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", - "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1840,8 +1614,6 @@ }, "node_modules/@chevrotain/gast": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", - "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1851,145 +1623,1114 @@ }, "node_modules/@chevrotain/regexp-to-ast": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", - "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", "dev": true, "license": "Apache-2.0" }, "node_modules/@chevrotain/types": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", - "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", "dev": true, "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", - "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", "dev": true, "license": "Apache-2.0" }, - "node_modules/@deadlyjack/ajax": { - "version": "1.2.6", - "license": "MIT" - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", - "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", - "dev": true, + "node_modules/@codemirror/autocomplete": { + "version": "6.20.0", "license": "MIT", - "engines": { - "node": ">=14.17.0" + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "node_modules/@codemirror/commands": { + "version": "6.10.1", "license": "MIT", - "engines": { - "node": "20 || >=22" + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" } }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@codemirror/lang-angular": { + "version": "0.1.4", "license": "MIT", "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.3" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", + "node_modules/@codemirror/lang-cpp": { + "version": "6.0.3", + "license": "MIT", "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" + "@codemirror/language": "^6.0.0", + "@lezer/cpp": "^1.0.0" } }, - "node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "license": "ISC" + "node_modules/@codemirror/lang-css": { + "version": "6.3.1", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.1.7" + } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "dev": true, + "node_modules/@codemirror/lang-go": { + "version": "6.0.1", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/go": "^1.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "dev": true, + "node_modules/@codemirror/lang-html": { + "version": "6.4.11", "license": "MIT", - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.12" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@codemirror/lang-java": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/java": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.4", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-jinja": { + "version": "6.0.0", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-less": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-liquid": { + "version": "6.3.1", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.5.0", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.7.1", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.3.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-php": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/php": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-python": { + "version": "6.2.1", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.3.2", + "@codemirror/language": "^6.8.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.1", + "@lezer/python": "^1.1.4" + } + }, + "node_modules/@codemirror/lang-rust": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/rust": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sass": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/lang-css": "^6.2.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/sass": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sql": { + "version": "6.10.0", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-vue": { + "version": "0.1.3", + "license": "MIT", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-javascript": "^6.1.2", + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.1" + } + }, + "node_modules/@codemirror/lang-wast": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-xml": { + "version": "6.1.0", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-yaml": { + "version": "6.1.2", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.2.0", + "@lezer/lr": "^1.0.0", + "@lezer/yaml": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.12.1", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/language-data": { + "version": "6.5.2", + "license": "MIT", + "dependencies": { + "@codemirror/lang-angular": "^0.1.0", + "@codemirror/lang-cpp": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-go": "^6.0.0", + "@codemirror/lang-html": "^6.0.0", + "@codemirror/lang-java": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/lang-jinja": "^6.0.0", + "@codemirror/lang-json": "^6.0.0", + "@codemirror/lang-less": "^6.0.0", + "@codemirror/lang-liquid": "^6.0.0", + "@codemirror/lang-markdown": "^6.0.0", + "@codemirror/lang-php": "^6.0.0", + "@codemirror/lang-python": "^6.0.0", + "@codemirror/lang-rust": "^6.0.0", + "@codemirror/lang-sass": "^6.0.0", + "@codemirror/lang-sql": "^6.0.0", + "@codemirror/lang-vue": "^0.1.1", + "@codemirror/lang-wast": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", + "@codemirror/lang-yaml": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/legacy-modes": "^6.4.0" + } + }, + "node_modules/@codemirror/legacy-modes": { + "version": "6.5.2", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.9.2", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.35.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/lsp-client": { + "version": "6.2.1", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.20.0", + "@codemirror/language": "^6.11.0", + "@codemirror/lint": "^6.8.5", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.37.0", + "@lezer/highlight": "^1.2.1", + "marked": "^15.0.12", + "vscode-languageserver-protocol": "^3.17.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.11", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.3", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.3", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.39.9", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@deadlyjack/ajax": { + "version": "1.2.6", + "license": "MIT" + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@emmetio/abbreviation": { + "version": "2.3.3", + "license": "MIT", + "dependencies": { + "@emmetio/scanner": "^1.0.4" + } + }, + "node_modules/@emmetio/codemirror6-plugin": { + "version": "0.4.0", + "dependencies": { + "@emmetio/math-expression": "^1.0.5", + "emmet": "^2.4.11" + }, + "peerDependencies": { + "@codemirror/autocomplete": "^6.17.0", + "@codemirror/commands": "^6.6.0", + "@codemirror/lang-css": "^6.2.1", + "@codemirror/lang-html": "^6.4.9", + "@codemirror/language": "^6.10.2", + "@codemirror/state": "^6.4.1", + "@codemirror/view": "^6.29.1" + } + }, + "node_modules/@emmetio/css-abbreviation": { + "version": "2.1.8", + "license": "MIT", + "dependencies": { + "@emmetio/scanner": "^1.0.4" + } + }, + "node_modules/@emmetio/math-expression": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "@emmetio/scanner": "^1.0.4" + } + }, + "node_modules/@emmetio/scanner": { + "version": "1.0.4", + "license": "MIT" + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "license": "ISC" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/buffers": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.56.10", + "@jsonjoy.com/fs-node-utils": "4.56.10", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.56.10", + "@jsonjoy.com/fs-node-builtins": "4.56.10", + "@jsonjoy.com/fs-node-utils": "4.56.10", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.56.10", + "@jsonjoy.com/fs-node-builtins": "4.56.10", + "@jsonjoy.com/fs-node-utils": "4.56.10", + "@jsonjoy.com/fs-print": "4.56.10", + "@jsonjoy.com/fs-snapshot": "4.56.10", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-fsa": "4.56.10", + "@jsonjoy.com/fs-node-builtins": "4.56.10", + "@jsonjoy.com/fs-node-utils": "4.56.10" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.56.10" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-utils": "4.56.10", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.56.10", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "17.65.0", + "@jsonjoy.com/buffers": "17.65.0", + "@jsonjoy.com/codegen": "17.65.0", + "@jsonjoy.com/json-pointer": "17.65.0", + "@jsonjoy.com/util": "17.65.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/base64": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/codegen": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/util": "17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "17.65.0", + "@jsonjoy.com/codegen": "17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/codegen": { + "version": "17.65.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@lezer/common": { + "version": "1.5.0", + "license": "MIT" + }, + "node_modules/@lezer/cpp": { + "version": "1.1.5", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/css": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/go": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.3.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.13", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/java": { + "version": "1.1.3", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.5.4", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.7", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/markdown": { + "version": "1.6.3", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.5.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@lezer/php": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.1.0" + } + }, + "node_modules/@lezer/python": { + "version": "1.1.18", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/rust": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/sass": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.6", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/yaml": { + "version": "1.0.3", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.4.0" + } + }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/@module-federation/error-codes": { + "version": "0.22.0", "dev": true, - "engines": { - "node": ">=6.0.0" + "license": "MIT" + }, + "node_modules/@module-federation/runtime": { + "version": "0.22.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/error-codes": "0.22.0", + "@module-federation/runtime-core": "0.22.0", + "@module-federation/sdk": "0.22.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@module-federation/runtime-core": { + "version": "0.22.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@module-federation/error-codes": "0.22.0", + "@module-federation/sdk": "0.22.0" } }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@module-federation/runtime-tools": { + "version": "0.22.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@module-federation/runtime": "0.22.0", + "@module-federation/webpack-bundler-runtime": "0.22.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "node_modules/@module-federation/sdk": { + "version": "0.22.0", "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "node_modules/@module-federation/webpack-bundler-runtime": { + "version": "0.22.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@module-federation/runtime": "0.22.0", + "@module-federation/sdk": "0.22.0" } }, "node_modules/@netflix/nerror": { @@ -2032,8 +2773,6 @@ }, "node_modules/@npmcli/agent": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", - "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", "license": "ISC", "dependencies": { "agent-base": "^7.1.0", @@ -2047,18 +2786,14 @@ } }, "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", + "version": "11.2.4", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/@npmcli/arborist": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-9.1.8.tgz", - "integrity": "sha512-TYAzq0oaXQU+uLfXFbR2wYx62qHIOSg/TYhGWJSphJDypyjdNXC7B/+k29ElC2vWlWfX4OJnhmSY5DTwSFiNpg==", + "version": "9.1.9", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -2103,18 +2838,47 @@ } }, "node_modules/@npmcli/arborist/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", + "version": "11.2.4", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@npmcli/arborist/node_modules/minimatch": { + "version": "10.1.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, "engines": { "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/arborist/node_modules/nopt": { + "version": "9.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/arborist/node_modules/nopt/node_modules/abbrev": { + "version": "4.0.0", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@npmcli/arborist/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2125,8 +2889,6 @@ }, "node_modules/@npmcli/fs": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", - "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", "license": "ISC", "dependencies": { "semver": "^7.3.5" @@ -2137,8 +2899,6 @@ }, "node_modules/@npmcli/fs/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2149,8 +2909,6 @@ }, "node_modules/@npmcli/git": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.1.tgz", - "integrity": "sha512-+XTFxK2jJF/EJJ5SoAzXk3qwIDfvFc5/g+bD274LZ7uY7LE8sTfG6Z8rOanPl2ZEvZWqNvmEdtXC25cE54VcoA==", "license": "ISC", "dependencies": { "@npmcli/promise-spawn": "^9.0.0", @@ -2168,26 +2926,20 @@ }, "node_modules/@npmcli/git/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "license": "ISC", "engines": { "node": ">=16" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", + "version": "11.2.4", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/@npmcli/git/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2198,8 +2950,6 @@ }, "node_modules/@npmcli/git/node_modules/which": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -2213,8 +2963,6 @@ }, "node_modules/@npmcli/installed-package-contents": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz", - "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==", "license": "ISC", "dependencies": { "npm-bundled": "^5.0.0", @@ -2229,8 +2977,6 @@ }, "node_modules/@npmcli/map-workspaces": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-5.0.3.tgz", - "integrity": "sha512-o2grssXo1e774E5OtEwwrgoszYRh0lqkJH+Pb9r78UcqdGJRDRfhpM8DvZPjzNLLNYeD/rNbjOKM3Ss5UABROw==", "license": "ISC", "dependencies": { "@npmcli/name-from-folder": "^4.0.0", @@ -2244,8 +2990,6 @@ }, "node_modules/@npmcli/map-workspaces/node_modules/glob": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "license": "BlueOak-1.0.0", "dependencies": { "minimatch": "^10.1.1", @@ -2259,10 +3003,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/map-workspaces/node_modules/minimatch": { + "version": "10.1.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/metavuln-calculator": { "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-9.0.3.tgz", - "integrity": "sha512-94GLSYhLXF2t2LAC7pDwLaM4uCARzxShyAQKsirmlNcpidH89VA4/+K1LbJmRMgz5gy65E/QBBWQdUvGLe2Frg==", "license": "ISC", "dependencies": { "cacache": "^20.0.0", @@ -2277,8 +3032,6 @@ }, "node_modules/@npmcli/metavuln-calculator/node_modules/json-parse-even-better-errors": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", - "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", "license": "MIT", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2286,8 +3039,6 @@ }, "node_modules/@npmcli/metavuln-calculator/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2298,8 +3049,6 @@ }, "node_modules/@npmcli/name-from-folder": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-4.0.0.tgz", - "integrity": "sha512-qfrhVlOSqmKM8i6rkNdZzABj8MKEITGFAY+4teqBziksCQAOLutiAxM1wY2BKEd8KjUSpWmWCYxvXr0y4VTlPg==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2307,8 +3056,6 @@ }, "node_modules/@npmcli/node-gyp": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", - "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2316,8 +3063,6 @@ }, "node_modules/@npmcli/package-json": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.4.tgz", - "integrity": "sha512-0wInJG3j/K40OJt/33ax47WfWMzZTm6OQxB9cDhTt5huCP2a9g2GnlsxmfN+PulItNPIpPrZ+kfwwUil7eHcZQ==", "license": "ISC", "dependencies": { "@npmcli/git": "^7.0.0", @@ -2334,8 +3079,6 @@ }, "node_modules/@npmcli/package-json/node_modules/glob": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "license": "BlueOak-1.0.0", "dependencies": { "minimatch": "^10.1.1", @@ -2349,10 +3092,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/package-json/node_modules/glob/node_modules/minimatch": { + "version": "10.1.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", - "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", "license": "MIT", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2360,8 +3114,6 @@ }, "node_modules/@npmcli/package-json/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -2372,8 +3124,6 @@ }, "node_modules/@npmcli/promise-spawn": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", - "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", "license": "ISC", "dependencies": { "which": "^6.0.0" @@ -2384,8 +3134,6 @@ }, "node_modules/@npmcli/promise-spawn/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "license": "ISC", "engines": { "node": ">=16" @@ -2393,8 +3141,6 @@ }, "node_modules/@npmcli/promise-spawn/node_modules/which": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -2408,8 +3154,6 @@ }, "node_modules/@npmcli/query": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-5.0.0.tgz", - "integrity": "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ==", "license": "ISC", "dependencies": { "postcss-selector-parser": "^7.0.0" @@ -2419,9 +3163,7 @@ } }, "node_modules/@npmcli/query/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -2433,8 +3175,6 @@ }, "node_modules/@npmcli/redact": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", - "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2442,8 +3182,6 @@ }, "node_modules/@npmcli/run-script": { "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.3.tgz", - "integrity": "sha512-ER2N6itRkzWbbtVmZ9WKaWxVlKlOeBFF1/7xx+KA5J1xKa4JjUwBdb6tDpk0v1qA+d+VDwHI9qmLcXSWcmi+Rw==", "license": "ISC", "dependencies": { "@npmcli/node-gyp": "^5.0.0", @@ -2459,8 +3197,6 @@ }, "node_modules/@npmcli/run-script/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "license": "ISC", "engines": { "node": ">=16" @@ -2468,8 +3204,6 @@ }, "node_modules/@npmcli/run-script/node_modules/which": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -2483,8 +3217,6 @@ }, "node_modules/@parcel/watcher": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2518,31 +3250,8 @@ "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@parcel/watcher-darwin-arm64": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", "cpu": [ "arm64" ], @@ -2560,241 +3269,148 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", - "cpu": [ - "x64" - ], + "node_modules/@polka/url": { + "version": "1.0.0-next.29", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "MIT" }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", - "cpu": [ - "x64" - ], + "node_modules/@rspack/binding": { + "version": "1.7.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.7.3", + "@rspack/binding-darwin-x64": "1.7.3", + "@rspack/binding-linux-arm64-gnu": "1.7.3", + "@rspack/binding-linux-arm64-musl": "1.7.3", + "@rspack/binding-linux-x64-gnu": "1.7.3", + "@rspack/binding-linux-x64-musl": "1.7.3", + "@rspack/binding-wasm32-wasi": "1.7.3", + "@rspack/binding-win32-arm64-msvc": "1.7.3", + "@rspack/binding-win32-ia32-msvc": "1.7.3", + "@rspack/binding-win32-x64-msvc": "1.7.3" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "1.7.3", "cpu": [ - "arm" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "darwin" + ] }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", - "cpu": [ - "arm" - ], + "node_modules/@rspack/cli": { + "version": "1.7.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" + "dependencies": { + "@discoveryjs/json-ext": "^0.5.7", + "@rspack/dev-server": "~1.1.5", + "exit-hook": "^4.0.0", + "webpack-bundle-analyzer": "4.10.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" + "bin": { + "rspack": "bin/rspack.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "@rspack/core": "^1.0.0-alpha || ^1.x" } }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", - "cpu": [ - "arm64" - ], + "node_modules/@rspack/core": { + "version": "1.7.3", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" + "dependencies": { + "@module-federation/runtime-tools": "0.22.0", + "@rspack/binding": "1.7.3", + "@rspack/lite-tapable": "1.1.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10.0.0" + "node": ">=18.12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "@swc/helpers": ">=0.5.1" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } } }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", - "cpu": [ - "x64" - ], + "node_modules/@rspack/dev-server": { + "version": "1.1.5", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "chokidar": "^3.6.0", + "http-proxy-middleware": "^2.0.9", + "p-retry": "^6.2.0", + "webpack-dev-server": "5.2.2", + "ws": "^8.18.0" + }, "engines": { - "node": ">= 10.0.0" + "node": ">= 18.12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "@rspack/core": "*" } }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", - "cpu": [ - "arm64" - ], + "node_modules/@rspack/dev-server/node_modules/chokidar": { + "version": "3.6.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": ">= 10.0.0" + "node": ">= 8.10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", - "cpu": [ - "ia32" - ], + "node_modules/@rspack/dev-server/node_modules/chokidar/node_modules/readdirp": { + "version": "3.6.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" + "dependencies": { + "picomatch": "^2.2.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=8.10.0" } }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", - "cpu": [ - "x64" - ], + "node_modules/@rspack/dev-server/node_modules/chokidar/node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">= 10.0.0" + "node": ">=8.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@rspack/lite-tapable": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, "node_modules/@sigstore/bundle": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", - "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==", "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.5.0" @@ -2804,9 +3420,7 @@ } }, "node_modules/@sigstore/core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.0.0.tgz", - "integrity": "sha512-NgbJ+aW9gQl/25+GIEGYcCyi8M+ng2/5X04BMuIgoDfgvp18vDcoNHOQjQsG9418HGNYRxG3vfEXaR1ayD37gg==", + "version": "3.1.0", "license": "Apache-2.0", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -2814,60 +3428,43 @@ }, "node_modules/@sigstore/protobuf-specs": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.0.tgz", - "integrity": "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==", "license": "Apache-2.0", "engines": { "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@sigstore/sign": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.0.1.tgz", - "integrity": "sha512-KFNGy01gx9Y3IBPG/CergxR9RZpN43N+lt3EozEfeoyqm8vEiLxwRl3ZO5sPx3Obv1ix/p7FWOlPc2Jgwfp9PA==", + "version": "4.1.0", "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", + "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0", - "make-fetch-happen": "^15.0.2", - "proc-log": "^5.0.0", + "make-fetch-happen": "^15.0.3", + "proc-log": "^6.1.0", "promise-retry": "^2.0.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@sigstore/sign/node_modules/proc-log": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", - "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, "node_modules/@sigstore/tuf": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.0.tgz", - "integrity": "sha512-0QFuWDHOQmz7t66gfpfNO6aEjoFrdhkJaej/AOqb4kqWZVbPWFZifXZzkxyQBB1OwTbkhdT3LNpMFxwkTvf+2w==", + "version": "4.0.1", "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.5.0", - "tuf-js": "^4.0.0" + "tuf-js": "^4.1.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@sigstore/verify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.0.0.tgz", - "integrity": "sha512-moXtHH33AobOhTZF8xcX1MpOFqdvfCk7v6+teJL8zymBiDXwEsQH6XG9HGx2VIxnJZNm4cNSzflTLDnQLmIdmw==", + "version": "3.1.0", "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", + "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0" }, "engines": { @@ -2880,36 +3477,30 @@ }, "node_modules/@tufjs/canonical-json": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", - "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", "license": "MIT", "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@tufjs/models": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.0.0.tgz", - "integrity": "sha512-h5x5ga/hh82COe+GoD4+gKUeV4T3iaYOxqLt41GRKApinPI7DMidhCmNVTjKfhCWFJIGXaFJee07XczdT4jdZQ==", + "version": "4.1.0", "license": "MIT", "dependencies": { "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" + "minimatch": "^10.1.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", + "version": "10.1.1", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2917,14 +3508,45 @@ }, "node_modules/@types/ace": { "version": "0.0.52", - "resolved": "https://registry.npmjs.org/@types/ace/-/ace-0.0.52.tgz", - "integrity": "sha512-YPF9S7fzpuyrxru+sG/rrTpZkC6gpHBPF14W3x70kqVOD+ks6jkYLapk4yceh36xej7K4HYxcyz9ZDQ2lTvwgQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } }, "node_modules/@types/eslint": { "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", "dependencies": { @@ -2934,8 +3556,6 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "license": "MIT", "dependencies": { @@ -2945,29 +3565,56 @@ }, "node_modules/@types/estree": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, + "node_modules/@types/express": { + "version": "4.17.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "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, "license": "MIT" }, "node_modules/@types/linkify-it": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "license": "MIT", "peer": true }, "node_modules/@types/markdown-it": { "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "license": "MIT", "peer": true, "dependencies": { @@ -2977,33 +3624,106 @@ }, "node_modules/@types/mdurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "license": "MIT", "peer": true }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "25.2.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.1.tgz", - "integrity": "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==", + "version": "25.0.3", "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" } }, + "node_modules/@types/node-forge": { + "version": "1.3.14", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT", "optional": true }, "node_modules/@types/url-parse": { "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@types/url-parse/-/url-parse-1.4.11.tgz", - "integrity": "sha512-FKvKIqRaykZtd4n47LbK/W/5fhQQ1X7cxxzG9A48h0BGN+S04NH7ervcCjM8tyR0lyGru83FAHSmw2ObgKoESg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@ungap/custom-elements": { "version": "1.3.0", @@ -3011,8 +3731,6 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3022,29 +3740,21 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "license": "MIT", "dependencies": { @@ -3055,15 +3765,11 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, "license": "MIT", "dependencies": { @@ -3075,8 +3781,6 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, "license": "MIT", "dependencies": { @@ -3085,8 +3789,6 @@ }, "node_modules/@webassemblyjs/leb128": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3095,15 +3797,11 @@ }, "node_modules/@webassemblyjs/utf8": { "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", "dev": true, "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3119,8 +3817,6 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, "license": "MIT", "dependencies": { @@ -3133,8 +3829,6 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, "license": "MIT", "dependencies": { @@ -3146,8 +3840,6 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3161,8 +3853,6 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, "license": "MIT", "dependencies": { @@ -3172,8 +3862,6 @@ }, "node_modules/@webpack-cli/configtest": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", - "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", "dev": true, "license": "MIT", "engines": { @@ -3186,8 +3874,6 @@ }, "node_modules/@webpack-cli/info": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", - "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", "dev": true, "license": "MIT", "engines": { @@ -3200,8 +3886,6 @@ }, "node_modules/@webpack-cli/serve": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", - "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", "dev": true, "license": "MIT", "engines": { @@ -3218,9 +3902,7 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "version": "0.8.11", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -3228,8 +3910,6 @@ }, "node_modules/@xterm/addon-attach": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-attach/-/addon-attach-0.11.0.tgz", - "integrity": "sha512-JboCN0QAY6ZLY/SSB/Zl2cQ5zW1Eh4X3fH7BnuR1NB7xGRhzbqU2Npmpiw/3zFlxDaU88vtKzok44JKi2L2V2Q==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.0.0" @@ -3237,8 +3917,6 @@ }, "node_modules/@xterm/addon-fit": { "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", - "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.0.0" @@ -3246,8 +3924,6 @@ }, "node_modules/@xterm/addon-image": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-image/-/addon-image-0.8.0.tgz", - "integrity": "sha512-b/dqpFn3jUad2pUP5UpF4scPIh0WdxRQL/1qyiahGfUI85XZTCXo0py9G6AcOR2QYUw8eJ8EowGspT7BQcgw6A==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.2.0" @@ -3255,8 +3931,6 @@ }, "node_modules/@xterm/addon-search": { "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.15.0.tgz", - "integrity": "sha512-ZBZKLQ+EuKE83CqCmSSz5y1tx+aNOCUaA7dm6emgOX+8J9H1FWXZyrKfzjwzV+V14TV3xToz1goIeRhXBS5qjg==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.0.0" @@ -3264,8 +3938,6 @@ }, "node_modules/@xterm/addon-unicode11": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.8.0.tgz", - "integrity": "sha512-LxinXu8SC4OmVa6FhgwsVCBZbr8WoSGzBl2+vqe8WcQ6hb1r6Gj9P99qTNdPiFPh4Ceiu2pC8xukZ6+2nnh49Q==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.0.0" @@ -3273,8 +3945,6 @@ }, "node_modules/@xterm/addon-web-links": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.11.0.tgz", - "integrity": "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.0.0" @@ -3282,8 +3952,6 @@ }, "node_modules/@xterm/addon-webgl": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz", - "integrity": "sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w==", "license": "MIT", "peerDependencies": { "@xterm/xterm": "^5.0.0" @@ -3291,37 +3959,59 @@ }, "node_modules/@xterm/xterm": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", - "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", "license": "MIT" }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true, "license": "Apache-2.0" }, - "node_modules/abbrev": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", - "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", - "license": "ISC", + "node_modules/accepts": { + "version": "1.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, "node_modules/acorn": { "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3332,8 +4022,6 @@ }, "node_modules/acorn-import-phases": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, "license": "MIT", "engines": { @@ -3343,24 +4031,33 @@ "acorn": "^8.14.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" } }, "node_modules/ajv": { - "version": "8.12.0", + "version": "8.17.1", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3396,8 +4093,6 @@ }, "node_modules/android-versions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/android-versions/-/android-versions-2.1.0.tgz", - "integrity": "sha512-oCBvVs2uaL8ohQtesGs78/X7QvFDLbKgTosBRiOIBCss1a/yiakQm/ADuoG2k/AUaI0FfrsFeMl/a+GtEtjEeA==", "dev": true, "license": "MIT", "dependencies": { @@ -3405,9 +4100,7 @@ } }, "node_modules/android-versions/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", "dev": true, "license": "ISC", "bin": { @@ -3421,15 +4114,75 @@ "version": "0.3.1", "license": "MIT" }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "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==" + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "dev": true, + "license": "MIT" }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "license": "MIT", "engines": { "node": ">=8" @@ -3443,9 +4196,7 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.21", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", - "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "version": "10.4.23", "dev": true, "funding": [ { @@ -3463,10 +4214,9 @@ ], "license": "MIT", "dependencies": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001760", + "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, @@ -3486,8 +4236,6 @@ }, "node_modules/babel-loader": { "version": "10.0.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", - "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", "dev": true, "license": "MIT", "dependencies": { @@ -3503,8 +4251,6 @@ }, "node_modules/babel-loader/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, "license": "MIT", "dependencies": { @@ -3520,8 +4266,6 @@ }, "node_modules/babel-loader/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, "license": "MIT", "dependencies": { @@ -3536,8 +4280,6 @@ }, "node_modules/babel-loader/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, "license": "MIT", "dependencies": { @@ -3552,8 +4294,6 @@ }, "node_modules/babel-loader/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, "license": "MIT", "dependencies": { @@ -3568,8 +4308,6 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "dev": true, "license": "MIT", "dependencies": { @@ -3583,8 +4321,6 @@ }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, "license": "MIT", "dependencies": { @@ -3597,8 +4333,6 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3610,6 +4344,7 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -3631,17 +4366,20 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", - "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "version": "2.9.13", "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/batch": { + "version": "0.6.1", + "dev": true, + "license": "MIT" + }, "node_modules/big-integer": { - "version": "1.6.51", + "version": "1.6.52", "license": "Unlicense", "engines": { "node": ">=0.6" @@ -3657,8 +4395,6 @@ }, "node_modules/bin-links": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-6.0.0.tgz", - "integrity": "sha512-X4CiKlcV2GjnCMwnKAfbVWpHa++65th9TuzAEYtZoATiOE2DQKhSp4CJlyLoTqdhBKlXjpXjCTYPNNFS33Fi6w==", "license": "ISC", "dependencies": { "cmd-shim": "^8.0.0", @@ -3671,10 +4407,19 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/bin-links/node_modules/signal-exit": { + "node_modules/bin-links/node_modules/write-file-atomic": { + "version": "7.0.0", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/bin-links/node_modules/write-file-atomic/node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "license": "ISC", "engines": { "node": ">=14" @@ -3683,42 +4428,86 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/bin-links/node_modules/write-file-atomic": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.0.tgz", - "integrity": "sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg==", - "license": "ISC", + "node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "dev": true, + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/bplist-parser": { - "version": "0.3.2", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "dev": true, "license": "MIT", "dependencies": { - "big-integer": "1.6.x" + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">= 5.10.0" + "node": ">=0.10.0" } }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/bonjour-service": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/bplist-parser": { + "version": "0.3.2", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" } }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -3728,8 +4517,6 @@ }, "node_modules/browserslist": { "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -3762,15 +4549,33 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cacache": { "version": "20.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", - "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", "license": "ISC", "dependencies": { "@npmcli/fs": "^5.0.0", @@ -3791,8 +4596,6 @@ }, "node_modules/cacache/node_modules/glob": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "license": "BlueOak-1.0.0", "dependencies": { "minimatch": "^10.1.1", @@ -3806,15 +4609,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/cacache/node_modules/glob/node_modules/minimatch": { + "version": "10.1.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/cacache/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", + "version": "11.2.4", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "license": "MIT", @@ -3823,9 +4664,7 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001768", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001768.tgz", - "integrity": "sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA==", + "version": "1.0.30001763", "dev": true, "funding": [ { @@ -3843,10 +4682,23 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/chevrotain": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", - "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -3860,8 +4712,6 @@ }, "node_modules/chevrotain-allstar": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", - "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3871,17 +4721,29 @@ "chevrotain": "^11.0.0" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/chownr": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "license": "BlueOak-1.0.0", "engines": { "node": ">=18" } }, "node_modules/chrome-trace-event": { - "version": "1.0.3", + "version": "1.0.4", "dev": true, "license": "MIT", "engines": { @@ -3890,8 +4752,6 @@ }, "node_modules/cli": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==", "dev": true, "license": "MIT", "dependencies": { @@ -3904,8 +4764,6 @@ }, "node_modules/cliui": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "license": "ISC", "dependencies": { "string-width": "^7.2.0", @@ -3918,8 +4776,6 @@ }, "node_modules/cliui/node_modules/ansi-regex": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { "node": ">=12" @@ -3930,14 +4786,10 @@ }, "node_modules/cliui/node_modules/emoji-regex": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "license": "MIT" }, "node_modules/cliui/node_modules/string-width": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -3953,8 +4805,6 @@ }, "node_modules/cliui/node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -3968,8 +4818,6 @@ }, "node_modules/clone-deep": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3983,15 +4831,42 @@ }, "node_modules/cmd-shim": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-8.0.0.tgz", - "integrity": "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/codemirror": { + "version": "6.0.2", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, "node_modules/colorette": { - "version": "2.0.19", + "version": "2.0.20", "dev": true, "license": "MIT" }, @@ -4015,19 +4890,78 @@ "resolved": "src/plugins/pluginContext", "link": true }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" - }, "node_modules/common-ancestor-path": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", "license": "ISC" }, + "node_modules/compressible": { + "version": "2.0.18", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "dev": true, @@ -4048,38 +4982,92 @@ "node": ">=8" } }, - "node_modules/configstore/node_modules/make-dir": { - "version": "3.1.0", + "node_modules/configstore/node_modules/make-dir": { + "version": "3.1.0", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/console-browserify": { + "version": "1.1.0", + "dev": true, + "dependencies": { + "date-now": "^0.1.4" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/content-type": { + "version": "1.0.5", + "dev": true, "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.6" } }, - "node_modules/console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==", + "node_modules/convert-source-map": { + "version": "2.0.0", "dev": true, - "dependencies": { - "date-now": "^0.1.4" + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "node_modules/cookie-signature": { + "version": "1.0.7", + "dev": true, + "license": "MIT" }, "node_modules/cordova": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/cordova/-/cordova-13.0.0.tgz", - "integrity": "sha512-QAIMwmYLL0jHo4vauWSnRd2fr9l+wajG+F5aUkrC6e4ZQGSTv0wAiRmpqQUkIc1ZdELisKDQws/BjHz5nP/sLw==", "license": "Apache-2.0", "dependencies": { "configstore": "^5.0.1", @@ -4101,8 +5089,6 @@ }, "node_modules/cordova-android": { "version": "14.0.1", - "resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-14.0.1.tgz", - "integrity": "sha512-HMBMdGu/JlSQtmBuDEpKWf/pE75SpF3FksxZ+mqYuL3qSIN8lN/QsNurwYaPAP7zWXN2DNpvwlpOJItS5VhdLg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4125,8 +5111,6 @@ }, "node_modules/cordova-android/node_modules/abbrev": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", - "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "dev": true, "license": "ISC", "engines": { @@ -4135,8 +5119,6 @@ }, "node_modules/cordova-android/node_modules/dedent": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -4150,8 +5132,6 @@ }, "node_modules/cordova-android/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, "license": "ISC", "engines": { @@ -4160,8 +5140,6 @@ }, "node_modules/cordova-android/node_modules/nopt": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", - "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "dev": true, "license": "ISC", "dependencies": { @@ -4175,9 +5153,7 @@ } }, "node_modules/cordova-android/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "7.7.3", "dev": true, "license": "ISC", "bin": { @@ -4189,8 +5165,6 @@ }, "node_modules/cordova-android/node_modules/which": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, "license": "ISC", "dependencies": { @@ -4205,8 +5179,6 @@ }, "node_modules/cordova-app-hello-world": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cordova-app-hello-world/-/cordova-app-hello-world-7.0.0.tgz", - "integrity": "sha512-uDTncFkI73ko+wEf6IEO9bw8lQRMQGnfdi5pPMei4P8+plChNcRW5fxjKlhM/8ZrT8OAWiHsQRrP4pIAn3HQ4g==", "license": "Apache-2.0" }, "node_modules/cordova-clipboard": { @@ -4216,8 +5188,6 @@ }, "node_modules/cordova-common": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-5.0.1.tgz", - "integrity": "sha512-OA2NQ6wvhNz4GytPYwTdlA9xfG7Yf7ufkj4u97m3rUfoL/AECwwj0GVT2CYpk/0Fk6HyuHA3QYCxfDPYsKzI1A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4240,8 +5210,6 @@ }, "node_modules/cordova-create": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cordova-create/-/cordova-create-6.0.0.tgz", - "integrity": "sha512-LD41sLn2GsmAlj3576R3xlUM3BP0rt0CYd5LdbzU82WBI3ApMrrhM6xcHDYJfe1nfSL89O/nb/u/h7+7DhPQeA==", "license": "Apache-2.0", "dependencies": { "cordova-app-hello-world": "^7.0.0", @@ -4261,8 +5229,6 @@ }, "node_modules/cordova-create/node_modules/cordova-common": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz", - "integrity": "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg==", "license": "Apache-2.0", "dependencies": { "@netflix/nerror": "^1.1.3", @@ -4279,8 +5245,6 @@ }, "node_modules/cordova-create/node_modules/isobject": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4288,8 +5252,6 @@ }, "node_modules/cordova-fetch": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cordova-fetch/-/cordova-fetch-5.0.0.tgz", - "integrity": "sha512-fsYnVfx32AOrFO6tw4EkzSig7WjNhze35dKIzdw20zTQetDKEfWA79PpCaoiSeahGi6O2MdnOFabLhEa8se6jg==", "license": "Apache-2.0", "dependencies": { "@npmcli/arborist": "^9.1.3", @@ -4308,8 +5270,6 @@ }, "node_modules/cordova-fetch/node_modules/cordova-common": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz", - "integrity": "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg==", "license": "Apache-2.0", "dependencies": { "@netflix/nerror": "^1.1.3", @@ -4326,8 +5286,6 @@ }, "node_modules/cordova-fetch/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "license": "ISC", "engines": { "node": ">=16" @@ -4335,8 +5293,6 @@ }, "node_modules/cordova-fetch/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4347,8 +5303,6 @@ }, "node_modules/cordova-fetch/node_modules/which": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", - "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -4362,8 +5316,6 @@ }, "node_modules/cordova-lib": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/cordova-lib/-/cordova-lib-13.0.0.tgz", - "integrity": "sha512-y8WQ+J6JtiU9C72ujvI3p+ScFJkg0VJwNfaUCqk9nPAssw2C6HltHk+ik/WrLUn6uDmwAM6gmfGUIMU2iVrNxA==", "license": "Apache-2.0", "dependencies": { "cordova-common": "^6.0.0", @@ -4382,8 +5334,6 @@ }, "node_modules/cordova-lib/node_modules/cordova-common": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz", - "integrity": "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg==", "license": "Apache-2.0", "dependencies": { "@netflix/nerror": "^1.1.3", @@ -4400,8 +5350,6 @@ }, "node_modules/cordova-lib/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4410,22 +5358,8 @@ "node": ">=10" } }, - "node_modules/cordova-lib/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/cordova-lib/node_modules/write-file-atomic": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.0.tgz", - "integrity": "sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg==", "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -4435,10 +5369,18 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/cordova-lib/node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/cordova-plugin-advanced-http": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/cordova-plugin-advanced-http/-/cordova-plugin-advanced-http-3.3.1.tgz", - "integrity": "sha512-hESuB3mxIHCUrzb5lm7juda6PSNcC5N8Invizj5wGV2rSldCapiNxMTEpzKR1UVPDDP2XOtBzO0SAYS+3+g/ig==", "dev": true, "engines": [ { @@ -4470,10 +5412,9 @@ } }, "node_modules/cordova-plugin-file": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cordova-plugin-file/-/cordova-plugin-file-8.0.1.tgz", - "integrity": "sha512-LgFLNQN58xguoJkNc8eGBmg/Vuaah9lY3Nye27OAfWCKalXPRjExIg5r8L3qlfiJxzmzupjrF0M4KdU2Lovm3Q==", + "version": "8.1.3", "dev": true, + "license": "Apache-2.0", "engines": { "cordovaDependencies": { "5.0.0": { @@ -4521,8 +5462,6 @@ }, "node_modules/cordova/node_modules/cordova-common": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz", - "integrity": "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg==", "license": "Apache-2.0", "dependencies": { "@netflix/nerror": "^1.1.3", @@ -4537,10 +5476,28 @@ "node": ">=20.9.0" } }, + "node_modules/cordova/node_modules/nopt": { + "version": "9.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/cordova/node_modules/nopt/node_modules/abbrev": { + "version": "4.0.0", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/cordova/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4550,9 +5507,7 @@ } }, "node_modules/core-js": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.0.tgz", - "integrity": "sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA==", + "version": "3.47.0", "hasInstallScript": true, "license": "MIT", "funding": { @@ -4561,13 +5516,11 @@ } }, "node_modules/core-js-compat": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz", - "integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==", + "version": "3.47.0", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.25.1" + "browserslist": "^4.28.0" }, "funding": { "type": "opencollective", @@ -4575,9 +5528,7 @@ } }, "node_modules/core-js-pure": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.45.0.tgz", - "integrity": "sha512-OtwjqcDpY2X/eIIg1ol/n0y/X8A9foliaNt1dSK0gV3J2/zw+89FcNG3mPK+N8YWts4ZFUPxnrAzsxs/lf8yDA==", + "version": "3.47.0", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4592,9 +5543,8 @@ }, "node_modules/cosmiconfig": { "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, + "license": "MIT", "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -4616,10 +5566,13 @@ } } }, + "node_modules/crelt": { + "version": "1.0.6", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4629,10 +5582,26 @@ "node": ">= 8" } }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which/node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, "node_modules/crypto-js": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + "license": "MIT" }, "node_modules/crypto-random-string": { "version": "2.0.0", @@ -4643,8 +5612,6 @@ }, "node_modules/css-loader": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", - "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", "dev": true, "license": "MIT", "dependencies": { @@ -4677,24 +5644,10 @@ } } }, - "node_modules/css-loader/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/css-loader/node_modules/semver": { - "version": "7.5.4", + "version": "7.7.3", "dev": true, "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4702,11 +5655,6 @@ "node": ">=10" } }, - "node_modules/css-loader/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, "node_modules/cssesc": { "version": "3.0.0", "license": "MIT", @@ -4719,8 +5667,6 @@ }, "node_modules/date-now": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==", "dev": true }, "node_modules/dayjs": { @@ -4729,10 +5675,13 @@ "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", "license": "MIT" }, + "node_modules/debounce": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4746,14 +5695,62 @@ } } }, - "node_modules/dedent": { - "version": "0.7.0", - "license": "MIT" + "node_modules/default-browser": { + "version": "5.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-indent": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "license": "MIT", "engines": { "node": ">=8" @@ -4761,8 +5758,6 @@ }, "node_modules/detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -4775,17 +5770,18 @@ }, "node_modules/detect-newline": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/detect-node": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -4794,10 +5790,19 @@ "node": ">=8" } }, + "node_modules/dns-packet": { + "version": "5.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/dom-serializer": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "dev": true, "license": "MIT", "dependencies": { @@ -4807,8 +5812,6 @@ }, "node_modules/dom-serializer/node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { @@ -4820,8 +5823,6 @@ }, "node_modules/dom-serializer/node_modules/entities": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, "license": "BSD-2-Clause", "funding": { @@ -4830,24 +5831,18 @@ }, "node_modules/domelementtype": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", "dev": true, "dependencies": { "domelementtype": "1" } }, "node_modules/dompurify": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", - "integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", + "version": "3.3.1", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -4855,8 +5850,6 @@ }, "node_modules/domutils": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", "dev": true, "dependencies": { "dom-serializer": "0", @@ -4873,14 +5866,35 @@ "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, "node_modules/editor": { "version": "1.0.0", "license": "MIT" }, + "node_modules/ee-first": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { - "version": "1.5.286", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", - "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "version": "1.5.267", "dev": true, "license": "ISC" }, @@ -4894,6 +5908,24 @@ "node": ">= 0.4.0" } }, + "node_modules/emmet": { + "version": "2.4.11", + "license": "MIT", + "workspaces": [ + "./packages/scanner", + "./packages/abbreviation", + "./packages/css-abbreviation", + "./" + ], + "dependencies": { + "@emmetio/abbreviation": "^2.3.3", + "@emmetio/css-abbreviation": "^2.1.8" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "license": "MIT" + }, "node_modules/emojis-list": { "version": "3.0.0", "dev": true, @@ -4902,16 +5934,33 @@ "node": ">= 4" } }, + "node_modules/encodeurl": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/encoding": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" } }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/endent": { "version": "2.1.0", "license": "MIT", @@ -4921,15 +5970,17 @@ "objectorarray": "^1.0.5" } }, + "node_modules/endent/node_modules/dedent": { + "version": "0.7.0", + "license": "MIT" + }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.18.4", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.2.0" }, "engines": { "node": ">=10.13.0" @@ -4937,8 +5988,7 @@ }, "node_modules/entities": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -4954,9 +6004,7 @@ } }, "node_modules/envinfo": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", - "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "version": "7.21.0", "dev": true, "license": "MIT", "bin": { @@ -4968,35 +6016,60 @@ }, "node_modules/err-code": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "license": "MIT" }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "version": "1.3.4", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-module-lexer": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "5.0.0", "license": "MIT", @@ -5011,12 +6084,23 @@ "version": "5.1.1", "dev": true, "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=8.0.0" + "node": ">=4" } }, "node_modules/esrecurse": { @@ -5054,6 +6138,19 @@ "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "dev": true, + "license": "MIT" + }, "node_modules/events": { "version": "3.3.0", "dev": true, @@ -5085,19 +6182,103 @@ }, "node_modules/exit": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" } }, + "node_modules/exit-hook": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "license": "Apache-2.0" }, + "node_modules/express": { + "version": "4.22.1", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/extsprintf": { "version": "1.4.1", "engines": [ @@ -5112,8 +6293,6 @@ }, "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==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -5135,6 +6314,21 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "dev": true, @@ -5144,25 +6338,33 @@ } }, "node_modules/fastq": { - "version": "1.15.0", + "version": "1.20.1", "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/filesize": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-11.0.2.tgz", - "integrity": "sha512-s/iAeeWLk5BschUIpmdrF8RA8lhFZ/xDZgKw1Tan72oGws1/dFGB06nYEiyyssWUfjKNQTNRlrwMVjO9/hvXDw==", + "version": "11.0.13", "license": "BSD-3-Clause", "engines": { - "node": ">= 10.4.0" + "node": ">= 10.8.0" } }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5170,45 +6372,93 @@ "node": ">=8" } }, - "node_modules/find-up": { - "version": "4.1.0", + "node_modules/finalhandler": { + "version": "1.3.2", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, + "node_modules/finalhandler/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/flat": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "version": "5.3.4", "dev": true, + "license": "MIT", "engines": { "node": "*" }, "funding": { - "type": "patreon", + "type": "github", "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fresh": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fs-minipass": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -5222,10 +6472,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5246,9 +6507,7 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "version": "1.4.0", "license": "MIT", "engines": { "node": ">=18" @@ -5257,6 +6516,41 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "license": "MIT", @@ -5296,17 +6590,28 @@ "node": ">= 6" } }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -5327,8 +6632,6 @@ }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -5345,26 +6648,62 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/gzip-size": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, "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, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -5374,8 +6713,6 @@ }, "node_modules/hosted-git-info": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "license": "ISC", "dependencies": { "lru-cache": "^11.1.0" @@ -5385,24 +6722,34 @@ } }, "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", + "version": "11.2.4", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, + "node_modules/hpack.js": { + "version": "2.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, "node_modules/html-tag-js": { - "version": "2.4.15", - "resolved": "https://registry.npmjs.org/html-tag-js/-/html-tag-js-2.4.15.tgz", - "integrity": "sha512-ll1CsDRYPQiUYv8DPUUnDy6k9CTwc7jMObXr7BYV6iuLm7ZUZ4ZSo5CjaU7qh1qL7S4TGaGT+JKqYXksa8dWrg==", + "version": "2.4.16", "license": "MIT" }, "node_modules/htmlparser2": { "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5415,22 +6762,11 @@ }, "node_modules/htmlparser2/node_modules/entities": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", "dev": true, "license": "BSD-like" }, - "node_modules/htmlparser2/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true, - "license": "MIT" - }, "node_modules/htmlparser2/node_modules/readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5440,23 +6776,64 @@ "string_decoder": "~0.10.x" } }, - "node_modules/htmlparser2/node_modules/string_decoder": { + "node_modules/htmlparser2/node_modules/readable-stream/node_modules/isarray": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/htmlparser2/node_modules/readable-stream/node_modules/string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true, "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "license": "BSD-2-Clause" }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -5466,10 +6843,31 @@ "node": ">= 14" } }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5486,17 +6884,12 @@ "node": ">=10.17.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/hyperdyperid": { + "version": "1.2.0", + "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=10.18" } }, "node_modules/icss-utils": { @@ -5512,8 +6905,6 @@ }, "node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "license": "MIT", "engines": { "node": ">= 4" @@ -5521,8 +6912,6 @@ }, "node_modules/ignore-walk": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", - "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", "license": "ISC", "dependencies": { "minimatch": "^10.0.3" @@ -5531,21 +6920,30 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "10.1.1", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/immediate": { "version": "3.0.6", "license": "MIT" }, "node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "version": "5.1.4", "dev": true, "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -5559,7 +6957,7 @@ } }, "node_modules/import-local": { - "version": "3.1.0", + "version": "3.2.0", "dev": true, "license": "MIT", "dependencies": { @@ -5598,8 +6996,6 @@ }, "node_modules/ini": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -5615,23 +7011,37 @@ }, "node_modules/ip-address": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "engines": { "node": ">= 12" } }, + "node_modules/ipaddr.js": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/is-core-module": { "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -5643,6 +7053,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "license": "MIT", @@ -5660,10 +7084,37 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-network-error": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5677,18 +7128,25 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "license": "MIT", "dependencies": { @@ -5698,6 +7156,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-plain-object/node_modules/isobject": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "license": "MIT", @@ -5712,28 +7178,26 @@ "version": "1.0.0", "license": "MIT" }, - "node_modules/isarray": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "license": "ISC" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/is-wsl": { + "version": "3.1.0", "dev": true, "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "1.0.0", + "license": "MIT" + }, "node_modules/java-parser": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/java-parser/-/java-parser-3.0.1.tgz", - "integrity": "sha512-sDIR7u9b7O2JViNUxiZRhnRz7URII/eE7g2B+BmGxDeS6Ex3OYAcCyz5oh0H4LQ+hL/BS8OJTz8apMy9xtGmrQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -5744,8 +7208,6 @@ }, "node_modules/jest-worker": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "license": "MIT", "dependencies": { @@ -5757,31 +7219,39 @@ "node": ">= 10.13.0" } }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "2.6.1", "dev": true, + "license": "MIT", "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-base64": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", - "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" + "version": "3.7.8", + "license": "BSD-3-Clause" }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -5793,8 +7263,6 @@ }, "node_modules/jsesc": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { @@ -5806,8 +7274,6 @@ }, "node_modules/jshint": { "version": "2.13.6", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.6.tgz", - "integrity": "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5825,8 +7291,6 @@ }, "node_modules/jshint/node_modules/brace-expansion": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -5836,8 +7300,6 @@ }, "node_modules/jshint/node_modules/minimatch": { "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, "license": "ISC", "dependencies": { @@ -5859,8 +7321,6 @@ }, "node_modules/json-stringify-nice": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", - "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", "license": "ISC", "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5879,8 +7339,6 @@ }, "node_modules/jsonparse": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "engines": [ "node >= 0.2.0" ], @@ -5898,26 +7356,29 @@ }, "node_modules/just-diff": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", - "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", "license": "MIT" }, "node_modules/just-diff-apply": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", - "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", "license": "MIT" }, "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/launch-editor": { + "version": "2.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, "node_modules/lie": { "version": "3.3.0", "license": "MIT", @@ -5927,22 +7388,18 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/linkify-it": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" } }, "node_modules/loader-runner": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "dev": true, "license": "MIT", "engines": { @@ -5966,25 +7423,12 @@ "node": ">=8.9.0" } }, - "node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/lodash": { "version": "4.17.21", "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "dev": true, "license": "MIT" }, @@ -6000,8 +7444,6 @@ }, "node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { @@ -6010,8 +7452,6 @@ }, "node_modules/make-fetch-happen": { "version": "15.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.3.tgz", - "integrity": "sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==", "license": "ISC", "dependencies": { "@npmcli/agent": "^4.0.0", @@ -6030,6 +7470,13 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/markdown-it": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", @@ -6049,8 +7496,6 @@ }, "node_modules/markdown-it-anchor": { "version": "9.2.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-9.2.0.tgz", - "integrity": "sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg==", "license": "Unlicense", "peerDependencies": { "@types/markdown-it": "*", @@ -6059,14 +7504,10 @@ }, "node_modules/markdown-it-footnote": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-4.0.0.tgz", - "integrity": "sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==", "license": "MIT" }, "node_modules/markdown-it-github-alerts": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-github-alerts/-/markdown-it-github-alerts-1.0.0.tgz", - "integrity": "sha512-RU3cbB/ewujrDpYNdyabvp4CscZ5J/3D71NWbJW+JSA0nplfutIXDMCwtGWlMLwzgBDAYkFMvYGkigq8nWOVdA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" @@ -6077,14 +7518,73 @@ }, "node_modules/markdown-it-task-lists": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz", - "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==", "license": "ISC" }, + "node_modules/marked": { + "version": "15.0.12", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.56.10", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.56.10", + "@jsonjoy.com/fs-fsa": "4.56.10", + "@jsonjoy.com/fs-node": "4.56.10", + "@jsonjoy.com/fs-node-builtins": "4.56.10", + "@jsonjoy.com/fs-node-to-fsa": "4.56.10", + "@jsonjoy.com/fs-node-utils": "4.56.10", + "@jsonjoy.com/fs-print": "4.56.10", + "@jsonjoy.com/fs-snapshot": "4.56.10", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -6097,10 +7597,16 @@ "node": ">= 8" } }, + "node_modules/methods": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -6112,8 +7618,6 @@ }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -6122,8 +7626,19 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { - "version": "1.52.0", + "version": "1.54.0", "dev": true, "license": "MIT", "engines": { @@ -6131,21 +7646,21 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mime-types/node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -6159,9 +7674,7 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.3.tgz", - "integrity": "sha512-tRA0+PsS4kLVijnN1w9jUu5lkxBwUk9E8SbgEB5dBJqchE6pVYdawROG6uQtpmAri7tdCK9i7b1bULeVWqS6Ag==", + "version": "2.9.4", "dev": true, "license": "MIT", "dependencies": { @@ -6179,25 +7692,13 @@ "webpack": "^5.0.0" } }, - "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "dev": true, + "license": "ISC" }, "node_modules/minipass": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -6205,8 +7706,6 @@ }, "node_modules/minipass-collect": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -6217,8 +7716,6 @@ }, "node_modules/minipass-fetch": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.0.tgz", - "integrity": "sha512-fiCdUALipqgPWrOVTz9fw0XhcazULXOSU6ie40DDbX1F49p1dBrSRBuswndTx1x3vEb/g0FT7vC4c4C2u/mh3A==", "license": "MIT", "dependencies": { "minipass": "^7.0.3", @@ -6234,8 +7731,6 @@ }, "node_modules/minipass-flush": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -6246,8 +7741,6 @@ }, "node_modules/minipass-flush/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -6256,16 +7749,12 @@ "node": ">=8" } }, - "node_modules/minipass-flush/node_modules/yallist": { + "node_modules/minipass-flush/node_modules/minipass/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, "node_modules/minipass-pipeline": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -6276,8 +7765,6 @@ }, "node_modules/minipass-pipeline/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -6286,16 +7773,12 @@ "node": ">=8" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { + "node_modules/minipass-pipeline/node_modules/minipass/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, "node_modules/minipass-sized": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -6306,8 +7789,6 @@ }, "node_modules/minipass-sized/node_modules/minipass": { "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -6316,16 +7797,12 @@ "node": ">=8" } }, - "node_modules/minipass-sized/node_modules/yallist": { + "node_modules/minipass-sized/node_modules/minipass/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, "node_modules/minizlib": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "license": "MIT", "dependencies": { "minipass": "^7.1.2" @@ -6334,12 +7811,30 @@ "node": ">= 18" } }, + "node_modules/mrmime": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "dev": true, + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, "node_modules/mustache": { "version": "4.2.0", "license": "MIT", @@ -6348,9 +7843,7 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", "dev": true, "funding": [ { @@ -6358,20 +7851,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/neo-async": { @@ -6381,16 +7866,20 @@ }, "node_modules/node-addon-api": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, "license": "MIT", "optional": true }, + "node_modules/node-forge": { + "version": "1.3.3", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/node-gyp": { "version": "12.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.1.0.tgz", - "integrity": "sha512-W+RYA8jBnhSr2vrTtlPYPc1K+CSjGpVDRZxcqJcERZ8ND3A1ThWPHRwctTx3qC3oW99jt726jhdz3Y6ky87J4g==", "license": "MIT", "dependencies": { "env-paths": "^2.2.0", @@ -6413,17 +7902,33 @@ }, "node_modules/node-gyp/node_modules/isexe": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "license": "ISC", "engines": { "node": ">=16" } }, + "node_modules/node-gyp/node_modules/nopt": { + "version": "9.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-gyp/node_modules/nopt/node_modules/abbrev": { + "version": "4.0.0", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/node-gyp/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6434,8 +7939,6 @@ }, "node_modules/node-gyp/node_modules/which": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.0.tgz", - "integrity": "sha512-f+gEpIKMR9faW/JgAgPK1D7mekkFoqbmiwvNzuhsHetni20QSgzg9Vhn0g2JSJkkfehQnqdUAx7/e15qS1lPxg==", "license": "ISC", "dependencies": { "isexe": "^3.1.1" @@ -6449,28 +7952,11 @@ }, "node_modules/node-releases": { "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, - "node_modules/nopt": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", - "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", - "license": "ISC", - "dependencies": { - "abbrev": "^4.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", + "node_modules/normalize-path": { + "version": "3.0.0", "dev": true, "license": "MIT", "engines": { @@ -6479,8 +7965,6 @@ }, "node_modules/npm-bundled": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", - "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==", "license": "ISC", "dependencies": { "npm-normalize-package-bin": "^5.0.0" @@ -6491,8 +7975,6 @@ }, "node_modules/npm-install-checks": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", - "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", "license": "BSD-2-Clause", "dependencies": { "semver": "^7.1.1" @@ -6503,8 +7985,6 @@ }, "node_modules/npm-install-checks/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6515,8 +7995,6 @@ }, "node_modules/npm-normalize-package-bin": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -6524,8 +8002,6 @@ }, "node_modules/npm-package-arg": { "version": "13.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", - "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", "license": "ISC", "dependencies": { "hosted-git-info": "^9.0.0", @@ -6539,8 +8015,6 @@ }, "node_modules/npm-package-arg/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6551,8 +8025,6 @@ }, "node_modules/npm-packlist": { "version": "10.0.3", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.3.tgz", - "integrity": "sha512-zPukTwJMOu5X5uvm0fztwS5Zxyvmk38H/LfidkOMt3gbZVCyro2cD/ETzwzVPcWZA3JOyPznfUN/nkyFiyUbxg==", "license": "ISC", "dependencies": { "ignore-walk": "^8.0.0", @@ -6564,8 +8036,6 @@ }, "node_modules/npm-pick-manifest": { "version": "11.0.3", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", - "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", "license": "ISC", "dependencies": { "npm-install-checks": "^8.0.0", @@ -6579,8 +8049,6 @@ }, "node_modules/npm-pick-manifest/node_modules/semver": { "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6591,8 +8059,6 @@ }, "node_modules/npm-registry-fetch": { "version": "19.1.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", - "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", "license": "ISC", "dependencies": { "@npmcli/redact": "^4.0.0", @@ -6618,10 +8084,45 @@ "node": ">=8" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/objectorarray": { "version": "1.0.5", "license": "ISC" }, + "node_modules/obuf": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "dev": true, @@ -6643,6 +8144,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "10.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "dev": true, + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, "node_modules/p-finally": { "version": "1.0.0", "dev": true, @@ -6651,41 +8177,38 @@ "node": ">=4" } }, - "node_modules/p-limit": { - "version": "2.3.0", - "dev": true, + "node_modules/p-map": { + "version": "7.0.4", "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate": { - "version": "4.1.0", + "node_modules/p-retry": { + "version": "6.2.1", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "dev": true, "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 4" } }, "node_modules/p-try": { @@ -6698,8 +8221,6 @@ }, "node_modules/pacote": { "version": "21.0.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.4.tgz", - "integrity": "sha512-RplP/pDW0NNNDh3pnaoIWYPvNenS7UqMbXyvMqJczosiFWTeGGwJC2NQBLqKf4rGLFfwCOnntw1aEp9Jiqm1MA==", "license": "ISC", "dependencies": { "@npmcli/git": "^7.0.0", @@ -6743,8 +8264,6 @@ }, "node_modules/parse-conflict-json": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-5.0.1.tgz", - "integrity": "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ==", "license": "ISC", "dependencies": { "json-parse-even-better-errors": "^5.0.0", @@ -6757,8 +8276,6 @@ }, "node_modules/parse-conflict-json/node_modules/json-parse-even-better-errors": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", - "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", "license": "MIT", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -6766,9 +8283,8 @@ }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -6782,6 +8298,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "dev": true, @@ -6805,8 +8329,6 @@ }, "node_modules/path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", "license": "(WTFPL OR MIT)" }, "node_modules/path-key": { @@ -6822,8 +8344,6 @@ }, "node_modules/path-scurry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", @@ -6837,18 +8357,19 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "license": "ISC", + "version": "11.2.4", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "dev": true, + "license": "MIT" + }, "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "license": "MIT", "engines": { "node": ">=8" @@ -6856,15 +8377,11 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", "engines": { "node": ">=12" @@ -6892,10 +8409,56 @@ "node": ">=8" } }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up/node_modules/locate-path/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up/node_modules/locate-path/node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/plist": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", - "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", @@ -6907,9 +8470,7 @@ } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.5.6", "dev": true, "funding": [ { @@ -6925,24 +8486,24 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/postcss-loader": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", - "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "version": "8.2.0", "dev": true, + "license": "MIT", "dependencies": { "cosmiconfig": "^9.0.0", - "jiti": "^1.20.0", - "semver": "^7.5.4" + "jiti": "^2.5.1", + "semver": "^7.6.2" }, "engines": { "node": ">= 18.12.0" @@ -6965,24 +8526,10 @@ } } }, - "node_modules/postcss-loader/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.5.4", + "version": "7.7.3", "dev": true, "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -6990,15 +8537,8 @@ "node": ">=10" } }, - "node_modules/postcss-loader/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, "license": "ISC", "engines": { @@ -7009,14 +8549,12 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "version": "4.2.0", "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -7027,13 +8565,11 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "version": "3.2.1", "dev": true, "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^10 || ^12 || >= 14" @@ -7057,7 +8593,7 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.11", + "version": "7.1.1", "dev": true, "license": "MIT", "dependencies": { @@ -7074,9 +8610,7 @@ "license": "MIT" }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.7.4", "dev": true, "license": "MIT", "bin": { @@ -7090,9 +8624,7 @@ } }, "node_modules/prettier-plugin-java": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/prettier-plugin-java/-/prettier-plugin-java-2.7.4.tgz", - "integrity": "sha512-RiRNkumIW9vaDpxirgIPI+oLSRmuCmoVZuTax9i3cWzWnxd+uKyAfDe4efS+ce00owAeh0a1DI5eFaH1xYWNPg==", + "version": "2.8.1", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7104,8 +8636,6 @@ }, "node_modules/proc-log": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", - "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -7117,8 +8647,6 @@ }, "node_modules/proggy": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/proggy/-/proggy-4.0.0.tgz", - "integrity": "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -7126,8 +8654,6 @@ }, "node_modules/promise-all-reject-late": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", - "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", "license": "ISC", "funding": { "url": "https://github.com/sponsors/isaacs" @@ -7135,8 +8661,6 @@ }, "node_modules/promise-call-limit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz", - "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==", "license": "ISC", "funding": { "url": "https://github.com/sponsors/isaacs" @@ -7144,8 +8668,6 @@ }, "node_modules/promise-retry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "license": "MIT", "dependencies": { "err-code": "^2.0.2", @@ -7155,18 +8677,43 @@ "node": ">=10" } }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/properties-parser": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.6.0.tgz", - "integrity": "sha512-qvr2cSmoA0dln0MARAKwBzPkkXn7FqwX+RVVNpMdMJc7rt9mqO2cXwluxtux9fHrLhjnPFaQkS8BM0kFrTCnSw==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.3.1" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/punycode": { - "version": "2.3.0", + "version": "2.3.1", "dev": true, "license": "MIT", "engines": { @@ -7175,8 +8722,7 @@ }, "node_modules/punycode.js": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -7190,6 +8736,20 @@ "teleport": ">=0.2.0" } }, + "node_modules/qs": { + "version": "6.14.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/querystringify": { "version": "2.2.0", "license": "MIT" @@ -7214,21 +8774,72 @@ }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } }, - "node_modules/raw-loader": { - "version": "4.0.2", + "node_modules/range-parser": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/raw-loader": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/raw-loader/node_modules/schema-utils": { + "version": "3.3.0", "dev": true, "license": "MIT", "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { "node": ">= 10.13.0" @@ -7236,12 +8847,9 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/raw-loader/node_modules/ajv": { + "node_modules/raw-loader/node_modules/schema-utils/node_modules/ajv": { "version": "6.12.6", "dev": true, "license": "MIT", @@ -7256,7 +8864,7 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/raw-loader/node_modules/ajv-keywords": { + "node_modules/raw-loader/node_modules/schema-utils/node_modules/ajv-keywords": { "version": "3.5.2", "dev": true, "license": "MIT", @@ -7264,28 +8872,11 @@ "ajv": "^6.9.1" } }, - "node_modules/raw-loader/node_modules/json-schema-traverse": { + "node_modules/raw-loader/node_modules/schema-utils/node_modules/ajv/node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, "license": "MIT" }, - "node_modules/raw-loader/node_modules/schema-utils": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/read-chunk": { "version": "3.2.0", "dev": true, @@ -7300,15 +8891,13 @@ }, "node_modules/read-cmd-shim": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-6.0.0.tgz", - "integrity": "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A==", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" } }, "node_modules/readable-stream": { - "version": "2.3.7", + "version": "2.3.8", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -7320,6 +8909,18 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdirp": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/rechoir": { "version": "0.8.0", "dev": true, @@ -7333,15 +8934,11 @@ }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "version": "10.2.2", "dev": true, "license": "MIT", "dependencies": { @@ -7352,18 +8949,16 @@ } }, "node_modules/regexpu-core": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", - "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "version": "6.4.0", "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", + "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", - "regjsparser": "^0.12.0", + "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.2.1" }, "engines": { "node": ">=4" @@ -7371,37 +8966,20 @@ }, "node_modules/regjsgen": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "dev": true, "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", - "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "version": "0.13.0", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~3.0.2" + "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "dev": true, @@ -7415,12 +8993,10 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7460,21 +9036,23 @@ "node": ">=4" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "node_modules/reusify": { + "version": "1.1.0", "license": "MIT", "engines": { - "node": ">= 4" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/reusify": { - "version": "1.0.4", + "node_modules/run-applescript": { + "version": "7.1.0", + "dev": true, "license": "MIT", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/run-parallel": { @@ -7504,15 +9082,11 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/sass": { - "version": "1.90.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", - "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", + "version": "1.97.2", "dev": true, "license": "MIT", "dependencies": { @@ -7531,9 +9105,7 @@ } }, "node_modules/sass-loader": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz", - "integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==", + "version": "16.0.6", "dev": true, "license": "MIT", "dependencies": { @@ -7571,44 +9143,12 @@ } } }, - "node_modules/sass/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/sass/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/sax": { "version": "1.1.4", "license": "ISC" }, "node_modules/schema-utils": { "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "license": "MIT", "dependencies": { @@ -7625,6 +9165,23 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/select-hose": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "6.3.1", "license": "ISC", @@ -7632,24 +9189,159 @@ "semver": "bin/semver.js" } }, + "node_modules/send": { + "version": "0.19.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/serialize-javascript": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, + "node_modules/serve-index": { + "version": "1.9.2", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors/node_modules/statuses": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "license": "MIT" }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, "node_modules/shallow-clone": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, "license": "MIT", "dependencies": { @@ -7676,31 +9368,119 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "license": "ISC" }, "node_modules/sigstore": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.0.0.tgz", - "integrity": "sha512-Gw/FgHtrLM9WP8P5lLcSGh9OQcrTruWCELAiS48ik1QbL0cH+dfjomiRTUE9zzz+D1N6rOLkwXUvVmXZAsNE0Q==", + "version": "4.1.0", "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.0.0", + "@sigstore/core": "^3.1.0", "@sigstore/protobuf-specs": "^0.5.0", - "@sigstore/sign": "^4.0.0", - "@sigstore/tuf": "^4.0.0", - "@sigstore/verify": "^3.0.0" + "@sigstore/sign": "^4.1.0", + "@sigstore/tuf": "^4.0.1", + "@sigstore/verify": "^3.1.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/sirv": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "license": "MIT", "engines": { "node": ">=8" @@ -7708,18 +9488,24 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" } }, + "node_modules/sockjs": { + "version": "0.3.24", + "dev": true, + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, "node_modules/socks": { "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "license": "MIT", "dependencies": { "ip-address": "^10.0.1", @@ -7732,8 +9518,6 @@ }, "node_modules/socks-proxy-agent": { "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -7744,18 +9528,8 @@ "node": ">= 14" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { - "version": "1.0.2", + "version": "1.2.1", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -7764,8 +9538,6 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "license": "MIT", "dependencies": { @@ -7773,10 +9545,16 @@ "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -7785,14 +9563,10 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", @@ -7801,15 +9575,51 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "license": "CC0-1.0" }, + "node_modules/spdy": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/sprintf": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz", - "integrity": "sha512-4X5KsuXFQ7f+d7Y+bi4qSb6eI+YoifDTGr0MQJXRoYO7BO7evfRCjds6kk3z7l5CiJYxgDN1x5Er4WiyCt+zTQ==", - "deprecated": "The sprintf package is deprecated in favor of sprintf-js.", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -7818,8 +9628,6 @@ }, "node_modules/ssri": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", - "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -7828,6 +9636,14 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/statuses": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "license": "MIT", @@ -7837,21 +9653,44 @@ }, "node_modules/string-argv": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "license": "MIT", "engines": { "node": ">=0.6.19" } }, + "node_modules/string-width": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stringify-package": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", - "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==", - "deprecated": "This module is not used anymore, and has been replaced by @npmcli/package-json", "license": "ISC" }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "dev": true, @@ -7869,8 +9708,6 @@ }, "node_modules/strip-json-comments": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", "dev": true, "license": "MIT", "bin": { @@ -7882,8 +9719,6 @@ }, "node_modules/style-loader": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", - "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", "dev": true, "license": "MIT", "engines": { @@ -7897,20 +9732,19 @@ "webpack": "^5.27.0" } }, + "node_modules/style-mod": { + "version": "4.1.3", + "license": "MIT" + }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -7924,9 +9758,7 @@ } }, "node_modules/systeminformation": { - "version": "5.27.14", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.27.14.tgz", - "integrity": "sha512-3DoNDYSZBLxBwaJtQGWNpq0fonga/VZ47HY1+7/G3YoIPaPz93Df6egSzzTKbEMmlzUpy3eQ0nR9REuYIycXGg==", + "version": "5.30.2", "license": "MIT", "os": [ "darwin", @@ -7951,8 +9783,6 @@ }, "node_modules/tapable": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, "license": "MIT", "engines": { @@ -7964,9 +9794,7 @@ } }, "node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "version": "7.5.2", "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", @@ -7981,8 +9809,6 @@ }, "node_modules/tar/node_modules/yallist": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -7990,8 +9816,6 @@ }, "node_modules/terminal": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/terminal/-/terminal-0.1.4.tgz", - "integrity": "sha512-w6OAFpUO+TimZUdQ46dK3fYYOCCBIsS2QUfIEkzX21oJ8tvJOJvJkcmrbleLH5KG02SNohYFDj81bL3VPaULsQ==", "dev": true, "dependencies": { "sprintf": ">= 0.1.1" @@ -8001,9 +9825,7 @@ } }, "node_modules/terser": { - "version": "5.46.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", - "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "version": "5.44.1", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -8021,8 +9843,6 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8054,10 +9874,33 @@ } } }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" + }, + "node_modules/thingies": { + "version": "2.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -8072,8 +9915,6 @@ }, "node_modules/tinyglobby/node_modules/fdir": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", "engines": { "node": ">=12.0.0" @@ -8089,8 +9930,6 @@ }, "node_modules/tmp": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "license": "MIT", "engines": { "node": ">=14.14" @@ -8098,8 +9937,7 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8107,29 +9945,130 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-dump": { + "version": "1.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/treeverse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", - "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/ts-loader": { + "version": "9.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.7.3", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.6", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "license": "0BSD" + }, "node_modules/tuf-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.0.0.tgz", - "integrity": "sha512-Lq7ieeGvXDXwpoSmOSgLWVdsGGV9J4a77oDTAPe/Ltrqnnm/ETaRlBAQTH5JatEh8KXuE6sddf9qAv1Q2282Hg==", + "version": "4.1.0", "license": "MIT", "dependencies": { - "@tufjs/models": "4.0.0", - "debug": "^4.4.1", - "make-fetch-happen": "^15.0.0" + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/type-is": { + "version": "1.6.18", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "license": "MIT", @@ -8137,22 +10076,29 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/uc.micro": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + "license": "MIT" }, "node_modules/undici-types": { "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { @@ -8161,8 +10107,6 @@ }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8174,9 +10118,7 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "version": "2.2.1", "dev": true, "license": "MIT", "engines": { @@ -8184,9 +10126,7 @@ } }, "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "version": "2.2.0", "dev": true, "license": "MIT", "engines": { @@ -8195,8 +10135,6 @@ }, "node_modules/unique-filename": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", - "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", "license": "ISC", "dependencies": { "unique-slug": "^6.0.0" @@ -8207,8 +10145,6 @@ }, "node_modules/unique-slug": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", - "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" @@ -8227,10 +10163,16 @@ "node": ">=8" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/untildify": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true, "license": "MIT", "engines": { @@ -8239,8 +10181,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -8288,16 +10228,28 @@ "version": "1.0.2", "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/valid-identifier": { "version": "0.0.2", - "resolved": "https://registry.npmjs.org/valid-identifier/-/valid-identifier-0.0.2.tgz", - "integrity": "sha512-zaSmOW6ykXwrkX0YTuFUSoALNEKGaQHpxBJQLb3TXspRNDpBwbfrIQCZqAQ0LKBlKuyn2YOq7NNd6415hvZ33g==", "license": "Apache-2.0" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", @@ -8305,9 +10257,7 @@ } }, "node_modules/validate-npm-package-name": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.0.tgz", - "integrity": "sha512-bwVk/OK+Qu108aJcMAEiU4yavHUI7aN20TgZNBj9MR2iU1zPUl1Z1Otr7771ExfYTPTvfN8ZJ1pbr5Iklgt4xg==", + "version": "7.0.2", "license": "ISC", "engines": { "node": "^20.17.0 || >=22.9.0" @@ -8315,17 +10265,44 @@ }, "node_modules/vanilla-picker": { "version": "2.12.3", - "resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.3.tgz", - "integrity": "sha512-qVkT1E7yMbUsB2mmJNFmaXMWE2hF8ffqzMMwe9zdAikd8u2VfnsVY2HQcOUi2F38bgbxzlJBEdS1UUhOXdF9GQ==", "license": "ISC", "dependencies": { "@sphinxxxx/color-conversion": "^2.2.2" } }, + "node_modules/vary": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "license": "MIT" + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "license": "MIT" + }, "node_modules/walk-up-path": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", - "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==", "license": "ISC", "engines": { "node": "20 || >=22" @@ -8333,8 +10310,6 @@ }, "node_modules/watchpack": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "license": "MIT", "dependencies": { @@ -8345,10 +10320,16 @@ "node": ">=10.13.0" } }, + "node_modules/wbuf": { + "version": "1.7.3", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/webpack": { "version": "5.105.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", - "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "dev": true, "license": "MIT", "dependencies": { @@ -8394,10 +10375,80 @@ } } }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/webpack-cli": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", - "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, "license": "MIT", "dependencies": { @@ -8437,20 +10488,153 @@ } } }, + "node_modules/webpack-cli/node_modules/@discoveryjs/json-ext": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17.0" + } + }, "node_modules/webpack-cli/node_modules/commander": { "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, "license": "MIT", "engines": { "node": ">=18" } }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.5", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.21.2", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar/node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar/node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/webpack-merge": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", - "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, "license": "MIT", "dependencies": { @@ -8464,18 +10648,26 @@ }, "node_modules/webpack-sources": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/enhanced-resolve": { + "version": "5.19.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webpack/node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { @@ -8485,23 +10677,56 @@ "node": ">= 0.6" } }, - "node_modules/which": { - "version": "2.0.2", - "license": "ISC", + "node_modules/webpack/node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" }, "engines": { - "node": ">= 8" + "node": ">=0.8.0" + } + }, + "node_modules/websocket-driver/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" } }, "node_modules/wildcard": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true, "license": "MIT" }, @@ -8519,9 +10744,7 @@ } }, "node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "version": "9.0.2", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -8535,22 +10758,8 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", "license": "MIT", "engines": { "node": ">=12" @@ -8559,44 +10768,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "dev": true, @@ -8612,6 +10783,40 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/ws": { + "version": "8.19.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xdg-basedir": { "version": "4.0.0", "license": "MIT", @@ -8621,8 +10826,6 @@ }, "node_modules/xmlbuilder": { "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "license": "MIT", "engines": { "node": ">=8.0" @@ -8637,15 +10840,11 @@ }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, "node_modules/yargs": { "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "license": "MIT", "dependencies": { "cliui": "^9.0.1", @@ -8661,8 +10860,6 @@ }, "node_modules/yargs-parser": { "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "license": "ISC", "engines": { "node": "^20.19.0 || ^22.12.0 || >=23" @@ -8670,8 +10867,6 @@ }, "node_modules/yargs/node_modules/ansi-regex": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "license": "MIT", "engines": { "node": ">=12" @@ -8682,14 +10877,10 @@ }, "node_modules/yargs/node_modules/emoji-regex": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "license": "MIT" }, "node_modules/yargs/node_modules/string-width": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -8705,8 +10896,6 @@ }, "node_modules/yargs/node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -8720,8 +10909,6 @@ }, "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, "license": "MIT", "engines": { @@ -8779,12 +10966,6 @@ "dev": true, "license": "MIT" }, - "src/plugins/Executor": { - "name": "com.foxdebug.acode.rk.exec.terminal", - "version": "1.0.0", - "extraneous": true, - "license": "MIT" - }, "src/plugins/ftp": { "name": "cordova-plugin-ftp", "version": "1.1.1", @@ -8815,12 +10996,6 @@ "dev": true, "license": "ISC" }, - "src/plugins/secrets": { - "name": "com.foxdebug.acode.rk.secrets", - "version": "1.0.0", - "extraneous": true, - "license": "MIT" - }, "src/plugins/server": { "name": "cordova-plugin-server", "version": "1.0.0", diff --git a/package.json b/package.json index d4e6acefd..23c64b5c0 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "lint": "biome lint --write", "format": "biome format --write", "check": "biome check --write", + "typecheck": "tsc --noEmit", "updateAce": "node ./utils/updateAce.js" }, "keywords": [ @@ -56,15 +57,18 @@ }, "homepage": "https://github.com/deadlyjack/acode#readme", "devDependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-runtime": "^7.28.0", - "@babel/preset-env": "^7.28.0", - "@babel/runtime": "^7.28.2", - "@babel/runtime-corejs3": "^7.28.2", + "@babel/core": "^7.28.5", + "@babel/plugin-transform-runtime": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@babel/preset-typescript": "^7.28.5", + "@babel/runtime": "^7.28.4", + "@babel/runtime-corejs3": "^7.28.4", "@biomejs/biome": "2.1.4", + "@rspack/cli": "^1.7.0", + "@rspack/core": "^1.7.0", "@types/ace": "^0.0.52", "@types/url-parse": "^1.4.11", - "autoprefixer": "^10.4.21", + "autoprefixer": "^10.4.22", "babel-loader": "^10.0.0", "com.foxdebug.acode.rk.auth": "file:src/plugins/auth", "com.foxdebug.acode.rk.customtabs": "file:src/plugins/custom-tabs", @@ -76,8 +80,8 @@ "cordova-plugin-advanced-http": "^3.3.1", "cordova-plugin-browser": "file:src/plugins/browser", "cordova-plugin-buildinfo": "file:src/plugins/cordova-plugin-buildinfo", - "cordova-plugin-device": "^2.0.3", - "cordova-plugin-file": "^8.0.1", + "cordova-plugin-device": "^2.1.0", + "cordova-plugin-file": "^8.1.3", "cordova-plugin-ftp": "file:src/plugins/ftp", "cordova-plugin-iap": "file:src/plugins/iap", "cordova-plugin-sdcard": "file:src/plugins/sdcard", @@ -86,21 +90,52 @@ "cordova-plugin-system": "file:src/plugins/system", "cordova-plugin-websocket": "file:src/plugins/websocket", "css-loader": "^7.1.2", - "mini-css-extract-plugin": "^2.9.3", + "mini-css-extract-plugin": "^2.9.4", "path-browserify": "^1.0.1", - "postcss-loader": "^8.1.1", - "prettier": "^3.6.2", - "prettier-plugin-java": "^2.7.4", + "postcss-loader": "^8.2.0", + "prettier": "^3.7.4", + "prettier-plugin-java": "^2.7.7", "raw-loader": "^4.0.2", - "sass": "^1.90.0", - "sass-loader": "^16.0.5", + "sass": "^1.94.2", + "sass-loader": "^16.0.6", "style-loader": "^4.0.0", "terminal": "^0.1.4", + "ts-loader": "^9.5.4", + "typescript": "^5.9.3", + "vscode-languageserver-types": "^3.17.5", "webpack": "^5.105.0", "webpack-cli": "^6.0.1" }, "dependencies": { + "@codemirror/autocomplete": "^6.20.0", + "@codemirror/commands": "^6.10.0", + "@codemirror/lang-cpp": "^6.0.3", + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-go": "^6.0.1", + "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-java": "^6.0.2", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.2", + "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-php": "^6.0.2", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/lang-rust": "^6.0.2", + "@codemirror/lang-sass": "^6.0.2", + "@codemirror/lang-vue": "^0.1.3", + "@codemirror/lang-xml": "^6.1.0", + "@codemirror/lang-yaml": "^6.1.2", + "@codemirror/language": "^6.11.3", + "@codemirror/language-data": "^6.5.2", + "@codemirror/legacy-modes": "^6.5.2", + "@codemirror/lint": "^6.9.2", + "@codemirror/lsp-client": "^6.2.1", + "@codemirror/search": "^6.5.11", + "@codemirror/state": "^6.5.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.38.8", "@deadlyjack/ajax": "^1.2.6", + "@emmetio/codemirror6-plugin": "^0.4.0", + "@lezer/highlight": "^1.2.3", "@ungap/custom-elements": "^1.3.0", "@xterm/addon-attach": "^0.11.0", "@xterm/addon-fit": "^0.10.0", @@ -112,15 +147,17 @@ "@xterm/xterm": "^5.5.0", "acorn": "^8.15.0", "autosize": "^6.0.1", + "codemirror": "^6.0.2", "cordova": "13.0.0", - "core-js": "^3.45.0", + "core-js": "^3.47.0", "crypto-js": "^4.2.0", "dayjs": "^1.11.19", - "dompurify": "^3.2.6", + "dompurify": "^3.3.0", "escape-string-regexp": "^5.0.0", - "filesize": "^11.0.2", - "html-tag-js": "^2.4.15", - "js-base64": "^3.7.7", + "esprima": "^4.0.1", + "filesize": "^11.0.13", + "html-tag-js": "^2.4.16", + "js-base64": "^3.7.8", "jszip": "^3.10.1", "markdown-it": "^14.1.1", "markdown-it-anchor": "^9.2.0", diff --git a/readme.md b/readme.md index f95dad8c3..a9c3070f8 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# Acode - Code Editor for Android +# Acode2 - Code Editor for Android

diff --git a/res/android/values/colors.xml b/res/android/values/colors.xml index 6b5433be0..ea7bb0320 100644 --- a/res/android/values/colors.xml +++ b/res/android/values/colors.xml @@ -1,4 +1,5 @@ #3a3e54 - \ No newline at end of file + #FFFFFF + diff --git a/res/android/values/themes.xml b/res/android/values/themes.xml index feed35132..1320016f8 100644 --- a/res/android/values/themes.xml +++ b/res/android/values/themes.xml @@ -4,10 +4,14 @@ @color/ic_splash_background @drawable/ic_launcher_foreground 200 - @style/Theme.AppCompat.DayNight.NoActionBar + @style/Theme.App.Activity true diff --git a/rspack.config.js b/rspack.config.js new file mode 100644 index 000000000..2a882aa26 --- /dev/null +++ b/rspack.config.js @@ -0,0 +1,147 @@ +const path = require('path'); +const { rspack } = require('@rspack/core'); + +module.exports = (env, options) => { + const { mode = 'development' } = options; + const prod = mode === 'production'; + + const rules = [ + // TypeScript/TSX files - Custom JSX loader + SWC + { + test: /\.tsx?$/, + exclude: /node_modules/, + use: [ + { + loader: 'builtin:swc-loader', + options: { + jsc: { + parser: { + syntax: 'typescript', + tsx: false, + }, + transform: { + // react: { + // pragma: 'tag', + // pragmaFrag: 'Array', + // throwIfNamespace: false, + // development: false, + // useBuiltins: false, + // runtime: 'classic', + // }, + }, + target: 'es2015', + }, + }, + }, + path.resolve(__dirname, 'utils/custom-loaders/html-tag-jsx-loader.js'), + ], + }, + // JavaScript files + { + test: /\.m?js$/, + oneOf: [ + // Node modules - use builtin:swc-loader only + { + include: /node_modules/, + use: [ + { + loader: 'builtin:swc-loader', + options: { + jsc: { + parser: { + syntax: 'ecmascript', + }, + target: 'es2015', + }, + }, + }, + ], + }, + // Source JS files - Custom JSX loader + SWC (JSX will be removed first) + { + use: [ + { + loader: 'builtin:swc-loader', + options: { + jsc: { + parser: { + syntax: 'ecmascript', + jsx: false, + }, + target: 'es2015', + }, + }, + }, + path.resolve(__dirname, 'utils/custom-loaders/html-tag-jsx-loader.js'), + ], + }, + ], + }, + // Handlebars and Markdown files + { + test: /\.(hbs|md)$/, + type: 'asset/source', + }, + // Module CSS/SCSS (with .m prefix) + { + test: /\.m\.(sa|sc|c)ss$/, + use: [ + 'raw-loader', + 'postcss-loader', + 'sass-loader', + ], + type: 'javascript/auto', + }, + // Asset files + { + test: /\.(png|svg|jpg|jpeg|ico|ttf|webp|eot|woff|webm|mp4|wav)(\?.*)?$/, + type: 'asset/resource', + }, + // Regular CSS/SCSS files + { + test: /(? { - if (file.session) { - file.session._addedColorRule = false; - } - }); - } - - onChangeMode(); - } -} - -export function deactivateColorView() { - const { renderer } = editor; - - changedRules.forEach((rule) => rule.shift()); - changedRules.length = 0; - forceTokenizer(); - - editor.off("changeMode", onChangeMode); - renderer.off("afterRender", afterRender); -} - -/** - * Checks if the session supports color - * @param {AceAjax.IEditSession} session - * @returns - */ -function sessionSupportsColor(session) { - const mode = session.getMode().$id.split("/").pop(); - return /css|less|scss|sass|stylus|html|svg|dart/.test(mode) ? mode : false; -} - -function onChangeMode() { - const session = editor.session; - let forceUpdate = false; - - // if mode is not css, scss, sass, less, stylus, or html, return - const mode = sessionSupportsColor(session); - if (session._addedColorRule || !mode) { - return; - } - - let rules = session.$mode.$highlightRules.getRules(); - - if (mode === "css") { - rules = { ruleset: rules["ruleset"] }; - } else if (mode === "html") { - rules = { "css-ruleset": rules["css-ruleset"] }; - } else if (mode === "svg") { - const svgColorAttrs = [ - "fill", - "stroke", - "stop-color", - "flood-color", - "lighting-color", - ]; - Object.keys(rules).forEach((key) => { - const rule = rules[key]; - if (Array.isArray(rule)) { - rule.unshift({ - token: "color", - regex: `(?<=\\b(?:${svgColorAttrs.join("|")})\\s*=\\s*["'])(${HEX}|${RGB}|${RGBA}|${HSL}|${HSLA}|\\w+)(?=["'])`, - }); - rule.unshift({ - token: "color", - regex: `(?<=style\\s*=\\s*["'][^"']*(?:${svgColorAttrs.join("|")})\\s*:\\s*)(${HEX}|${RGB}|${RGBA}|${HSL}|${HSLA}|\\w+)(?=\\s*[;'"])`, - }); - changedRules.push(rule); - forceUpdate = true; - } - }); - } - - Object.keys(rules).forEach((key) => { - const rule = rules[key]; - if (Array.isArray(rule)) { - const ruleExists = rule.some((r) => r.token === "color"); - if (ruleExists) return; - forceUpdate = true; - rule.unshift({ - token: "color", - regex: `${HEX}|${RGB}|${RGBA}|${HSL}|${HSLA}`, - }); - changedRules.push(rule); - return; - } - }); - - if (!forceUpdate) return; - - forceTokenizer(); -} - -function afterRender() { - const { session, renderer } = editor; - const { content } = renderer; - let classes = COLORPICKER_TOKEN_CLASS; - - // if session is css, scss, less, sass, stylus, or html (with css mode), continue - - const mode = sessionSupportsColor(session); - if (!mode) { - return; - } - - if (mode === "scss") { - classes += ",.ace_function"; - } - - content - .getAll(COLORPICKER_TOKEN_CLASS) - .forEach((/**@type {HTMLElement} */ el, i, els) => { - let content = el.textContent; - const previousContent = els[i - 1]?.textContent; - const nextContent = els[i + 1]?.textContent; - const multiLinePrev = previousContent + content; - const multiLineNext = content + nextContent; - - if (el.dataset.modified === "true") return; - el.dataset.modified = "true"; - - if (mode === "svg" && content in NAMED_COLORS) { - content = NAMED_COLORS[content]; - } - - if (!isValidColor(content)) { - if (isValidColor(multiLinePrev)) { - content = multiLinePrev; - } else if (isValidColor(multiLineNext)) { - content = multiLineNext; - } else { - return; - } - } - - try { - const fontColorString = - Color(content).luminance > 0.5 ? "#000" : "#fff"; - el.classList.add("ace_color"); - el.style.cssText = `background-color: ${content}; color: ${fontColorString}; pointer-events: all;`; - } catch (error) { - window.log("error", `Invalid color: ${content}`); - window.log("error", error); - } - }); -} - -function forceTokenizer() { - const { session } = editor; - // force recreation of tokenizer - session.$mode.$tokenizer = null; - session.bgTokenizer.setTokenizer(session.$mode.getTokenizer()); - // force re-highlight whole document - session.bgTokenizer.start(0); -} diff --git a/src/ace/commands.js b/src/ace/commands.js deleted file mode 100644 index 2a108159b..000000000 --- a/src/ace/commands.js +++ /dev/null @@ -1,442 +0,0 @@ -import fsOperation from "fileSystem"; -import prompt from "dialogs/prompt"; -import actions from "handlers/quickTools"; -import keyBindings from "lib/keyBindings"; -import settings from "lib/settings"; -import Url from "utils/Url"; - -const commands = [ - { - name: "focusEditor", - description: "Focus editor", - exec() { - editorManager.editor.focus(); - }, - }, - { - name: "findFile", - description: "Find file in workspace", - exec() { - acode.exec("find-file"); - }, - }, - { - name: "closeCurrentTab", - description: "Close current tab", - exec() { - acode.exec("close-current-tab"); - }, - }, - { - name: "closeAllTabs", - description: "Close all tabs", - exec() { - acode.exec("close-all-tabs"); - }, - }, - { - name: "newFile", - description: "Create new file", - exec() { - acode.exec("new-file"); - }, - readOnly: true, - }, - { - name: "openFile", - description: "Open a file", - exec() { - acode.exec("open-file"); - }, - readOnly: true, - }, - { - name: "openFolder", - description: "Open a folder", - exec() { - acode.exec("open-folder"); - }, - readOnly: true, - }, - { - name: "saveFile", - description: "Save current file", - exec() { - acode.exec("save"); - }, - readOnly: true, - }, - { - name: "saveFileAs", - description: "Save as current file", - exec() { - acode.exec("save-as"); - }, - readOnly: true, - }, - { - name: "saveAllChanges", - description: "Save all changes", - exec() { - acode.exec("save-all-changes"); - }, - readOnly: true, - }, - { - name: "nextFile", - description: "Open next file tab", - exec() { - acode.exec("next-file"); - }, - }, - { - name: "prevFile", - description: "Open previous file tab", - exec() { - acode.exec("prev-file"); - }, - }, - { - name: "showSettingsMenu", - description: "Show settings menu", - exec() { - acode.exec("open", "settings"); - }, - readOnly: true, - }, - { - name: "renameFile", - description: "Rename active file", - exec() { - acode.exec("rename"); - }, - readOnly: true, - }, - { - name: "run", - description: "Preview HTML and MarkDown", - exec() { - acode.exec("run"); - }, - readOnly: true, - }, - { - name: "openInAppBrowser", - description: "Open In-App Browser", - async exec() { - const url = await prompt("Enter url", "", "url", { - placeholder: "http://", - match: /^https?:\/\/.+/, - }); - if (url) { - acode.exec("open-inapp-browser", url); - } - }, - }, - { - name: "toggleFullscreen", - description: "Toggle full screen mode", - exec() { - acode.exec("toggle-fullscreen"); - }, - }, - { - name: "toggleSidebar", - description: "Toggle sidebar", - exec() { - acode.exec("toggle-sidebar"); - }, - }, - { - name: "toggleMenu", - description: "Toggle main menu", - exec() { - acode.exec("toggle-menu"); - }, - }, - { - name: "toggleEditMenu", - description: "Toggle edit menu", - exec() { - acode.exec("toggle-editmenu"); - }, - }, - { - name: "selectall", - description: "Select all", - exec(editor) { - editor.selectAll(); - }, - readOnly: true, - }, - { - name: "gotoline", - description: "Go to line...", - exec() { - acode.exec("goto"); - }, - readOnly: true, - }, - { - name: "find", - description: "Find", - exec() { - acode.exec("find"); - }, - readOnly: true, - }, - { - name: "copy", - description: "Copy", - exec(editor) { - const { clipboard } = cordova.plugins; - const copyText = editor.getCopyText(); - clipboard.copy(copyText); - toast(strings["copied to clipboard"]); - }, - readOnly: true, - }, - { - name: "cut", - description: "Cut", - exec(editor) { - let cutLine = - editor.$copyWithEmptySelection && editor.selection.isEmpty(); - let range = cutLine - ? editor.selection.getLineRange() - : editor.selection.getRange(); - editor._emit("cut", range); - if (!range.isEmpty()) { - const { clipboard } = cordova.plugins; - const copyText = editor.session.getTextRange(range); - clipboard.copy(copyText); - toast(strings["copied to clipboard"]); - editor.session.remove(range); - } - editor.clearSelection(); - }, - scrollIntoView: "cursor", - multiSelectAction: "forEach", - }, - { - name: "paste", - description: "Paste", - exec() { - const { clipboard } = cordova.plugins; - clipboard.paste((text) => { - editorManager.editor.$handlePaste(text); - }); - }, - scrollIntoView: "cursor", - }, - { - name: "problems", - description: "Show errors and warnings", - exec() { - acode.exec("open", "problems"); - }, - }, - { - name: "replace", - description: "Replace", - exec() { - acode.exec("replace"); - }, - }, - { - name: "openCommandPalette", - description: "Open command palette", - exec() { - acode.exec("command-palette"); - }, - readOnly: true, - }, - { - name: "modeSelect", - description: "Change language mode...", - exec() { - acode.exec("syntax"); - }, - readOnly: true, - }, - { - name: "toggleQuickTools", - description: "Toggle quick tools", - exec() { - actions("toggle"); - }, - }, - { - name: "selectWord", - description: "Select current word", - exec(editor) { - editor.selection.selectAWord(); - editor._emit("select-word"); - }, - }, - { - name: "openLogFile", - description: "Open Log File", - exec() { - acode.exec("open-log-file"); - }, - }, - { - name: "increaseFontSize", - description: "Increase font size", - exec(editor) { - let size = Number.parseInt(editor.getFontSize(), 10) || 12; - editor.setFontSize(size + 1); - settings.value.fontSize = size + 1 + "px"; - settings.update(false); - }, - }, - { - name: "decreaseFontSize", - description: "Decrease font size", - exec(editor) { - let size = Number.parseInt(editor.getFontSize(), 10) || 12; - editor.setFontSize(Math.max(size - 1 || 1)); - settings.value.fontSize = Math.max(size - 1 || 1) + "px"; - settings.update(false); - }, - }, - { - name: "openPluginsPage", - description: "Open Plugins Page", - exec() { - acode.exec("open", "plugins"); - }, - readOnly: true, - }, - { - name: "openFileExplorer", - description: "File Explorer", - exec() { - acode.exec("open", "file_browser"); - }, - readOnly: true, - }, - { - name: "copyDeviceInfo", - description: "Copy Device info", - exec() { - acode.exec("copy-device-info"); - }, - readOnly: true, - }, - { - name: "changeAppTheme", - description: "Change App Theme", - exec() { - acode.exec("change-app-theme"); - }, - readOnly: true, - }, - { - name: "changeEditorTheme", - description: "Change Editor Theme", - exec() { - acode.exec("change-editor-theme"); - }, - readOnly: true, - }, - { - name: "openTerminal", - description: "Open Terminal", - exec() { - acode.exec("new-terminal"); - }, - readOnly: true, - }, - { - name: "acode:showWelcome", - description: "Show Welcome", - exec() { - acode.exec("welcome"); - }, - readOnly: true, - }, - { - name: "run-tests", - description: "Run Tests", - exec() { - acode.exec("run-tests"); - }, - readOnly: true, - }, - { - name: "dev:toggleDevTools", - description: "Toggle Developer Tools", - exec() { - acode.exec("toggle-inspector"); - }, - readOnly: true, - }, - { - name: "dev:openInspector", - description: "Open Inspector", - exec() { - acode.exec("open-inspector"); - }, - readOnly: true, - }, -]; - -export function setCommands(editor) { - commands.forEach((command) => { - editor.commands.addCommand(command); - }); -} - -/** - * Sets key bindings for the editor - * @param {AceAjax.Editor} editor Ace editor - */ -export async function setKeyBindings({ commands }) { - let keyboardShortcuts = keyBindings; - try { - const bindingsFile = fsOperation(KEYBINDING_FILE); - if (await bindingsFile.exists()) { - const bindings = await bindingsFile.readFile("json"); - // keyboardShortcuts = compareAndFixKeyBindings(keyboardShortcuts, bindings); - keyboardShortcuts = bindings; - } else { - throw new Error("Key binding file not found"); - } - } catch (error) { - await resetKeyBindings(); - } - - Object.keys(commands.byName).forEach((name) => { - const shortcut = keyboardShortcuts[name]; - const command = commands.byName[name]; - - if (shortcut?.description) { - command.description = shortcut.description; - } - - // not chekiang if shortcut is empty because it can be used to remove shortcut - command.bindKey = { win: shortcut?.key ?? null }; - commands.addCommand(command); - }); -} - -/** - * Resets key binding - */ -export async function resetKeyBindings() { - try { - const fs = fsOperation(KEYBINDING_FILE); - const fileName = Url.basename(KEYBINDING_FILE); - const content = JSON.stringify(keyBindings, undefined, 2); - if (!(await fs.exists())) { - await fsOperation(DATA_STORAGE).createFile(fileName, content); - return; - } - await fs.writeFile(content); - } catch (error) { - window.log("error", "Reset Keybinding failed!"); - window.log("error", error); - } -} diff --git a/src/ace/modelist.js b/src/ace/modelist.js deleted file mode 100644 index 0840e7108..000000000 --- a/src/ace/modelist.js +++ /dev/null @@ -1,130 +0,0 @@ -const modesByName = {}; -const modes = []; - -export function initModes() { - ace.define( - "ace/ext/modelist", - ["require", "exports", "module"], - function (require, exports, module) { - /** - * Calculates a specificity score for a mode. - * Higher score means more specific. - * - Anchored patterns (e.g., "^Dockerfile") get a base score of 1000. - * - Non-anchored patterns (extensions) are scored by length. - */ - function getModeSpecificityScore(modeInstance) { - const extensionsStr = modeInstance.extensions; - if (!extensionsStr) return 0; - - const patterns = extensionsStr.split("|"); - let maxScore = 0; - - for (const pattern of patterns) { - let currentScore = 0; - if (pattern.startsWith("^")) { - // Exact filename match or anchored pattern - currentScore = 1000 + (pattern.length - 1); // Subtract 1 for '^' - } else { - // Extension match - currentScore = pattern.length; - } - if (currentScore > maxScore) { - maxScore = currentScore; - } - } - return maxScore; - } - module.exports = { - getModeForPath(path) { - let mode = modesByName.text; - let fileName = path.split(/[\/\\]/).pop(); - // Sort modes by specificity (descending) to check most specific first - const sortedModes = [...modes].sort((a, b) => { - return getModeSpecificityScore(b) - getModeSpecificityScore(a); - }); - - for (const iMode of sortedModes) { - if (iMode.supportsFile?.(fileName)) { - mode = iMode; - break; - } - } - return mode; - }, - get modesByName() { - return modesByName; - }, - get modes() { - return modes; - }, - }; - }, - ); -} - -/** - * Add language mode to ace editor - * @param {string} name name of the mode - * @param {string|Array} extensions extensions of the mode - * @param {string} [caption] display name of the mode - */ -export function addMode(name, extensions, caption) { - const filename = name.toLowerCase(); - const mode = new Mode(filename, caption, extensions); - modesByName[filename] = mode; - modes.push(mode); -} - -/** - * Remove language mode from ace editor - * @param {string} name - */ -export function removeMode(name) { - const filename = name.toLowerCase(); - delete modesByName[filename]; - const modeIndex = modes.findIndex((mode) => mode.name === filename); - if (modeIndex >= 0) { - modes.splice(modeIndex, 1); - } -} - -class Mode { - extensions; - displayName; - name; - mode; - extRe; - - /** - * Create a new mode - * @param {string} name - * @param {string} caption - * @param {string|Array} extensions - */ - constructor(name, caption, extensions) { - if (Array.isArray(extensions)) { - extensions = extensions.join("|"); - } - - this.name = name; - this.mode = "ace/mode/" + name; - this.extensions = extensions; - this.caption = caption || this.name.replace(/_/g, " "); - let re; - - if (/\^/.test(extensions)) { - re = - extensions.replace(/\|(\^)?/g, function (a, b) { - return "$|" + (b ? "^" : "^.*\\."); - }) + "$"; - } else { - re = "^.*\\.(" + extensions + ")$"; - } - - this.extRe = new RegExp(re, "i"); - } - - supportsFile(filename) { - return this.extRe.test(filename); - } -} diff --git a/src/ace/supportedModes.js b/src/ace/supportedModes.js deleted file mode 100644 index e0134a1d8..000000000 --- a/src/ace/supportedModes.js +++ /dev/null @@ -1,220 +0,0 @@ -import { addMode } from "./modelist"; - -const modeList = { - ABAP: "abap", - ABC: "abc", - ActionScript: "as", - ADA: "ada|adb", - Alda: "alda", - Apache_Conf: "^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd", - Apex: "apex|cls|trigger|tgr", - AQL: "aql", - AsciiDoc: "asciidoc|adoc", - ASL: "dsl|asl|asl.json", - Assembly_x86: "asm|a", - Assembly_arm32: "s", - Astro: "astro", - AutoHotKey: "ahk", - Basic: "bas", - BatchFile: "bat|cmd", - BibTeX: "bib", - C_Cpp: "cpp|c|cc|cxx|h|hh|hpp|ino", - C9Search: "c9search_results", - Cirru: "cirru|cr", - Clojure: "clj|cljs", - Clue: "clue", - Cobol: "CBL|COB", - coffee: "coffee|cf|cson|^Cakefile", - ColdFusion: "cfm|cfc", - Crystal: "cr", - CSharp: "cs", - Csound_Document: "csd", - Csound_Orchestra: "orc", - Csound_Score: "sco", - CSS: "css", - CSV: "csv", - Curly: "curly", - Cuttlefish: "conf", - D: "d|di", - Dart: "dart", - Diff: "diff|patch", - Dockerfile: "^Dockerfile", - Dot: "dot", - Drools: "drl", - Edifact: "edi", - Eiffel: "e|ge", - EJS: "ejs", - Elixir: "ex|exs", - Elm: "elm", - Erlang: "erl|hrl", - Forth: "frt|fs|ldr|fth|4th", - Fortran: "f|f90", - FSharp: "fsi|fs|ml|mli|fsx|fsscript", - FSL: "fsl", - FTL: "ftl", - Flix: "flix", - Gcode: "gcode", - Gherkin: "feature", - Gitignore: "^.gitignore", - Glsl: "glsl|frag|vert", - Gobstones: "gbs", - golang: "go", - GraphQLSchema: "gql", - Groovy: "groovy", - HAML: "haml", - Handlebars: "hbs|handlebars|tpl|mustache", - Haskell: "hs", - Haskell_Cabal: "cabal", - haXe: "hx", - Hjson: "hjson", - HTML: "html|htm|xhtml|we|wpy", - HTML_Elixir: "eex|html.eex", - HTML_Ruby: "erb|rhtml|html.erb", - INI: "ini|conf|cfg|prefs", - Io: "io", - Ion: "ion", - Jack: "jack", - Jade: "jade|pug", - Java: "java", - JavaScript: "js|jsm|jsx|cjs|mjs", - JEXL: "jexl", - JSON: "json", - JSON5: "json5", - JSONiq: "jq", - JSP: "jsp", - JSSM: "jssm|jssm_state", - JSX: "jsx", - Julia: "jl", - Kotlin: "kt|kts", - LaTeX: "tex|latex|ltx|bib", - Latte: "latte", - LESS: "less", - Liquid: "liquid", - Lisp: "lisp", - LiveScript: "ls", - Log: "log", - LogiQL: "logic|lql", - Logtalk: "lgt", - LSL: "lsl", - Lua: "lua", - LuaPage: "lp", - Lucene: "lucene", - Makefile: "^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make", - Markdown: "md|markdown", - Mask: "mask", - MATLAB: "matlab", - Maze: "mz", - MediaWiki: "wiki|mediawiki", - MEL: "mel", - MIPS: "s|asm", - MIXAL: "mixal", - MUSHCode: "mc|mush", - MySQL: "mysql", - Nasal: "nas", - Nginx: "nginx|conf", - Nim: "nim", - Nix: "nix", - NSIS: "nsi|nsh", - Nunjucks: "nunjucks|nunjs|nj|njk", - ObjectiveC: "m|mm", - OCaml: "ml|mli", - Odin: "odin", - PartiQL: "partiql|pql", - Pascal: "pas|p", - Perl: "pl|pm", - pgSQL: "pgsql", - PHP: "php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module", - PHP_Laravel_blade: "blade.php", - Pig: "pig", - PLSQL: "plsql", - Powershell: "ps1", - Praat: "praat|praatscript|psc|proc", - Prisma: "prisma", - Prolog: "plg|prolog", - Properties: "properties", - Protobuf: "proto", - Puppet: "epp|pp", - Python: "py", - PRQL: "prql", - QML: "qml", - R: "r", - Raku: "raku|rakumod|rakutest|p6|pl6|pm6", - Razor: "cshtml|asp", - RDoc: "Rd", - Red: "red|reds", - RHTML: "Rhtml", - Robot: "robot|resource", - RST: "rst", - Ruby: "rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile", - Rust: "rs", - SaC: "sac", - SASS: "sass", - SCAD: "scad", - Scala: "scala|sbt", - Scheme: "scm|sm|rkt|oak|scheme", - Scrypt: "scrypt", - SCSS: "scss", - SH: "sh|bash|^.bashrc", - SJS: "sjs", - Slim: "slim|skim", - Smarty: "smarty|tpl", - Smithy: "smithy", - snippets: "snippets", - Soy_Template: "soy", - Space: "space", - SPARQL: "rq", - SQL: "sql", - SQLServer: "sqlserver", - Stylus: "styl|stylus", - SVG: "svg", - Swift: "swift", - Tcl: "tcl", - Terraform: "tf|tfvars|terragrunt", - Tex: "tex", - Text: "txt", - Textile: "textile", - Toml: "toml", - TSV: "TSV", - TSX: "tsx", - Turtle: "ttl", - Twig: "twig|swig", - Typescript: "ts|typescript|str", - Vala: "vala", - VBScript: "vbs|vb", - Velocity: "vm", - Verilog: "v|vh|sv|svh", - VHDL: "vhd|vhdl", - Visualforce: "vfp|component|page", - Vue: "vue", - Wollok: "wlk|wpgm|wtest", - XML: "xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml", - XQuery: "xq", - YAML: "yaml|yml", - Zeek: "zeek|bro", - Zig: "zig", - Django: "html", -}; - -const languageNames = { - ObjectiveC: "Objective-C", - CSharp: "C#", - golang: "Go", - C_Cpp: "C/C++", - Csound_Document: "Csound Document", - Csound_Orchestra: "Csound", - Csound_Score: "Csound Score", - coffee: "CoffeeScript", - HTML_Ruby: "HTML (Ruby)", - HTML_Elixir: "HTML (Elixir)", - FTL: "FreeMarker", - PHP_Laravel_blade: "PHP (Blade Template)", - Perl6: "Perl 6", - AutoHotKey: "AutoHotkey/AutoIt", -}; - -Object.keys(modeList).forEach((key) => { - const extensions = modeList[key]; - const caption = languageNames[key]; - - addMode(key, extensions, caption); -}); diff --git a/src/ace/touchHandler.js b/src/ace/touchHandler.js deleted file mode 100644 index 23d29a695..000000000 --- a/src/ace/touchHandler.js +++ /dev/null @@ -1,1085 +0,0 @@ -import { key } from "handlers/quickTools"; -import tag from "html-tag-js"; -import constants from "lib/constants"; -import selectionMenu from "lib/selectionMenu"; -import appSettings from "lib/settings"; -import { getColorRange } from "utils/color/regex"; - -export let scrollAnimationFrame; // scroll animation frame id - -const SCROLL_SPEED = { - FAST_X2: 0.99, - FAST: 0.97, - NORMAL: 0.95, - SLOW: 0.9, -}; - -/** - * Handler for touch events - * @param {AceAjax.Editor} editor Ace editor instance - * @param {boolean} minimal if true, disable selection, menu and cursor - */ -export default function addTouchListeners(editor, minimal, onclick) { - const { renderer, container: $el } = editor; - const { $gutter } = renderer; - const { Range } = ace.require("ace/range"); - - let { - diagonalScrolling, - reverseScrolling, - teardropSize, - teardropTimeout, - scrollSpeed, - } = appSettings.value; - - if (minimal) { - diagonalScrolling = false; - reverseScrolling = false; - teardropSize = 0; - } - - /** - * Selection controller start - */ - const $start = tag("span", { - className: "cursor start", - dataset: { - size: teardropSize, - }, - size: teardropSize, - }); - - /** - * Selection controller end - */ - const $end = tag("span", { - className: "cursor end", - dataset: { - size: teardropSize, - }, - size: teardropSize, - }); - - /** - * Tear drop cursor - */ - const $cursor = tag("span", { - className: "cursor single", - dataset: { - size: teardropSize, - }, - get size() { - const widthSq = teardropSize * teardropSize * 2; - const actualWidth = Math.sqrt(widthSq); - delete this.size; - this.size = actualWidth; - return actualWidth; - }, - startHide() { - clearTimeout($cursor.dataset.timeout); - $cursor.dataset.timeout = setTimeout(() => { - $cursor.remove(); - hideMenu(); - }, teardropTimeout); - }, - }); - - /** - * Text menu for touch devices - */ - const $menu =

; - const RESET_CLICK_COUNT_TIME = 500; // ms - const config = { passive: false }; // event listener config - const ACE_NO_CURSOR = - ".ace_gutter,.ace_gutter *,.ace_fold,.ace_inline_button"; - - let LOCK_X = appSettings.value.textWrap; - - let scrollTimeout; // timeout to check if scrolling is finished - let menuActive; // true if menu is active - let mode; // cursor, selection or scroll - let moveY; // touch difference in vertical direction - let moveX; // touch difference in horizontal direction - let lastX; // last x - let lastY; // last y - let directionX; // direction in x - let directionY; // direction in y - let initialX; // initial x - let initialY; // initial y - let initialTimeX; // initial time - let initialTimeY; // initial time - let lockX; // lock x for prevent scrolling in horizontal direction - let lockY; // lock y for prevent scrolling in vertical direction - let clickCount = 0; // number of clicks - let selectionActive; // true if selection is active - let lastClickPos = null; - let teardropDoesShowMenu = true; // teardrop handler - let teardropTouchEnded = false; // teardrop handler - let teardropMoveTimeout; // teardrop handler - let forceCursorMode = false; // force to show cursor - let $activeTeardrop; // active teardrop - let timeTouchStart; // time of touch start - let touchEnded = true; // true if touch ended - let threshold = appSettings.value.touchMoveThreshold; - - $el.addEventListener("touchstart", touchStart, config, true); - $el.addEventListener("contextmenu", contextmenu, config, true); - - editor.setSelection = (value) => { - selectionActive = value; - }; - - editor.setMenu = (value) => { - menuActive = value; - }; - - if (!minimal) { - editor.on("change", onupdate); - editor.on("changeSession", onchangesession); - editor.on("scroll", onscroll); - editor.on("fold", onfold); - editor.on("select-word", () => { - selectionMode($end); - }); - editor.on("scroll-intoview", () => { - if (selectionActive) { - selectionMode($end); - } else { - cursorMode(); - } - }); - - appSettings.on("update:diagonalScrolling", (value) => { - diagonalScrolling = value; - }); - appSettings.on("update:reverseScrolling", (value) => { - reverseScrolling = value; - }); - appSettings.on("update:teardropSize", (value) => { - teardropSize = value; - $start.dataset.size = value; - $end.dataset.size = value; - $cursor.dataset.size = value; - }); - appSettings.on("update:textWrap", (value) => { - LOCK_X = value; - onupdate(); - }); - appSettings.on("update:scrollSpeed", (value) => { - scrollSpeed = value; - }); - appSettings.on("update:touchMoveThreshold", (value) => { - threshold = value; - }); - } - - /** - * Editor container on touch start - * @param {TouchEvent} e Touch event - */ - function touchStart(e) { - /**@type {HTMLElement} */ - const $target = e.target; - - editor.textInput.onContextMenu = null; - cancelAnimationFrame(scrollAnimationFrame); - const { clientX, clientY } = e.touches[0]; - - if (minimal && clientX <= constants.SIDEBAR_SLIDE_START_THRESHOLD_PX) { - return; - } - - if (isIn($start, clientX, clientY)) { - e.preventDefault(); - teardropHandler($start); - return; - } - - if (isIn($end, clientX, clientY)) { - e.preventDefault(); - teardropHandler($end); - return; - } - - if (isIn($cursor, clientX, clientY)) { - e.preventDefault(); - teardropHandler($cursor); - return; - } - - if ($target.matches(ACE_NO_CURSOR)) { - moveCursorTo(0, clientY); - return; - } - - touchEnded = false; - lastX = clientX; - lastY = clientY; - initialX = clientX; - initialY = clientY; - initialTimeX = e.timeStamp; - initialTimeY = e.timeStamp; - moveY = 0; - moveX = 0; - lockX = LOCK_X; - lockY = false; - mode = "wait"; - - setTimeout(() => { - clickCount = 0; - lastClickPos = null; - }, RESET_CLICK_COUNT_TIME); - - document.addEventListener("touchmove", touchMove, config); - document.addEventListener("touchend", touchEnd, config); - } - - /** - * Editor container on touch move - * @param {TouchEvent} e Event - */ - function touchMove(e) { - if (mode === "selection") { - removeListeners(); - return; - } - - let currentDirectionX; // direction in x - let currentDirectionY; // direction in y - const { clientX, clientY } = e.touches[0]; - - moveX = clientX - lastX; - moveY = clientY - lastY; - currentDirectionX = moveX > 0 ? 1 : -1; - currentDirectionY = moveY > 0 ? 1 : -1; - - if (directionX !== currentDirectionX) { - initialX = clientX; - initialTimeX = e.timeStamp; - } - - if (directionY !== currentDirectionY) { - initialY = clientY; - initialTimeY = e.timeStamp; - } - - directionX = currentDirectionX; - directionY = currentDirectionY; - lastX = clientX; - lastY = clientY; - - if (!moveX && !moveY) { - return; - } - - if (!diagonalScrolling && !lockX && !lockY) { - if (Math.abs(moveX) > Math.abs(moveY)) { - lockY = true; - } else { - lockX = true; - } - } - - if (lockX || Math.abs(moveX) < threshold) { - moveX = 0; - } - - if (lockY || Math.abs(moveY) < threshold) { - moveY = 0; - } - - if (moveX || moveY) { - e.preventDefault(); - [moveX, moveY] = testScroll(moveX, moveY); - mode = "scroll"; - scroll(moveX, moveY); - } - } - - /** - * Editor container on touch end - * @param {TouchEvent} e Event - */ - function touchEnd(e) { - const { clientX, clientY } = e.changedTouches[0]; - // why I was using e.preventDefault() ? 🤔 - // because select word and select line misbehave without - // preventDefault - removeListeners(); - touchEnded = true; - - if (mode === "scroll") { - const deltaTimeX = e.timeStamp - initialTimeX; - const deltaTimeY = e.timeStamp - initialTimeY; - const deltaX = clientX - initialX; - const deltaY = clientY - initialY; - const velocityX = lockX ? 0 : Math.round(deltaX / deltaTimeX); // in px/ms - const velocityY = lockY ? 0 : Math.round(deltaY / deltaTimeY); // in px/ms - scrollAnimation(velocityX, velocityY); - return; - } - - if (mode === "wait") { - if (lastClickPos) { - const { clientX: clickXThen, clientY: clickYThen } = lastClickPos; - const { row: rowNow, column: columnNow } = - renderer.screenToTextCoordinates(clientX, clientY); - const { row: rowThen, column: columnThen } = - renderer.screenToTextCoordinates(clickXThen, clickYThen); - - const rowDiff = Math.abs(rowNow - rowThen); - const columnDiff = Math.abs(columnNow - columnThen); - if (!rowDiff && columnDiff <= 2) { - clickCount += 1; - } - } else { - clickCount = 1; - } - - lastClickPos = { clientX, clientY }; - - if (clickCount === 2) { - mode = "selection"; - } else if (clickCount >= 3) { - mode = "select-line"; - } else { - mode = "cursor"; - } - } - - if (minimal && mode === "cursor") { - moveCursorTo(clientX, clientY); - if (onclick) onclick(); - return; - } else if (minimal) { - return; - } - - if (mode === "cursor") { - e.preventDefault(); - const shiftKey = key.shift || e.shiftKey; - const ctrlKey = key.ctrl || e.ctrlKey; - moveCursorTo(clientX, clientY, shiftKey, ctrlKey); - if (!ctrlKey && !shiftKey) { - forceCursorMode = true; - cursorMode(); - } - if (!editor.isFocused()) editor.focus(); - return; - } - - if (mode === "selection") { - e.preventDefault(); - moveCursorTo(clientX, clientY); - select(); - vibrate(); - return; - } - - if (mode === "select-line") { - e.preventDefault(); - moveCursorTo(clientX, clientY); - editor.selection.selectLine(); - selectionMode($end); - vibrate(); - } - } - - /** - * Checks if given element is in the touch area - * @param {Element} $el - * @param {number} cX - * @param {number} cY - * @returns - */ - function isIn($el, cX, cY) { - const { - x, - y, - left, - top, - width: sWidth, - height: sHeight, - } = $el.getBoundingClientRect(); - - const sx = x || left; - const sy = y || top; - - return cX > sx && cX < sx + sWidth && cY > sy && cY < sy + sHeight; - } - - /** - * Vibrate device - * @returns {void} - */ - function vibrate() { - if (appSettings.value.vibrateOnTap) { - navigator.vibrate(constants.VIBRATION_TIME); - } - } - - /** - * Callback for contextmenu event - * @param {MouseEvent} e Event - */ - function contextmenu(e) { - e.preventDefault(); - e.stopPropagation(); - if (minimal) return; - const { clientX, clientY } = e; - moveCursorTo(clientX, clientY); - select(); - touchEnded = true; - editor.focus(); - } - - /** - * Select word at cursor position - * @returns {void} - */ - function select() { - removeListeners(); - const range = getColorRange() || editor.selection.getWordRange(); - if (!range || range?.isEmpty()) return; - editor.selection.setSelectionRange(range); - selectionMode($end); - } - - /** - * Scrolls the editor with smooth animation - * @param {number} velocityX velocity in x direction - * @param {number} velocityY velocity in y direction - * @param {number} [timeThen] - * @returns {void} - */ - function scrollAnimation(velocityX, velocityY, timeThen = 0) { - if (!velocityX && !velocityY) { - onscrollend(); - return; - } - - const timeNow = Date.now(); - - if (!timeThen) { - scrollAnimationFrame = requestAnimationFrame( - scrollAnimation.bind(null, velocityX, velocityY, timeNow), - ); - return; - } - - const timeElapsed = timeNow - timeThen; - const FRICTION = SCROLL_SPEED[scrollSpeed]; - const nextX = velocityX * timeElapsed; - const nextY = velocityY * timeElapsed; - - let scrollX = Number.parseInt(nextX * 100) / 100; - let scrollY = Number.parseInt(nextY * 100) / 100; - - const [canScrollX, canScrollY] = testScroll(scrollX, scrollY); - - if (!canScrollX) { - velocityX = 0; - scrollX = 0; - } - - if (!canScrollY) { - velocityY = 0; - scrollY = 0; - } - - if (!scrollX && !scrollY) { - cancelAnimationFrame(scrollAnimationFrame); - return; - } - - scroll(scrollX, scrollY); - - velocityX *= FRICTION; - velocityY *= FRICTION; - - scrollAnimationFrame = requestAnimationFrame( - scrollAnimation.bind(null, velocityX, velocityY, timeNow), - ); - } - - /** - * Test if scrolling is possible - * @param {number} moveX move in x direction - * @param {number} moveY move in y direction - * @returns {[number, number]} - */ - function testScroll(moveX, moveY) { - const UP = reverseScrolling ? "down" : "up"; - const DOWN = reverseScrolling ? "up" : "down"; - const LEFT = reverseScrolling ? "right" : "left"; - const RIGHT = reverseScrolling ? "left" : "right"; - - const vDirection = moveY > 0 ? DOWN : UP; - const hDirection = moveX > 0 ? RIGHT : LEFT; - - const { getEditorHeight, getEditorWidth } = editorManager; - const scrollLeft = editor.renderer.getScrollLeft(); - const scrollTop = editor.renderer.getScrollTop(); - const [editorWidth, editorHeight] = [ - getEditorWidth(editor), - getEditorHeight(editor), - ]; - - if ( - (vDirection === "down" && scrollTop <= 0) || - (vDirection === "up" && scrollTop >= editorHeight) - ) { - moveY = 0; - } - - if ( - (hDirection === "right" && scrollLeft <= 0) || - (hDirection === "left" && scrollLeft >= editorWidth) - ) { - moveX = 0; - } - - return [moveX, moveY]; - } - - /** - * Scroll to given position - * @param {number} x - * @param {number} y - */ - function scroll(x, y) { - let direction = reverseScrolling ? 1 : -1; - let scrollX = direction * x; - let scrollY = direction * y; - - renderer.scrollBy(scrollX, scrollY); - } - - /** - * Remove all listeners - */ - function removeListeners() { - document.removeEventListener("touchmove", touchMove, config); - document.removeEventListener("touchend", touchEnd, config); - } - - /** - * Compare two ranges - * @param {AceAjax.Range} r1 - * @param {AceAjax.Range} r2 - * @returns {boolean} - */ - function compareRanges(r1, r2) { - return ( - r1.start.row === r2.start.row && - r1.start.column === r2.start.column && - r1.end.row === r2.end.row && - r1.end.column === r2.end.column - ); - } - - /** - * Moves cursor to given position - * @param {number} x - * @param {number} y - * @param {boolean} [shiftKey] - * @param {boolean} [ctrlKey] - */ - function moveCursorTo(x, y, shiftKey = false, ctrlKey = false) { - const pos = renderer.screenToTextCoordinates(x, y); - - hideTooltip(); - - if (shiftKey) { - const anchor = - editor.selection.getSelectionAnchor() || editor.getCursorPosition(); - editor.selection.setRange({ start: anchor, end: pos }); - selectionMode($end); - return; - } - - if (ctrlKey) { - const range = new Range(pos.row, pos.column, pos.row, pos.column); - const ranges = editor.selection.getAllRanges(); - const exists = ranges.some((r) => compareRanges(r, range)); - if (exists) { - editor.selection.clearSelection(); - ranges.splice(ranges.indexOf(exists), 1); - ranges.forEach((r) => editor.selection.addRange(r)); - return; - } - - editor.selection.addRange(range); - return; - } - - editor.selection.moveToPosition(pos); - } - - /** - * Shows teardrop - * @returns {void} - */ - function cursorMode() { - if ((!teardropSize || !editor.isFocused()) && !forceCursorMode) { - $cursor.remove(); - return; - } - - forceCursorMode = false; - clearTimeout($cursor.dataset.timeout); - clearSelectionMode(); - - const { pageX, pageY } = renderer.textToScreenCoordinates( - editor.getCursorPosition(), - ); - const { lineHeight } = renderer; - const actualHeight = lineHeight; - const [x, y] = relativePosition(pageX, pageY + actualHeight); - $cursor.style.left = `${x}px`; - $cursor.style.top = `${y}px`; - if (!$cursor.isConnected) $el.append($cursor); - $cursor.startHide(); - - editor.selection.on("changeCursor", clearCursorMode); - } - - /** - * Remove cursor mode - * @returns {void} - */ - function clearCursorMode() { - if (!$el.contains($cursor)) return; - if ($cursor.dataset.immortal === "true") return; - $cursor.remove(); - clearTimeout($cursor.dataset.timeout); - - editor.selection.off("changeCursor", clearCursorMode); - } - - /** - * Shows both teardrops - * @param {HTMLElement} $trigger - * @returns {void} - */ - function selectionMode($trigger) { - if (!teardropSize) return; - - clearCursorMode(); - selectionActive = true; - positionEnd(); - positionStart(); - if ($trigger) showMenu($trigger); - - setTimeout(() => { - editor.selection.on("changeSelection", clearSelectionMode); - editor.selection.on("changeCursor", clearSelectionMode); - }, 0); - } - - /** - * Positions the start teardrop - */ - function positionStart() { - const range = editor.getSelectionRange(); - const { pageX, pageY } = renderer.textToScreenCoordinates(range.start); - const { lineHeight } = renderer; - - // Calculate desired position but ensure it stays within viewport - let targetX = pageX - teardropSize; - const [relativeX, y] = relativePosition(targetX, pageY + lineHeight); - - // Ensure the teardrop doesn't go outside the left edge - // Leave some padding (e.g., 4px) so it's not flush against the edge - const minX = 4; - const constrainedX = Math.max(relativeX, minX); - - $start.style.left = `${constrainedX}px`; - $start.style.top = `${y}px`; - - if (!$start.isConnected) $el.append($start); - } - - /** - * Positions the end teardrop - */ - function positionEnd() { - const range = editor.getSelectionRange(); - const { pageX, pageY } = renderer.textToScreenCoordinates(range.end); - const { lineHeight } = renderer; - const [x, y] = relativePosition(pageX, pageY + lineHeight); - - $end.style.left = `${x}px`; - $end.style.top = `${y}px`; - - if (!$end.isConnected) $el.append($end); - } - - /** - * Remove selection mode - * @param {Event} e Event - * @param {boolean} clearActive whether to clear selectionActive - * @returns {void} - */ - function clearSelectionMode(e, clearActive = true) { - const $els = [$start.dataset.immortal, $end.dataset.immortal]; - if ($els.includes("true")) return; - if ($el.contains($start)) $start.remove(); - if ($el.contains($end)) $end.remove(); - if (clearActive) { - selectionActive = false; - } - - editor.selection.off("changeSelection", clearSelectionMode); - editor.selection.off("changeCursor", clearSelectionMode); - } - - /** - * Shows the edit context menu - * @param {HTMLElement} [$trigger] A trigger element that triggered the menu, if not provided, menu will be shown at the current cursor position - */ - function showMenu($trigger) { - menuActive = true; - const rect = $trigger?.getBoundingClientRect(); - const { bottom, left } = rect; - const readOnly = editor.getReadOnly(); - const [x, y] = relativePosition(left, bottom); - if (readOnly) { - populateMenuItems("read-only"); - } else { - populateMenuItems(); - } - - $menu.style.left = `${x}px`; - $menu.style.top = `${y}px`; - - if (!$menu.isConnected) $el.parentElement.append($menu); - if ($trigger) positionMenu($trigger); - - editor.selection.on("changeCursor", hideMenu); - editor.selection.on("changeSelection", hideMenu); - } - - /** - * @param {boolean} clearActive whether to clear menuActive - * @returns {void} - */ - function hideMenu(clearActive = true) { - if (!$el.parentElement.contains($menu)) return; - $menu.remove(); - editor.selection.off("changeCursor", hideMenu); - editor.selection.off("changeSelection", hideMenu); - if (clearActive) menuActive = false; - } - - /** - * Populates the menu items - * @param {HTMLElement} $trigger - * @returns - */ - function positionMenu($trigger) { - const getProp = ($el, prop) => $el.getBoundingClientRect()[prop]; - const containerRight = getProp($el, "right"); - const containerLeft = getProp($el, "left"); - const containerBottom = getProp($el, "bottom"); - const { lineHeight } = editor.renderer; - const margin = 10; - - // if menu is positioned off screen horizontally from the right - const menuRight = getProp($menu, "right"); - if (menuRight + margin > containerRight) { - const menuLeft = getProp($menu, "left"); - const [x] = relativePosition( - menuLeft - Math.abs(menuRight - containerRight), - ); - $menu.style.left = `${x - margin}px`; - } - - // if menu is positioned off screen horizontally from the left - const menuLeft = getProp($menu, "left"); - if (menuLeft - margin < containerLeft) { - const [x] = relativePosition( - menuLeft + Math.abs(menuLeft - containerLeft), - ); - $menu.style.left = `${x + margin}px`; - } - - if (shrink()) return; - - // if menu is positioned off screen vertically from the bottom - const menuBottom = getProp($menu, "bottom"); - if (menuBottom > containerBottom) { - const range = editor.getSelectionRange(); - let pos; - - if ($trigger === $start) { - pos = range.start; - } else { - pos = range.end; - } - - const { pageY } = renderer.textToScreenCoordinates(pos); - const [, y] = relativePosition(null, pageY - lineHeight * 1.8); - $menu.style.top = `${y}px`; - } - - function shrink() { - const [left, right] = [getProp($menu, "left"), getProp($menu, "right")]; - const tooLeft = left < containerLeft; - const tooRight = right > containerRight; - if (tooLeft || tooRight) { - const { scale = 1 } = $menu.dataset; - $menu.dataset.scale = Number.parseFloat(scale - 0.1); - $menu.style.transform = `scale(${$menu.dataset.scale})`; - positionMenu($trigger); - return true; - } - return false; - } - } - - /** - * Handles teardrop - * @param {HTMLDivElement} $teardrop Teardrop element to handle - */ - function teardropHandler($teardrop) { - $activeTeardrop = $teardrop; - $activeTeardrop.dataset.immortal = true; - teardropDoesShowMenu = true; - teardropTouchEnded = false; - - if (mode === "cursor") { - const timeout = Number.parseInt($cursor.dataset.timeout, 10); - clearTimeout(timeout); - } - - timeTouchStart = Date.now(); - document.addEventListener("touchmove", teardropTouchMoveHandler, config); - document.addEventListener("touchend", teardropTouchEndHandler, config); - } - - /** - * Touch event handler for teardrop - * @param {Event} e - */ - function teardropTouchMoveHandler(e) { - const { clientX, clientY } = e.touches[0]; - const { lineHeight } = renderer; - const { start, end } = editor.selection.getRange(); - let y = clientY - lineHeight * 1.8; - let x = clientX; - - if (timeTouchStart) { - timeTouchStart = null; - - // Prevents accidental touchmove - if (diffX < threshold && diffY < threshold) return; - - const diffX = Math.abs(lastX - clientX); - const diffY = Math.abs(lastY - clientY); - const timeDiff = Date.now() - timeTouchStart; - - // Prevents accidental touchmove or highly sensitive touchmove - if (timeDiff < 50) return; - return; - } - - if ($activeTeardrop === $cursor) { - const { row, column } = renderer.screenToTextCoordinates(x, y); - editor.gotoLine(row + 1, column); - } else if ($activeTeardrop === $start) { - x = clientX + teardropSize; - - const { pageX, pageY } = renderer.textToScreenCoordinates(end); - if (pageY <= y) { - y = pageY; - } - - if (pageY <= y && pageX < x) { - x = pageX; - } - - let { row, column } = renderer.screenToTextCoordinates(x, y); - - if (column === end.column) { - --column; - } - - editor.selection.setSelectionAnchor(row, column); - positionEnd(); - } else { - const { pageX, pageY } = renderer.textToScreenCoordinates(start); - if (pageY >= y) { - y = pageY; - } - - if (pageY >= y && pageX > x) { - x = pageX; - } - - let { row, column } = renderer.screenToTextCoordinates(x, y); - - // if (column === start.column) { - // ++column; - // } - - editor.selection.moveCursorToPosition({ row, column }); - positionStart(); - } - - clearTimeout(teardropMoveTimeout); - const parent = $el.getBoundingClientRect(); - let deltaX = 0; - if (clientY < parent.top) deltaX = -lineHeight; - if (clientY > parent.bottom) deltaX = lineHeight; - - if (deltaX) { - teardropMoveTimeout = setTimeout(() => { - const top = editor.session.getScrollTop(); - editor.session.setScrollTop(top + deltaX); - if (teardropTouchEnded) return; - teardropTouchMoveHandler(e); - }, 100); - } - - const [left, top] = relativePosition(clientX, clientY - lineHeight); - $activeTeardrop.style.left = `${left}px`; - $activeTeardrop.style.top = `${top}px`; - } - - /** - * Touch event handler for teardrop - */ - function teardropTouchEndHandler() { - teardropTouchEnded = true; - if ($activeTeardrop === $cursor) { - cursorMode(); - } else { - selectionMode($activeTeardrop); - } - - $activeTeardrop.dataset.immortal = false; - document.removeEventListener("touchmove", teardropTouchMoveHandler, config); - document.removeEventListener("touchend", teardropTouchEndHandler, config); - if (teardropDoesShowMenu) { - showMenu($activeTeardrop); - } - editor.focus(); - } - - /** - * Editor container on scroll - */ - function onscroll() { - clearTimeout(scrollTimeout); - clearCursorMode(); - clearSelectionMode(null, false); - hideMenu(false); - - hideTooltip(); - scrollTimeout = setTimeout(onscrollend, 100); - } - - /** - * Hides tooltip in the gutter - */ - function hideTooltip() { - $gutter.dispatchEvent(new MouseEvent("mouseout")); - } - - /** - * Editor container on scroll end - */ - function onscrollend() { - scrollTimeout = null; - editor._emit("scroll-end"); - if (!touchEnded) return; - - if (selectionActive) { - selectionMode(); - } - - if (menuActive) { - showMenu($end); - } - } - - /** - * Editor container on update - */ - function onupdate() { - clearSelectionMode(); - clearCursorMode(); - hideMenu(); - } - - /** - * Editor container on change session - */ - function onchangesession() { - if (scrollTimeout) { - clearTimeout(scrollTimeout); - onscrollend(); - } - - cancelAnimationFrame(scrollAnimationFrame); - setTimeout(() => { - const copyText = editor.session.getTextRange(editor.getSelectionRange()); - if (copyText) { - selectionMode($end); - return; - } - - clearSelectionMode(); - cursorMode(); - hideMenu(); - }, 0); - } - - /** - * Editor container on fold - */ - function onfold() { - if (selectionActive) { - positionEnd(); - positionStart(); - hideMenu(); - showMenu($end); - } else { - clearCursorMode(); - } - } - - /** - * Populates the menu items - * @param {'regular'|'read-only'|'select'} mode - */ - function populateMenuItems(mode = "regular") { - $menu.innerHTML = ""; - const copyText = editor.getCopyText(); - const items = []; - - selectionMenu().forEach((item) => { - if (mode === "read-only" && !item.readOnly) return; - if (copyText && !["selected", "all"].includes(item.mode)) return; - if (!copyText && item.mode === "selected") return; - - items.push(item); - }); - - items.forEach(({ onclick, text }) => { - $menu.append(
{text}
); - }); - } - - /** - * Returns relative position of given coordinates - * @param {number} x x coordinate - * @param {number} y y coordinate - * @returns {[number, number]} - */ - function relativePosition(x, y) { - const { top, left } = $el.getBoundingClientRect(); - return [x - left, y - top]; - } -} diff --git a/src/cm/baseExtensions.ts b/src/cm/baseExtensions.ts new file mode 100644 index 000000000..aded7737c --- /dev/null +++ b/src/cm/baseExtensions.ts @@ -0,0 +1,59 @@ +import { closeBrackets, completionKeymap } from "@codemirror/autocomplete"; +import { defaultKeymap, history, historyKeymap } from "@codemirror/commands"; +import { + bracketMatching, + defaultHighlightStyle, + foldGutter, + indentOnInput, + syntaxHighlighting, +} from "@codemirror/language"; +import { highlightSelectionMatches } from "@codemirror/search"; +import type { Extension } from "@codemirror/state"; +import { EditorState } from "@codemirror/state"; +import { + crosshairCursor, + drawSelection, + dropCursor, + highlightActiveLine, + highlightActiveLineGutter, + highlightSpecialChars, + keymap, + rectangularSelection, + tooltips, +} from "@codemirror/view"; + +/** + * Base extensions roughly matching the useful parts of CodeMirror's basicSetup + */ +export default function createBaseExtensions(): Extension[] { + return [ + highlightActiveLineGutter(), + highlightSpecialChars(), + history(), + foldGutter(), + drawSelection(), + dropCursor(), + EditorState.allowMultipleSelections.of(true), + indentOnInput(), + syntaxHighlighting(defaultHighlightStyle, { fallback: true }), + bracketMatching(), + closeBrackets(), + rectangularSelection(), + crosshairCursor(), + highlightActiveLine(), + highlightSelectionMatches(), + keymap.of([...completionKeymap, ...defaultKeymap, ...historyKeymap]), + // This prevents tooltips from being going out of the editor area + tooltips({ + tooltipSpace: (view) => { + const rect = view.dom.getBoundingClientRect(); + return { + top: rect.top, + left: rect.left, + bottom: window.innerHeight, + right: window.innerWidth, + }; + }, + }), + ]; +} diff --git a/src/cm/colorView.ts b/src/cm/colorView.ts new file mode 100644 index 000000000..070a1d68b --- /dev/null +++ b/src/cm/colorView.ts @@ -0,0 +1,256 @@ +import type { Range, Text } from "@codemirror/state"; +import type { DecorationSet, ViewUpdate } from "@codemirror/view"; +import { + Decoration, + EditorView, + ViewPlugin, + WidgetType, +} from "@codemirror/view"; +import pickColor from "dialogs/color"; +import color from "utils/color"; +import { colorRegex, HEX } from "utils/color/regex"; + +interface ColorWidgetState { + from: number; + to: number; + colorType: string; + alpha?: string; +} + +interface ColorWidgetParams extends ColorWidgetState { + color: string; + colorRaw: string; +} + +// WeakMap to carry state from widget DOM back into handler +const colorState = new WeakMap(); + +const HEX_RE = new RegExp(HEX, "gi"); + +const RGBG = new RegExp(colorRegex.anyGlobal); + +const enumColorType = { hex: "hex", rgb: "rgb", hsl: "hsl", named: "named" }; + +const disallowedBoundaryBefore = new Set(["-", ".", "/", "#"]); +const disallowedBoundaryAfter = new Set(["-", ".", "/"]); +const ignoredLeadingWords = new Set(["url"]); + +function isWhitespace(char: string): boolean { + return ( + char === " " || + char === "\t" || + char === "\n" || + char === "\r" || + char === "\f" + ); +} + +function isAlpha(char: string): boolean { + if (!char) return false; + const code = char.charCodeAt(0); + return ( + (code >= 65 && code <= 90) || // A-Z + (code >= 97 && code <= 122) + ); +} + +function charAt(doc: Text, index: number): string { + if (index < 0 || index >= doc.length) return ""; + return doc.sliceString(index, index + 1); +} + +function findPrevNonWhitespace(doc: Text, index: number): number { + for (let i = index - 1; i >= 0; i--) { + if (!isWhitespace(charAt(doc, i))) return i; + } + return -1; +} + +function findNextNonWhitespace(doc: Text, index: number): number { + for (let i = index; i < doc.length; i++) { + if (!isWhitespace(charAt(doc, i))) return i; + } + return doc.length; +} + +function readWordBefore(doc: Text, index: number): string { + let pos = index; + while (pos >= 0 && isWhitespace(charAt(doc, pos))) pos--; + if (pos < 0) return ""; + if (charAt(doc, pos) === "(") { + pos--; + } + while (pos >= 0 && isWhitespace(charAt(doc, pos))) pos--; + const end = pos; + while (pos >= 0 && isAlpha(charAt(doc, pos))) pos--; + const start = pos + 1; + if (end < start) return ""; + return doc.sliceString(start, end + 1).toLowerCase(); +} + +function shouldRenderColor(doc: Text, start: number, end: number): boolean { + const immediatePrev = charAt(doc, start - 1); + if (disallowedBoundaryBefore.has(immediatePrev)) return false; + + const immediateNext = charAt(doc, end); + if (disallowedBoundaryAfter.has(immediateNext)) return false; + + const prevNonWhitespaceIndex = findPrevNonWhitespace(doc, start); + if (prevNonWhitespaceIndex !== -1) { + const prevNonWhitespaceChar = charAt(doc, prevNonWhitespaceIndex); + if (disallowedBoundaryBefore.has(prevNonWhitespaceChar)) return false; + const prevWord = readWordBefore(doc, prevNonWhitespaceIndex); + if (ignoredLeadingWords.has(prevWord)) return false; + } + + const nextNonWhitespaceIndex = findNextNonWhitespace(doc, end); + if (nextNonWhitespaceIndex < doc.length) { + const nextNonWhitespaceChar = charAt(doc, nextNonWhitespaceIndex); + if (disallowedBoundaryAfter.has(nextNonWhitespaceChar)) return false; + } + + return true; +} + +class ColorWidget extends WidgetType { + state: ColorWidgetState; + color: string; + colorRaw: string; + + constructor({ color, colorRaw, ...state }: ColorWidgetParams) { + super(); + this.state = state; // from, to, colorType, alpha + this.color = color; // hex for input value + this.colorRaw = colorRaw; // original css color string + } + + eq(other: ColorWidget): boolean { + return ( + other.state.colorType === this.state.colorType && + other.color === this.color && + other.state.from === this.state.from && + other.state.to === this.state.to && + (other.state.alpha || "") === (this.state.alpha || "") + ); + } + + toDOM(): HTMLElement { + const wrapper = document.createElement("span"); + wrapper.className = "cm-color-chip"; + wrapper.style.display = "inline-block"; + wrapper.style.width = "0.9em"; + wrapper.style.height = "0.9em"; + wrapper.style.borderRadius = "2px"; + wrapper.style.verticalAlign = "middle"; + wrapper.style.margin = "0 2px"; + wrapper.style.boxSizing = "border-box"; + wrapper.style.border = "1px solid rgba(0,0,0,0.2)"; + wrapper.style.backgroundColor = this.colorRaw; + wrapper.dataset["color"] = this.color; + wrapper.dataset["colorraw"] = this.colorRaw; + wrapper.style.cursor = "pointer"; + colorState.set(wrapper, this.state); + return wrapper; + } + + ignoreEvent(): boolean { + return false; + } +} + +function colorDecorations(view: EditorView): DecorationSet { + const deco: Range[] = []; + const ranges = view.visibleRanges; + const doc = view.state.doc; + for (const { from, to } of ranges) { + const text = doc.sliceString(from, to); + // Any color using global matcher from utils (captures named/rgb/rgba/hsl/hsla/hex) + RGBG.lastIndex = 0; + for (let m: RegExpExecArray | null; (m = RGBG.exec(text)); ) { + const raw = m[2]; + const start = from + m.index + m[1].length; + const end = start + raw.length; + if (!shouldRenderColor(doc, start, end)) continue; + const c = color(raw); + const colorHex = c.hex.toString(false); + deco.push( + Decoration.widget({ + widget: new ColorWidget({ + from: start, + to: end, + color: colorHex, + colorRaw: raw, + colorType: enumColorType.named, + }), + side: -1, + }).range(start), + ); + } + } + + return Decoration.set(deco, true); +} + +class ColorViewPlugin { + decorations: DecorationSet; + + constructor(view: EditorView) { + this.decorations = colorDecorations(view); + } + + update(update: ViewUpdate): void { + if (update.docChanged || update.viewportChanged) { + this.decorations = colorDecorations(update.view); + } + const readOnly = update.view.contentDOM.ariaReadOnly === "true"; + const editable = update.view.contentDOM.contentEditable === "true"; + const canBeEdited = readOnly === false && editable; + this.changePicker(update.view, canBeEdited); + } + + changePicker(view: EditorView, canBeEdited: boolean): void { + const doms = view.contentDOM.querySelectorAll("input[type=color]"); + doms.forEach((inp) => { + const input = inp as HTMLInputElement; + if (canBeEdited) { + input.removeAttribute("disabled"); + } else { + input.setAttribute("disabled", ""); + } + }); + } +} + +export const colorView = (showPicker = true) => + ViewPlugin.fromClass(ColorViewPlugin, { + decorations: (v) => v.decorations, + eventHandlers: { + click: (e: PointerEvent, view: EditorView): boolean => { + const target = e.target as HTMLElement | null; + const chip = target?.closest?.(".cm-color-chip") as HTMLElement | null; + if (!chip) return false; + // Respect read-only and setting toggle + const readOnly = view.contentDOM.ariaReadOnly === "true"; + const editable = view.contentDOM.contentEditable === "true"; + const canBeEdited = !readOnly && editable; + if (!canBeEdited) return true; + const data = colorState.get(chip); + if (!data) return false; + + pickColor(chip.dataset.colorraw || chip.dataset.color || "") + .then((picked: string | null) => { + if (!picked) return; + view.dispatch({ + changes: { from: data.from, to: data.to, insert: picked }, + }); + }) + .catch(() => { + /* ignore */ + }); + + return true; + }, + }, + }); + +export default colorView; diff --git a/src/cm/commandRegistry.js b/src/cm/commandRegistry.js new file mode 100644 index 000000000..f0ceba6e8 --- /dev/null +++ b/src/cm/commandRegistry.js @@ -0,0 +1,1542 @@ +import fsOperation from "fileSystem"; +import * as cmCommands from "@codemirror/commands"; +import { + copyLineDown, + copyLineUp, + cursorCharLeft, + cursorCharRight, + cursorDocEnd, + cursorDocStart, + cursorGroupLeft, + cursorGroupRight, + cursorLineDown, + cursorLineEnd, + cursorLineStart, + cursorLineUp, + cursorMatchingBracket, + cursorPageDown, + cursorPageUp, + deleteCharBackward, + deleteCharForward, + deleteGroupBackward, + deleteGroupForward, + deleteLine, + deleteLineBoundaryForward, + deleteToLineEnd, + deleteToLineStart, + indentLess, + indentMore, + indentSelection, + insertBlankLine, + insertNewlineAndIndent, + lineComment, + lineUncomment, + moveLineDown, + moveLineUp, + redo, + selectAll, + selectCharLeft, + selectCharRight, + selectDocEnd, + selectDocStart, + selectGroupLeft, + selectGroupRight, + selectLine, + selectLineDown, + selectLineEnd, + selectLineStart, + selectLineUp, + selectMatchingBracket, + selectPageDown, + selectPageUp, + simplifySelection, + toggleBlockComment, + undo, +} from "@codemirror/commands"; +import { indentUnit as indentUnitFacet } from "@codemirror/language"; +import { + closeLintPanel, + forceLinting, + nextDiagnostic, + openLintPanel, + previousDiagnostic, +} from "@codemirror/lint"; +import { + LSPPlugin, + closeReferencePanel as lspCloseReferencePanel, + findReferences as lspFindReferences, + formatDocument as lspFormatDocument, + jumpToDeclaration as lspJumpToDeclaration, + jumpToDefinition as lspJumpToDefinition, + jumpToImplementation as lspJumpToImplementation, + jumpToTypeDefinition as lspJumpToTypeDefinition, + nextSignature as lspNextSignature, + prevSignature as lspPrevSignature, + showSignatureHelp as lspShowSignatureHelp, +} from "@codemirror/lsp-client"; +import { Compartment, EditorSelection } from "@codemirror/state"; +import { keymap } from "@codemirror/view"; +import { + renameSymbol as acodeRenameSymbol, + clearDiagnosticsEffect, + clientManager, +} from "cm/lsp"; +import { + closeReferencesPanel as acodeCloseReferencesPanel, + findAllReferences as acodeFindAllReferences, + findAllReferencesInTab as acodeFindAllReferencesInTab, +} from "cm/lsp/references"; +import { showDocumentSymbols } from "components/symbolsPanel"; +import toast from "components/toast"; +import prompt from "dialogs/prompt"; +import actions from "handlers/quickTools"; +import keyBindings from "lib/keyBindings"; +import settings from "lib/settings"; +import Url from "utils/Url"; + +const commandKeymapCompartment = new Compartment(); + +/** + * @typedef {import("@codemirror/view").EditorView} EditorView + */ + +/** + * @typedef {{ + * name: string; + * description?: string; + * readOnly?: boolean; + * run: (view?: EditorView | null) => boolean | void; + * requiresView?: boolean; + * defaultDescription?: string; + * key?: string | null; + * }} CommandEntry + */ + +/** @type {Map} */ +const commandMap = new Map(); + +/** @type {Record} */ +let resolvedKeyBindings = keyBindings; + +/** @type {import("@codemirror/view").KeyBinding[]} */ +let cachedKeymap = []; + +const ARROW_KEY_MAP = { + left: "ArrowLeft", + right: "ArrowRight", + up: "ArrowUp", + down: "ArrowDown", +}; + +const SPECIAL_KEY_MAP = { + esc: "Escape", + escape: "Escape", + return: "Enter", + enter: "Enter", + space: "Space", + del: "Delete", + delete: "Delete", + backspace: "Backspace", + tab: "Tab", + home: "Home", + end: "End", + pageup: "PageUp", + pagedown: "PageDown", + insert: "Insert", +}; + +const MODIFIER_MAP = { + ctrl: "Mod", + control: "Mod", + cmd: "Mod", + meta: "Mod", + shift: "Shift", + alt: "Alt", + option: "Alt", +}; + +const CODEMIRROR_COMMAND_ENTRIES = Object.entries(cmCommands).filter( + ([, value]) => typeof value === "function", +); + +const CODEMIRROR_COMMAND_MAP = new Map( + CODEMIRROR_COMMAND_ENTRIES.map(([name, fn]) => [name, fn]), +); + +registerCoreCommands(); +registerLspCommands(); +registerLintCommands(); +registerCommandsFromKeyBindings(); +rebuildKeymap(); + +function registerCoreCommands() { + addCommand({ + name: "focusEditor", + description: "Focus editor", + readOnly: true, + requiresView: false, + run(view) { + const resolvedView = resolveView(view); + resolvedView?.focus(); + return true; + }, + }); + addCommand({ + name: "findFile", + description: "Find file in workspace", + readOnly: true, + requiresView: false, + run() { + acode.exec("find-file"); + return true; + }, + }); + addCommand({ + name: "closeCurrentTab", + description: "Close current tab", + readOnly: false, + requiresView: false, + run() { + acode.exec("close-current-tab"); + return true; + }, + }); + addCommand({ + name: "closeAllTabs", + description: "Close all tabs", + readOnly: false, + requiresView: false, + run() { + acode.exec("close-all-tabs"); + return true; + }, + }); + addCommand({ + name: "newFile", + description: "Create new file", + readOnly: true, + requiresView: false, + run() { + acode.exec("new-file"); + return true; + }, + }); + addCommand({ + name: "openFile", + description: "Open a file", + readOnly: true, + requiresView: false, + run() { + acode.exec("open-file"); + return true; + }, + }); + addCommand({ + name: "openFolder", + description: "Open a folder", + readOnly: true, + requiresView: false, + run() { + acode.exec("open-folder"); + return true; + }, + }); + addCommand({ + name: "saveFile", + description: "Save current file", + readOnly: true, + requiresView: false, + run() { + acode.exec("save"); + return true; + }, + }); + addCommand({ + name: "saveFileAs", + description: "Save as current file", + readOnly: true, + requiresView: false, + run() { + acode.exec("save-as"); + return true; + }, + }); + addCommand({ + name: "saveAllChanges", + description: "Save all changes", + readOnly: true, + requiresView: false, + run() { + acode.exec("save-all-changes"); + return true; + }, + }); + addCommand({ + name: "nextFile", + description: "Open next file tab", + readOnly: true, + requiresView: false, + run() { + acode.exec("next-file"); + return true; + }, + }); + addCommand({ + name: "prevFile", + description: "Open previous file tab", + readOnly: true, + requiresView: false, + run() { + acode.exec("prev-file"); + return true; + }, + }); + addCommand({ + name: "showSettingsMenu", + description: "Show settings menu", + readOnly: true, + requiresView: false, + run() { + acode.exec("open", "settings"); + return true; + }, + }); + addCommand({ + name: "renameFile", + description: "Rename active file", + readOnly: true, + requiresView: false, + run() { + acode.exec("rename"); + return true; + }, + }); + addCommand({ + name: "run", + description: "Preview HTML and MarkDown", + readOnly: true, + requiresView: false, + run() { + acode.exec("run"); + return true; + }, + }); + addCommand({ + name: "openInAppBrowser", + description: "Open In-App Browser", + readOnly: true, + requiresView: false, + run: openInAppBrowserCommand, + }); + addCommand({ + name: "toggleFullscreen", + description: "Toggle full screen mode", + readOnly: true, + requiresView: false, + run() { + acode.exec("toggle-fullscreen"); + return true; + }, + }); + addCommand({ + name: "toggleSidebar", + description: "Toggle sidebar", + readOnly: true, + requiresView: false, + run() { + acode.exec("toggle-sidebar"); + return true; + }, + }); + addCommand({ + name: "toggleMenu", + description: "Toggle main menu", + readOnly: true, + requiresView: false, + run() { + acode.exec("toggle-menu"); + return true; + }, + }); + addCommand({ + name: "toggleEditMenu", + description: "Toggle edit menu", + readOnly: true, + requiresView: false, + run() { + acode.exec("toggle-editmenu"); + return true; + }, + }); + addCommand({ + name: "selectall", + description: "Select all", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return selectAll(resolvedView); + }, + }); + addCommand({ + name: "gotoline", + description: "Go to line...", + readOnly: true, + requiresView: false, + run() { + acode.exec("goto"); + return true; + }, + }); + addCommand({ + name: "find", + description: "Find", + readOnly: true, + requiresView: false, + run() { + acode.exec("find"); + return true; + }, + }); + addCommand({ + name: "copy", + description: "Copy", + readOnly: true, + requiresView: true, + run: copyCommand, + }); + addCommand({ + name: "cut", + description: "Cut", + readOnly: false, + requiresView: true, + run: cutCommand, + }); + addCommand({ + name: "paste", + description: "Paste", + readOnly: false, + requiresView: true, + run: pasteCommand, + }); + addCommand({ + name: "problems", + description: "Show errors and warnings", + readOnly: true, + requiresView: false, + run() { + acode.exec("open", "problems"); + return true; + }, + }); + addCommand({ + name: "replace", + description: "Replace", + readOnly: true, + requiresView: false, + run() { + acode.exec("replace"); + return true; + }, + }); + addCommand({ + name: "openCommandPalette", + description: "Open command palette", + readOnly: true, + requiresView: false, + run() { + acode.exec("command-palette"); + return true; + }, + }); + addCommand({ + name: "modeSelect", + description: "Change language mode...", + readOnly: true, + requiresView: false, + run() { + acode.exec("syntax"); + return true; + }, + }); + addCommand({ + name: "toggleQuickTools", + description: "Toggle quick tools", + readOnly: true, + requiresView: false, + run() { + actions("toggle"); + return true; + }, + }); + addCommand({ + name: "selectWord", + description: "Select current word", + readOnly: false, + requiresView: true, + run: selectWordCommand, + }); + addCommand({ + name: "openLogFile", + description: "Open Log File", + readOnly: true, + requiresView: false, + run() { + acode.exec("open-log-file"); + return true; + }, + }); + addCommand({ + name: "increaseFontSize", + description: "Increase font size", + readOnly: false, + requiresView: false, + run: () => adjustFontSize(1), + }); + addCommand({ + name: "decreaseFontSize", + description: "Decrease font size", + readOnly: false, + requiresView: false, + run: () => adjustFontSize(-1), + }); + addCommand({ + name: "openPluginsPage", + description: "Open Plugins Page", + readOnly: true, + requiresView: false, + run() { + acode.exec("open", "plugins"); + return true; + }, + }); + addCommand({ + name: "openFileExplorer", + description: "File Explorer", + readOnly: true, + requiresView: false, + run() { + acode.exec("open", "file_browser"); + return true; + }, + }); + addCommand({ + name: "copyDeviceInfo", + description: "Copy Device info", + readOnly: true, + requiresView: false, + run() { + acode.exec("copy-device-info"); + return true; + }, + }); + addCommand({ + name: "changeAppTheme", + description: "Change App Theme", + readOnly: true, + requiresView: false, + run() { + acode.exec("change-app-theme"); + return true; + }, + }); + addCommand({ + name: "changeEditorTheme", + description: "Change Editor Theme", + readOnly: true, + requiresView: false, + run() { + acode.exec("change-editor-theme"); + return true; + }, + }); + addCommand({ + name: "openTerminal", + description: "Open Terminal", + readOnly: true, + requiresView: false, + run() { + acode.exec("new-terminal"); + return true; + }, + }); + addCommand({ + name: "acode:showWelcome", + description: "Show Welcome", + readOnly: true, + requiresView: false, + run() { + acode.exec("welcome"); + return true; + }, + }); + addCommand({ + name: "run-tests", + description: "Run Tests", + key: "Ctrl-Shift-T", + readOnly: true, + requiresView: false, + run() { + acode.exec("run-tests"); + return true; + }, + }); + addCommand({ + name: "dev:openInspector", + description: "Open Inspector", + run() { + acode.exec("open-inspector"); + return true; + }, + readOnly: true, + requiresView: false, + }); + addCommand({ + name: "dev:toggleDevTools", + description: "Toggle Developer Tools", + run() { + acode.exec("toggle-inspector"); + return true; + }, + readOnly: true, + requiresView: false, + key: "Ctrl-Shift-I", + }); + + // Additional editor-centric helpers mapped to CodeMirror primitives that have existing key bindings in defaults. + addCommand({ + name: "duplicateSelection", + description: "Duplicate selection", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return copyLineDown(resolvedView); + }, + }); + addCommand({ + name: "copylinesdown", + description: "Copy lines down", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return copyLineDown(resolvedView); + }, + }); + addCommand({ + name: "copylinesup", + description: "Copy lines up", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return copyLineUp(resolvedView); + }, + }); + addCommand({ + name: "movelinesdown", + description: "Move lines down", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return moveLineDown(resolvedView); + }, + }); + addCommand({ + name: "movelinesup", + description: "Move lines up", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return moveLineUp(resolvedView); + }, + }); + addCommand({ + name: "removeline", + description: "Remove line", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return deleteLine(resolvedView); + }, + }); + addCommand({ + name: "insertlineafter", + description: "Insert line after", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return insertBlankLine(resolvedView); + }, + }); + addCommand({ + name: "selectline", + description: "Select line", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return selectLine(resolvedView); + }, + }); + addCommand({ + name: "selectlinesdown", + description: "Select line down", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return selectLineDown(resolvedView); + }, + }); + addCommand({ + name: "selectlinesup", + description: "Select line up", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return selectLineUp(resolvedView); + }, + }); + addCommand({ + name: "selectlinestart", + description: "Select line start", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return selectLineStart(resolvedView); + }, + }); + addCommand({ + name: "selectlineend", + description: "Select line end", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return selectLineEnd(resolvedView); + }, + }); + addCommand({ + name: "indent", + description: "Indent", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const { state } = resolvedView; + const hasSelection = state.selection.ranges.some((range) => !range.empty); + if (hasSelection) { + return indentMore(resolvedView); + } + const indentString = + state.facet(indentUnitFacet) || + (settings?.value?.softTab + ? " ".repeat(Math.max(1, Number(settings?.value?.tabSize) || 2)) + : "\t"); + const insert = indentString && indentString.length ? indentString : "\t"; + resolvedView.dispatch( + state.changeByRange((range) => ({ + changes: { from: range.from, to: range.to, insert }, + range: EditorSelection.cursor(range.from + insert.length), + })), + ); + return true; + }, + }); + addCommand({ + name: "outdent", + description: "Outdent", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return indentLess(resolvedView); + }, + }); + addCommand({ + name: "indentselection", + description: "Indent selection", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return indentSelection(resolvedView); + }, + }); + addCommand({ + name: "newline", + description: "Insert newline", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return insertNewlineAndIndent(resolvedView); + }, + }); + addCommand({ + name: "joinlines", + description: "Join lines", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return deleteLineBoundaryForward(resolvedView); + }, + }); + addCommand({ + name: "deletetolinestart", + description: "Delete to line start", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return deleteToLineStart(resolvedView); + }, + }); + addCommand({ + name: "deletetolineend", + description: "Delete to line end", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return deleteToLineEnd(resolvedView); + }, + }); + addCommand({ + name: "togglecomment", + description: "Toggle comment", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return lineComment(resolvedView); + }, + }); + addCommand({ + name: "comment", + description: "Add line comment", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return lineComment(resolvedView); + }, + }); + addCommand({ + name: "uncomment", + description: "Remove line comment", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return lineUncomment(resolvedView); + }, + }); + addCommand({ + name: "toggleBlockComment", + description: "Toggle block comment", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return toggleBlockComment(resolvedView); + }, + }); + addCommand({ + name: "undo", + description: "Undo", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return undo(resolvedView); + }, + }); + addCommand({ + name: "redo", + description: "Redo", + readOnly: false, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return redo(resolvedView); + }, + }); + addCommand({ + name: "simplifySelection", + description: "Simplify selection", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return simplifySelection(resolvedView); + }, + }); +} + +function registerLspCommands() { + addCommand({ + name: "formatDocument", + description: "Format document (Language Server)", + readOnly: false, + requiresView: true, + run: runLspCommand(lspFormatDocument), + }); + addCommand({ + name: "renameSymbol", + description: "Rename symbol (Language Server)", + readOnly: false, + requiresView: true, + run: runLspCommand(acodeRenameSymbol), + }); + addCommand({ + name: "showSignatureHelp", + description: "Show signature help", + readOnly: true, + requiresView: true, + run: runLspCommand(lspShowSignatureHelp), + }); + addCommand({ + name: "nextSignature", + description: "Next signature", + readOnly: true, + requiresView: true, + run: runLspCommand(lspNextSignature, { silentOnMissing: true }), + }); + addCommand({ + name: "prevSignature", + description: "Previous signature", + readOnly: true, + requiresView: true, + run: runLspCommand(lspPrevSignature, { silentOnMissing: true }), + }); + addCommand({ + name: "jumpToDefinition", + description: "Go to definition (Language Server)", + readOnly: true, + requiresView: true, + run: runLspCommand(lspJumpToDefinition), + }); + addCommand({ + name: "jumpToDeclaration", + description: "Go to declaration (Language Server)", + readOnly: true, + requiresView: true, + run: runLspCommand(lspJumpToDeclaration), + }); + addCommand({ + name: "jumpToTypeDefinition", + description: "Go to type definition (Language Server)", + readOnly: true, + requiresView: true, + run: runLspCommand(lspJumpToTypeDefinition), + }); + addCommand({ + name: "jumpToImplementation", + description: "Go to implementation (Language Server)", + readOnly: true, + requiresView: true, + run: runLspCommand(lspJumpToImplementation), + }); + addCommand({ + name: "findReferences", + description: "Find all references (Language Server)", + readOnly: true, + requiresView: true, + async run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const plugin = LSPPlugin.get(resolvedView); + if (!plugin) { + notifyLspUnavailable(); + return false; + } + return acodeFindAllReferences(resolvedView); + }, + }); + addCommand({ + name: "closeReferencePanel", + description: "Close references panel", + readOnly: true, + requiresView: false, + run() { + return acodeCloseReferencesPanel(); + }, + }); + addCommand({ + name: "findReferencesInTab", + description: "Find all references in new tab (Language Server)", + readOnly: true, + requiresView: true, + async run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const plugin = LSPPlugin.get(resolvedView); + if (!plugin) { + notifyLspUnavailable(); + return false; + } + return acodeFindAllReferencesInTab(resolvedView); + }, + }); + addCommand({ + name: "restartAllLspServers", + description: "Restart all running LSP servers", + readOnly: true, + requiresView: false, + async run() { + const activeClients = clientManager.getActiveClients(); + if (!activeClients.length) { + toast("No LSP servers are currently running"); + return true; + } + const count = activeClients.length; + toast(`Restarting ${count} LSP server${count > 1 ? "s" : ""}...`); + + // Dispose all clients (also clears diagnostics) + await clientManager.dispose(); + + // Trigger reconnect for active file + editorManager?.restartLsp?.(); + return true; + }, + }); + addCommand({ + name: "stopAllLspServers", + description: "Stop all running LSP servers", + readOnly: true, + requiresView: false, + async run() { + const activeClients = clientManager.getActiveClients(); + if (!activeClients.length) { + toast("No LSP servers are currently running"); + return true; + } + const count = activeClients.length; + + // Dispose all clients + await clientManager.dispose(); + toast(`Stopped ${count} LSP server${count > 1 ? "s" : ""}`); + return true; + }, + }); + addCommand({ + name: "documentSymbols", + description: "Go to Symbol in Document...", + readOnly: true, + requiresView: true, + async run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return showDocumentSymbols(resolvedView); + }, + }); +} + +function registerLintCommands() { + addCommand({ + name: "openLintPanel", + description: "Open lint panel", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return openLintPanel(resolvedView); + }, + }); + addCommand({ + name: "closeLintPanel", + description: "Close lint panel", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return closeLintPanel(resolvedView); + }, + }); + addCommand({ + name: "nextDiagnostic", + description: "Go to next diagnostic", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return nextDiagnostic(resolvedView); + }, + }); + addCommand({ + name: "previousDiagnostic", + description: "Go to previous diagnostic", + readOnly: true, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return previousDiagnostic(resolvedView); + }, + }); +} + +function registerCommandsFromKeyBindings() { + Object.entries(keyBindings).forEach(([name, binding]) => { + if (commandMap.has(name)) return; + const description = binding?.description || humanizeCommandName(name); + const readOnly = binding?.readOnly ?? false; + const requiresView = !!binding?.editorOnly; + const commandFn = CODEMIRROR_COMMAND_MAP.get(name); + + if (binding?.action) { + addCommand({ + name, + description, + readOnly, + requiresView, + run(view) { + try { + if (requiresView) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + } + acode.exec(binding.action); + return true; + } catch (error) { + console.error(`Failed to execute action ${binding.action}`, error); + return false; + } + }, + }); + return; + } + + if (commandFn) { + addCommand({ + name, + description, + readOnly, + requiresView: true, + run(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + return commandFn(resolvedView); + }, + }); + } + }); +} + +function addCommand(entry) { + const command = { + ...entry, + defaultDescription: entry.description || entry.name, + key: entry.key ?? null, + }; + commandMap.set(entry.name, command); +} + +function resolveView(view) { + return view || editorManager?.editor || null; +} + +function notifyLspUnavailable() { + toast?.("Language server not available"); +} + +function runLspCommand(commandFn, options = {}) { + return (view) => { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const plugin = LSPPlugin.get(resolvedView); + if (!plugin) { + if (!options?.silentOnMissing) { + notifyLspUnavailable(); + } + return false; + } + const result = commandFn(resolvedView); + return result !== false; + }; +} + +function humanizeCommandName(name) { + return name + .replace(/([a-z0-9])([A-Z])/g, "$1 $2") + .replace(/_/g, " ") + .replace(/^./, (char) => char.toUpperCase()); +} + +function copyCommand(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const { state } = resolvedView; + const texts = state.selection.ranges.map((range) => { + if (range.empty) { + const line = state.doc.lineAt(range.head); + return state.doc.sliceString(line.from, line.to); + } + return state.doc.sliceString(range.from, range.to); + }); + const textToCopy = texts.join("\n"); + cordova.plugins.clipboard.copy(textToCopy); + toast?.(strings?.["copied to clipboard"] || "Copied to clipboard"); + return true; +} + +function cutCommand(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const { state } = resolvedView; + const ranges = state.selection.ranges; + const segments = []; + let changes = []; + ranges.forEach((range) => { + if (range.empty) { + const line = state.doc.lineAt(range.head); + segments.push(state.doc.sliceString(line.from, line.to)); + changes.push({ from: line.from, to: line.to, insert: "" }); + return; + } + segments.push(state.doc.sliceString(range.from, range.to)); + changes.push({ from: range.from, to: range.to, insert: "" }); + }); + cordova.plugins.clipboard.copy(segments.join("\n")); + resolvedView.dispatch({ + changes, + selection: EditorSelection.single( + changes[0]?.from ?? state.selection.main.from, + ), + }); + return true; +} + +function pasteCommand(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + cordova.plugins.clipboard.paste((text = "") => { + const insertText = String(text); + resolvedView.dispatch( + resolvedView.state.changeByRange((range) => ({ + changes: { from: range.from, to: range.to, insert: insertText }, + range: EditorSelection.cursor(range.from + insertText.length), + })), + ); + }); + return true; +} + +function selectWordCommand(view) { + const resolvedView = resolveView(view); + if (!resolvedView) return false; + const { state } = resolvedView; + const ranges = state.selection.ranges.map((range) => { + const word = state.wordAt(range.head); + if (word) return EditorSelection.range(word.from, word.to); + const line = state.doc.lineAt(range.head); + return EditorSelection.range(line.from, line.to); + }); + resolvedView.dispatch({ + selection: EditorSelection.create(ranges, state.selection.mainIndex), + }); + return true; +} + +async function openInAppBrowserCommand() { + const url = await prompt("Enter url", "", "url", { + placeholder: "http://", + match: /^https?:\/\/.+/, + }); + if (url) acode.exec("open-inapp-browser", url); + return true; +} + +function adjustFontSize(delta) { + const current = settings?.value?.fontSize || "12px"; + const numeric = Number.parseInt(current, 10) || 12; + const next = Math.max(1, numeric + delta); + settings.value.fontSize = `${next}px`; + settings.update(false); + return true; +} + +function parseKeyString(keyString) { + if (!keyString) return []; + return String(keyString) + .split("|") + .map((combo) => combo.trim()) + .filter(Boolean); +} + +function toCodeMirrorKey(combo) { + if (!combo) return null; + const parts = combo + .split("-") + .map((part) => part.trim()) + .filter(Boolean); + const modifiers = []; + let key = null; + + parts.forEach((part, index) => { + const lower = part.toLowerCase(); + if (MODIFIER_MAP[lower]) { + const mod = MODIFIER_MAP[lower]; + if (!modifiers.includes(mod)) modifiers.push(mod); + return; + } + + if (ARROW_KEY_MAP[lower]) { + key = ARROW_KEY_MAP[lower]; + return; + } + + if (SPECIAL_KEY_MAP[lower]) { + key = SPECIAL_KEY_MAP[lower]; + return; + } + + if (part.length === 1 && /[a-z]/i.test(part)) { + key = part.length === 1 ? part.toLowerCase() : part; + return; + } + + key = part; + }); + + if (!key) return modifiers.join("-") || null; + return modifiers.length ? `${modifiers.join("-")}-${key}` : key; +} + +function rebuildKeymap() { + const bindings = []; + commandMap.forEach((command, name) => { + const bindingInfo = resolvedKeyBindings?.[name]; + command.description = + bindingInfo?.description || command.defaultDescription; + const keySource = bindingInfo?.key ?? command.key ?? null; + command.key = keySource; + const combos = parseKeyString(keySource); + combos.forEach((combo) => { + const cmKey = toCodeMirrorKey(combo); + if (!cmKey) return; + bindings.push({ + key: cmKey, + run: (view) => executeCommand(name, view), + preventDefault: true, + }); + }); + }); + cachedKeymap = bindings; + return bindings; +} + +function resolveCommand(name) { + return commandMap.get(name) || null; +} + +function commandRunsInReadOnly(command, view) { + if (!view) return command.readOnly; + return view.state?.readOnly ? !!command.readOnly : true; +} + +export function executeCommand(name, view, args) { + const command = resolveCommand(name); + if (!command) return false; + const targetView = command.requiresView + ? resolveView(view) + : resolveView(view) || null; + if (command.requiresView && !targetView) return false; + if (!commandRunsInReadOnly(command, targetView)) return false; + try { + const result = command.run(targetView, args); + return result !== false; + } catch (error) { + console.error(`Failed to execute command ${name}`, error); + return false; + } +} + +export function getRegisteredCommands() { + return Array.from(commandMap.values()).map((command) => ({ + name: command.name, + description: command.description || command.defaultDescription, + key: command.key || null, + })); +} + +export function getCommandKeymapExtension() { + return commandKeymapCompartment.of(keymap.of(cachedKeymap)); +} + +export async function setKeyBindings(view) { + await loadCustomKeyBindings(); + const bindings = rebuildKeymap(); + const resolvedView = resolveView(view); + applyCommandKeymap(resolvedView, bindings); +} + +async function loadCustomKeyBindings() { + try { + const bindingsFile = fsOperation(KEYBINDING_FILE); + if (await bindingsFile.exists()) { + const bindings = await bindingsFile.readFile("json"); + if (bindings && typeof bindings === "object") { + resolvedKeyBindings = bindings; + } + } else { + throw new Error("Key binding file not found"); + } + } catch (error) { + await resetKeyBindings(); + resolvedKeyBindings = keyBindings; + } +} + +export async function resetKeyBindings() { + try { + const fs = fsOperation(KEYBINDING_FILE); + const fileName = Url.basename(KEYBINDING_FILE); + const content = JSON.stringify(keyBindings, undefined, 2); + if (!(await fs.exists())) { + await fsOperation(DATA_STORAGE).createFile(fileName, content); + return; + } + await fs.writeFile(content); + } catch (error) { + window.log?.("error", "Reset Keybinding failed!"); + window.log?.("error", error); + } +} + +export { commandKeymapCompartment }; + +export function registerExternalCommand(descriptor = {}) { + const normalized = normalizeExternalCommand(descriptor); + if (!normalized) return null; + + const { name } = normalized; + if (commandMap.has(name)) { + commandMap.delete(name); + } + + addCommand(normalized); + const stored = commandMap.get(name); + if (stored) { + stored.key = normalized.key ?? stored.key; + } + + rebuildKeymap(); + return stored; +} + +export function removeExternalCommand(name) { + if (!name) return false; + const exists = commandMap.has(name); + if (!exists) return false; + commandMap.delete(name); + rebuildKeymap(); + return true; +} + +export function refreshCommandKeymap(view) { + const resolvedView = resolveView(view); + applyCommandKeymap(resolvedView); +} + +function normalizeExternalCommand(descriptor) { + const name = + typeof descriptor?.name === "string" ? descriptor.name.trim() : ""; + if (!name) { + console.warn("Command registration skipped: missing name", descriptor); + return null; + } + const exec = typeof descriptor?.exec === "function" ? descriptor.exec : null; + if (!exec) { + console.warn( + `Command registration skipped for "${name}": exec must be a function.`, + ); + return null; + } + + const requiresView = descriptor?.requiresView ?? true; + const key = normalizeExternalKey(descriptor?.bindKey); + + return { + name, + description: descriptor?.description || humanizeCommandName(name), + readOnly: descriptor?.readOnly ?? true, + requiresView, + key, + run(view, args) { + try { + const resolvedView = resolveView(view); + if (requiresView && !resolvedView) return false; + const result = exec(resolvedView || null, args); + return result !== false; + } catch (error) { + console.error(`Command \"${name}\" failed`, error); + return false; + } + }, + }; +} + +function normalizeExternalKey(bindKey) { + if (!bindKey) return null; + if (typeof bindKey === "string") return bindKey; + const combos = []; + if (typeof bindKey === "object") { + const pushCombo = (combo) => { + if (typeof combo === "string" && combo.trim()) combos.push(combo.trim()); + }; + pushCombo(bindKey.win); + pushCombo(bindKey.linux); + pushCombo(bindKey.mac); + } + return combos.length ? combos.join("|") : null; +} + +function applyCommandKeymap(view, bindings = cachedKeymap) { + if (!view) return; + view.dispatch({ + effects: commandKeymapCompartment.reconfigure( + keymap.of(bindings ?? cachedKeymap), + ), + }); +} diff --git a/src/cm/editorUtils.ts b/src/cm/editorUtils.ts new file mode 100644 index 000000000..ff750f061 --- /dev/null +++ b/src/cm/editorUtils.ts @@ -0,0 +1,182 @@ +import { foldEffect, foldedRanges } from "@codemirror/language"; +import type { EditorState, StateEffect } from "@codemirror/state"; +import { EditorSelection } from "@codemirror/state"; +import type { EditorView } from "@codemirror/view"; + +export interface FoldSpan { + fromLine: number; + fromCol: number; + toLine: number; + toCol: number; +} +export interface SelectionRange { + from: number; + to: number; +} +export interface SerializedSelection { + ranges: SelectionRange[]; + mainIndex: number; +} +export interface ScrollPosition { + scrollTop: number; + scrollLeft: number; +} + +/** + * Get all folded ranges from CodeMirror editor state + */ +export function getAllFolds(state: EditorState): FoldSpan[] { + const doc = state.doc; + const folds: FoldSpan[] = []; + + foldedRanges(state).between(0, doc.length, (from, to) => { + const fromPos = doc.lineAt(from); + const toPos = doc.lineAt(to); + folds.push({ + fromLine: fromPos.number, + fromCol: from - fromPos.from, + toLine: toPos.number, + toCol: to - toPos.from, + }); + }); + + return folds; +} + +/** + * Get current selection from editor view + */ +export function getSelection(view: EditorView): SerializedSelection { + const sel = view.state.selection; + return { + ranges: sel.ranges.map((r) => ({ from: r.from, to: r.to })), + mainIndex: sel.mainIndex, + }; +} + +/** + * Get scroll position from editor view + */ +export function getScrollPosition(view: EditorView): ScrollPosition { + const { scrollTop, scrollLeft } = view.scrollDOM; + return { scrollTop, scrollLeft }; +} + +/** + * Set scroll position in CodeMirror editor view + */ +export function setScrollPosition( + view: EditorView, + scrollTop?: number, + scrollLeft?: number, +): void { + const scroller = view.scrollDOM; + + if (typeof scrollTop === "number") { + scroller.scrollTop = scrollTop; + } + + if (typeof scrollLeft === "number") { + scroller.scrollLeft = scrollLeft; + } +} + +/** + * Restore selection to editor view + */ +export function restoreSelection( + view: EditorView, + sel: SerializedSelection | null | undefined, +): void { + if (!sel || !sel.ranges || !sel.ranges.length) return; + const len = view.state.doc.length; + + const ranges = sel.ranges + .map((r) => { + const from = Math.max(0, Math.min(len, r.from | 0)); + const to = Math.max(0, Math.min(len, r.to | 0)); + return EditorSelection.range(from, to); + }) + .filter(Boolean); + + if (!ranges.length) return; + + const mainIndex = + sel.mainIndex >= 0 && sel.mainIndex < ranges.length ? sel.mainIndex : 0; + + view.dispatch({ + selection: EditorSelection.create(ranges, mainIndex), + scrollIntoView: true, + }); +} + +/** + * Restore folds to CodeMirror editor + */ +export function restoreFolds( + view: EditorView, + folds: FoldSpan[] | null | undefined, +): void { + if (!Array.isArray(folds) || folds.length === 0) return; + + function lineColToOffset( + doc: EditorState["doc"], + line: number, + col: number, + ): number { + const ln = doc.line(line); + return Math.min(ln.from + col, ln.to); + } + + function loadFolds( + state: EditorState, + saved: FoldSpan[], + ): StateEffect<{ from: number; to: number }>[] { + const doc = state.doc; + const effects: StateEffect<{ from: number; to: number }>[] = []; + + for (const f of saved) { + // Validate line numbers + if (f.fromLine < 1 || f.fromLine > doc.lines) continue; + if (f.toLine < 1 || f.toLine > doc.lines) continue; + + const from = lineColToOffset(doc, f.fromLine, f.fromCol); + const to = lineColToOffset(doc, f.toLine, f.toCol); + if (to > from) { + effects.push(foldEffect.of({ from, to })); + } + } + return effects; + } + + const restoreEffects = loadFolds(view.state, folds); + if (restoreEffects.length) { + view.dispatch({ effects: restoreEffects }); + } +} + +/** + * Clear selection, keeping only cursor position + */ +export function clearSelection(view: EditorView): void { + view.dispatch({ + selection: EditorSelection.single(view.state.selection.main.head), + scrollIntoView: true, + }); + // Also clear the global DOM selection to prevent native selection handles/menus persisting + try { + document.getSelection()?.removeAllRanges(); + } catch (_) { + // Ignore errors + } +} + +export default { + getAllFolds, + getSelection, + getScrollPosition, + setScrollPosition, + restoreSelection, + restoreFolds, + clearSelection, +}; diff --git a/src/cm/indentGuides.ts b/src/cm/indentGuides.ts new file mode 100644 index 000000000..fb3324bfc --- /dev/null +++ b/src/cm/indentGuides.ts @@ -0,0 +1,447 @@ +import { syntaxTree } from "@codemirror/language"; +import type { Extension } from "@codemirror/state"; +import { EditorState, RangeSetBuilder } from "@codemirror/state"; +import { + Decoration, + type DecorationSet, + EditorView, + ViewPlugin, + type ViewUpdate, + WidgetType, +} from "@codemirror/view"; +import type { SyntaxNode } from "@lezer/common"; + +/** + * Configuration options for indent guides + */ +export interface IndentGuidesConfig { + /** Whether to highlight the guide at the cursor's indent level */ + highlightActiveGuide?: boolean; + /** Whether to hide guides on blank lines */ + hideOnBlankLines?: boolean; +} + +const defaultConfig: Required = { + highlightActiveGuide: true, + hideOnBlankLines: false, +}; + +/** + * Get the tab size from editor state + */ +function getTabSize(state: EditorState): number { + return state.facet(EditorState.tabSize); +} + +/** + * Calculate the visual indentation of a line + */ +function getLineIndentation(line: string, tabSize: number): number { + let columns = 0; + for (const ch of line) { + if (ch === " ") { + columns++; + } else if (ch === "\t") { + columns += tabSize - (columns % tabSize); + } else { + break; + } + } + return columns; +} + +/** + * Check if a line is blank + */ +function isBlankLine(line: string): boolean { + return /^\s*$/.test(line); +} + +/** + * Node types that represent scope blocks in various languages + */ +const SCOPE_NODE_TYPES = new Set([ + "Block", + "ObjectExpression", + "ArrayExpression", + "ArrowFunction", + "FunctionDeclaration", + "FunctionExpression", + "ClassBody", + "ClassDeclaration", + "MethodDeclaration", + "SwitchBody", + "IfStatement", + "WhileStatement", + "ForStatement", + "ForInStatement", + "ForOfStatement", + "TryStatement", + "CatchClause", + "Object", + "Array", + "Element", + "SelfClosingTag", + "RuleSet", + "Block", + "DeclarationList", + "Body", + "Suite", + "Program", + "Script", + "Module", +]); + +/** + * Information about the active scope for highlighting + */ +interface ActiveScope { + level: number; + startLine: number; + endLine: number; +} + +/** + * Find the active scope using syntax tree analysis + */ +function getActiveScope( + view: EditorView, + indentUnit: number, +): ActiveScope | null { + const { state } = view; + const { main } = state.selection; + const cursorPos = main.head; + + const tree = syntaxTree(state); + if (!tree || tree.length === 0) { + // No syntax tree available, fall back to indentation-based + return getActiveScopeByIndentation(state, indentUnit); + } + + // Find the innermost scope node containing the cursor + let scopeNode: SyntaxNode | null = null; + let node: SyntaxNode | null = tree.resolveInner(cursorPos, 0); + + // Walk up the tree to find a scope-defining node + while (node) { + if (SCOPE_NODE_TYPES.has(node.name)) { + scopeNode = node; + break; + } + node = node.parent; + } + + if (!scopeNode) { + return null; + } + + // Get the line range of this scope + const startLine = state.doc.lineAt(scopeNode.from); + const endLine = state.doc.lineAt(scopeNode.to); + + // Calculate indent level from the first line of the scope's content + // (usually the line after the opening bracket) + let contentStartLine = startLine.number; + if (startLine.number < endLine.number) { + contentStartLine = startLine.number + 1; + } + + const tabSize = getTabSize(state); + let level = 0; + + // Find the first non-blank line inside the scope to determine indent level + for (let ln = contentStartLine; ln <= endLine.number; ln++) { + const line = state.doc.line(ln); + if (!isBlankLine(line.text)) { + const indent = getLineIndentation(line.text, tabSize); + level = Math.floor(indent / indentUnit); + break; + } + } + + if (level <= 0) { + return null; + } + + return { + level, + startLine: startLine.number, + endLine: endLine.number, + }; +} + +/** + * Fallback: Find active scope by indentation when no syntax tree is available + */ +function getActiveScopeByIndentation( + state: EditorState, + indentUnit: number, +): ActiveScope | null { + const { main } = state.selection; + const cursorLine = state.doc.lineAt(main.head); + const tabSize = getTabSize(state); + + let cursorIndent = getLineIndentation(cursorLine.text, tabSize); + + if (isBlankLine(cursorLine.text)) { + for (let lineNum = cursorLine.number - 1; lineNum >= 1; lineNum--) { + const prevLine = state.doc.line(lineNum); + if (!isBlankLine(prevLine.text)) { + cursorIndent = getLineIndentation(prevLine.text, tabSize); + break; + } + } + } + + const cursorLevel = Math.floor(cursorIndent / indentUnit); + if (cursorLevel <= 0) return null; + + let startLine = cursorLine.number; + for (let lineNum = cursorLine.number - 1; lineNum >= 1; lineNum--) { + const line = state.doc.line(lineNum); + if (isBlankLine(line.text)) continue; + const lineLevel = Math.floor( + getLineIndentation(line.text, tabSize) / indentUnit, + ); + if (lineLevel < cursorLevel) break; + startLine = lineNum; + } + + let endLine = cursorLine.number; + for ( + let lineNum = cursorLine.number + 1; + lineNum <= state.doc.lines; + lineNum++ + ) { + const line = state.doc.line(lineNum); + if (isBlankLine(line.text)) { + endLine = lineNum; + continue; + } + const lineLevel = Math.floor( + getLineIndentation(line.text, tabSize) / indentUnit, + ); + if (lineLevel < cursorLevel) break; + endLine = lineNum; + } + + return { level: cursorLevel, startLine, endLine }; +} + +/** + * Widget that renders indent guide lines + */ +class IndentGuidesWidget extends WidgetType { + constructor( + readonly levels: number, + readonly indentUnit: number, + readonly activeGuideIndex: number, + readonly lineHeight: number, + ) { + super(); + } + + eq(other: IndentGuidesWidget): boolean { + return ( + other.levels === this.levels && + other.indentUnit === this.indentUnit && + other.activeGuideIndex === this.activeGuideIndex && + other.lineHeight === this.lineHeight + ); + } + + toDOM(): HTMLElement { + const container = document.createElement("span"); + container.className = "cm-indent-guides-wrapper"; + container.setAttribute("aria-hidden", "true"); + + const guidesContainer = document.createElement("span"); + guidesContainer.className = "cm-indent-guides"; + + for (let i = 0; i < this.levels; i++) { + const guide = document.createElement("span"); + guide.className = "cm-indent-guide"; + guide.style.left = `${i * this.indentUnit}ch`; + guide.style.height = `${this.lineHeight}px`; + + if (i === this.activeGuideIndex) { + guide.classList.add("cm-indent-guide-active"); + } + + guidesContainer.appendChild(guide); + } + + container.appendChild(guidesContainer); + return container; + } + + ignoreEvent(): boolean { + return true; + } +} + +/** + * Build decorations for indent guides + */ +function buildDecorations( + view: EditorView, + config: Required, +): DecorationSet { + const builder = new RangeSetBuilder(); + const { state } = view; + const tabSize = getTabSize(state); + const indentUnit = tabSize; + + // Get active scope using syntax tree (or fallback to indentation) + const activeScope = config.highlightActiveGuide + ? getActiveScope(view, indentUnit) + : null; + + const lineHeight = view.defaultLineHeight; + + // Only process visible lines for performance + for (const { from: blockFrom, to: blockTo } of view.visibleRanges) { + const startLine = state.doc.lineAt(blockFrom); + const endLine = state.doc.lineAt(blockTo); + + for (let lineNum = startLine.number; lineNum <= endLine.number; lineNum++) { + const line = state.doc.line(lineNum); + const lineText = line.text; + + if (config.hideOnBlankLines && isBlankLine(lineText)) { + continue; + } + + const indentColumns = getLineIndentation(lineText, tabSize); + const levels = Math.floor(indentColumns / indentUnit); + + if (levels > 0) { + let activeGuideIndex = -1; + + // Check if this line is in the active scope + if ( + activeScope && + lineNum >= activeScope.startLine && + lineNum <= activeScope.endLine && + levels >= activeScope.level + ) { + activeGuideIndex = activeScope.level - 1; + } + + const widget = new IndentGuidesWidget( + levels, + indentUnit, + activeGuideIndex, + lineHeight, + ); + + const deco = Decoration.widget({ + widget, + side: -1, + }); + + builder.add(line.from, line.from, deco); + } + } + } + + return builder.finish(); +} + +/** + * ViewPlugin for indent guides + */ +function createIndentGuidesPlugin( + config: Required, +): ViewPlugin<{ + decorations: DecorationSet; + update(update: ViewUpdate): void; +}> { + return ViewPlugin.fromClass( + class { + decorations: DecorationSet; + + constructor(view: EditorView) { + this.decorations = buildDecorations(view, config); + } + + update(update: ViewUpdate): void { + // Only rebuild when necessary + if ( + update.docChanged || + update.viewportChanged || + update.geometryChanged || + (config.highlightActiveGuide && update.selectionSet) + ) { + this.decorations = buildDecorations(update.view, config); + } + } + }, + { + decorations: (v) => v.decorations, + }, + ); +} + +/** + * Theme for indent guides with subtle animation + */ +const indentGuidesTheme = EditorView.baseTheme({ + ".cm-indent-guides-wrapper": { + display: "inline", + position: "relative", + width: "0", + height: "0", + overflow: "visible", + verticalAlign: "top", + }, + ".cm-indent-guides": { + position: "absolute", + top: "0", + left: "0", + height: "100%", + pointerEvents: "none", + zIndex: "0", + }, + ".cm-indent-guide": { + position: "absolute", + top: "0", + width: "1px", + background: "var(--indent-guide-color)", + transition: "background 0.15s ease, opacity 0.15s ease", + }, + ".cm-indent-guide-active": { + background: "var(--indent-guide-active-color)", + }, + "&": { + "--indent-guide-color": "rgba(128, 128, 128, 0.25)", + "--indent-guide-active-color": "rgba(128, 128, 128, 0.7)", + }, + "&light": { + "--indent-guide-color": "rgba(0, 0, 0, 0.1)", + "--indent-guide-active-color": "rgba(0, 0, 0, 0.4)", + }, + "&dark": { + "--indent-guide-color": "rgba(255, 255, 255, 0.1)", + "--indent-guide-active-color": "rgba(255, 255, 255, 0.4)", + }, +}); + +export function indentGuides(config: IndentGuidesConfig = {}): Extension { + const mergedConfig: Required = { + ...defaultConfig, + ...config, + }; + + return [createIndentGuidesPlugin(mergedConfig), indentGuidesTheme]; +} + +export function indentGuidesExtension( + enabled: boolean, + config: IndentGuidesConfig = {}, +): Extension { + if (!enabled) return []; + return indentGuides(config); +} + +export default indentGuides; diff --git a/src/cm/lsp/clientManager.ts b/src/cm/lsp/clientManager.ts new file mode 100644 index 000000000..e59a35024 --- /dev/null +++ b/src/cm/lsp/clientManager.ts @@ -0,0 +1,1049 @@ +import { getIndentUnit, indentUnit } from "@codemirror/language"; +import type { LSPClientExtension } from "@codemirror/lsp-client"; +import { + findReferencesKeymap, + formatKeymap, + hoverTooltips, + jumpToDefinitionKeymap, + LSPClient, + LSPPlugin, + serverCompletion, + serverDiagnostics, + signatureHelp, +} from "@codemirror/lsp-client"; +import { EditorState, Extension, MapMode } from "@codemirror/state"; +import { EditorView, keymap } from "@codemirror/view"; +import lspStatusBar from "components/lspStatusBar"; +import NotificationManager from "lib/notificationManager"; +import Uri from "utils/Uri"; +import { clearDiagnosticsEffect } from "./diagnostics"; +import { documentHighlightsExtension } from "./documentHighlights"; +import { inlayHintsExtension } from "./inlayHints"; +import { acodeRenameKeymap } from "./rename"; +import { ensureServerRunning } from "./serverLauncher"; +import serverRegistry from "./serverRegistry"; +import { createTransport } from "./transport"; +import type { + BuiltinExtensionsConfig, + ClientManagerOptions, + ClientState, + EnsureServerResult, + FileMetadata, + FormattingOptions, + LspServerDefinition, + NormalizedRootUri, + ParsedUri, + RootUriContext, + TextEdit, + TransportHandle, +} from "./types"; +import AcodeWorkspace from "./workspace"; + +function asArray(value: T | T[] | null | undefined): T[] { + if (!value) return []; + return Array.isArray(value) ? value : [value]; +} + +function pluginKey( + serverId: string, + rootUri: string | null | undefined, + useWorkspaceFolders?: boolean, +): string { + // For workspace folders mode, use just the server ID (one client per server type) + if (useWorkspaceFolders) { + return serverId; + } + return `${serverId}::${rootUri ?? "__global__"}`; +} + +function safeString(value: unknown): string { + return value != null ? String(value) : ""; +} + +const defaultKeymaps = keymap.of([ + ...formatKeymap, + ...acodeRenameKeymap, + ...jumpToDefinitionKeymap, + ...findReferencesKeymap, +]); + +interface BuiltinExtensionsResult { + extensions: Extension[]; + diagnosticsExtension: Extension | LSPClientExtension | null; +} + +function buildBuiltinExtensions( + config: BuiltinExtensionsConfig = {}, +): BuiltinExtensionsResult { + const { + hover: includeHover = true, + completion: includeCompletion = true, + signature: includeSignature = true, + keymaps: includeKeymaps = true, + diagnostics: includeDiagnostics = true, + inlayHints: includeInlayHints = true, + documentHighlights: includeDocumentHighlights = true, + } = config; + + const extensions: Extension[] = []; + let diagnosticsExtension: Extension | LSPClientExtension | null = null; + + if (includeCompletion) extensions.push(serverCompletion()); + if (includeHover) extensions.push(hoverTooltips()); + if (includeKeymaps) extensions.push(defaultKeymaps); + if (includeSignature) extensions.push(signatureHelp()); + if (includeDiagnostics) { + const diagExt = serverDiagnostics(); + diagnosticsExtension = diagExt; + extensions.push(diagExt as Extension); + } + if (includeInlayHints) { + const hintsExt = inlayHintsExtension(); + extensions.push(hintsExt as LSPClientExtension as Extension); + } + if (includeDocumentHighlights) { + const highlightsExt = documentHighlightsExtension(); + extensions.push(highlightsExt as LSPClientExtension as Extension); + } + + return { extensions, diagnosticsExtension }; +} + +interface LSPError extends Error { + code?: string; +} + +interface InitContext { + key: string; + normalizedRootUri: string | null; + originalRootUri: string | null; +} + +interface ExtendedLSPClient extends LSPClient { + __acodeLoggedInfo?: boolean; +} + +export class LspClientManager { + options: ClientManagerOptions; + + #clients: Map; + #pendingClients: Map>; + + constructor(options: ClientManagerOptions = {}) { + this.options = { ...options }; + this.#clients = new Map(); + this.#pendingClients = new Map(); + } + + setOptions(next: Partial): void { + this.options = { ...this.options, ...next }; + } + + getActiveClients(): ClientState[] { + return Array.from(this.#clients.values()); + } + + async getExtensionsForFile(metadata: FileMetadata): Promise { + const { + uri: originalUri, + languageId, + languageName, + view, + file, + rootUri, + } = metadata; + + const effectiveLang = safeString(languageId ?? languageName).toLowerCase(); + if (!effectiveLang) return []; + + const servers = serverRegistry.getServersForLanguage(effectiveLang); + if (!servers.length) return []; + + // Normalize the document URI for LSP (convert content:// to file://) + let normalizedUri = normalizeDocumentUri(originalUri); + if (!normalizedUri) { + // Fall back to cache file path for unrecognized URIs + // This allows LSP to work with any file system provider using the local cache + const cacheFile = file?.cacheFile; + if (cacheFile && typeof cacheFile === "string") { + normalizedUri = buildFileUri(cacheFile.replace(/^file:\/\//, "")); + if (normalizedUri) { + console.info( + `LSP using cache path for unrecognized URI: ${originalUri} -> ${normalizedUri}`, + ); + } + } + if (!normalizedUri) { + console.warn(`Cannot normalize document URI for LSP: ${originalUri}`); + return []; + } + } + + const lspExtensions: Extension[] = []; + const diagnosticsUiExtension = this.options.diagnosticsUiExtension; + + for (const server of servers) { + let targetLanguageId = effectiveLang; + if (server.resolveLanguageId) { + try { + const resolved = server.resolveLanguageId({ + languageId: effectiveLang, + languageName, + uri: normalizedUri, + file, + }); + if (resolved) targetLanguageId = safeString(resolved); + } catch (error) { + console.warn( + `LSP server ${server.id} failed to resolve language id for ${normalizedUri}`, + error, + ); + } + } + + try { + const clientState = await this.#ensureClient(server, { + uri: normalizedUri, + file, + view, + languageId: targetLanguageId, + rootUri, + }); + const plugin = clientState.client.plugin( + normalizedUri, + targetLanguageId, + ); + clientState.attach(normalizedUri, view as EditorView); + lspExtensions.push(plugin); + } catch (error) { + const lspError = error as LSPError; + if (lspError?.code === "LSP_SERVER_UNAVAILABLE") { + console.info( + `Skipping LSP client for ${server.id}: ${lspError.message}`, + ); + continue; + } + console.error( + `Failed to initialize LSP client for ${server.id}`, + error, + ); + } + } + + if (diagnosticsUiExtension && lspExtensions.length) { + lspExtensions.push(...asArray(diagnosticsUiExtension)); + } + + return lspExtensions; + } + + async formatDocument( + metadata: FileMetadata, + options: FormattingOptions = {}, + ): Promise { + const { uri: originalUri, languageId, languageName, view, file } = metadata; + const effectiveLang = safeString(languageId ?? languageName).toLowerCase(); + if (!effectiveLang || !view) return false; + + let normalizedUri = normalizeDocumentUri(originalUri); + if (!normalizedUri) { + const cacheFile = file?.cacheFile; + if (cacheFile && typeof cacheFile === "string") { + normalizedUri = buildFileUri(cacheFile.replace(/^file:\/\//, "")); + } + if (!normalizedUri) { + console.warn( + `Cannot normalize document URI for formatting: ${originalUri}`, + ); + return false; + } + } + + const servers = serverRegistry.getServersForLanguage(effectiveLang); + if (!servers.length) return false; + + for (const server of servers) { + try { + const context: RootUriContext = { + uri: normalizedUri, + languageId: effectiveLang, + view, + file, + rootUri: metadata.rootUri, + }; + const state = await this.#ensureClient(server, context); + const capabilities = state.client.serverCapabilities; + if (!capabilities?.documentFormattingProvider) continue; + state.attach(normalizedUri, view); + const plugin = LSPPlugin.get(view); + if (!plugin) continue; + plugin.client.sync(); + const edits = await state.client.request< + { textDocument: { uri: string }; options: FormattingOptions }, + TextEdit[] | null + >("textDocument/formatting", { + textDocument: { uri: normalizedUri }, + options: buildFormattingOptions(view, options), + }); + if (!edits || !edits.length) { + plugin.client.sync(); + return true; + } + const applied = applyTextEdits(plugin, view, edits); + if (applied) { + plugin.client.sync(); + return true; + } + } catch (error) { + console.error(`LSP formatting failed for ${server.id}`, error); + } + } + return false; + } + + detach(uri: string, view: EditorView): void { + for (const state of this.#clients.values()) { + state.detach(uri, view); + } + } + + async dispose(): Promise { + try { + interface FileWithSession { + id?: string; + type?: string; + session?: EditorState; + } + + interface EditorManagerLike { + files?: FileWithSession[]; + editor?: EditorView; + activeFile?: FileWithSession; + } + + const em = (globalThis as Record).editorManager as + | EditorManagerLike + | undefined; + + if (em?.editor) { + try { + em.editor.dispatch({ effects: clearDiagnosticsEffect() }); + if (em.activeFile?.type === "editor") { + em.activeFile.session = em.editor.state; + } + } catch { + /* View may be disposed */ + } + } + + if (em?.files) { + for (const file of em.files) { + if (file?.type !== "editor" || file.id === em.activeFile?.id) + continue; + const session = file.session; + if (session && typeof session.update === "function") { + try { + file.session = session.update({ + effects: clearDiagnosticsEffect(), + }).state; + } catch { + /* State update failed */ + } + } + } + } + } catch { + /* Ignore errors */ + } + + const disposeOps: Promise[] = []; + for (const [key, state] of this.#clients.entries()) { + disposeOps.push(state.dispose()); + this.#clients.delete(key); + } + await Promise.allSettled(disposeOps); + } + + async #ensureClient( + server: LspServerDefinition, + context: RootUriContext, + ): Promise { + const useWsFolders = server.useWorkspaceFolders === true; + const resolvedRoot = await this.#resolveRootUri(server, context); + const { normalizedRootUri, originalRootUri } = normalizeRootUriForServer( + server, + resolvedRoot, + ); + + // For workspace folders mode, use a shared key based on server ID only + const key = pluginKey(server.id, normalizedRootUri, useWsFolders); + + // Return existing client if already initialized + if (this.#clients.has(key)) { + const existing = this.#clients.get(key)!; + // For workspace folders mode, add the new folder to the existing server + if (useWsFolders && normalizedRootUri) { + const workspace = existing.client.workspace as AcodeWorkspace | null; + if (workspace && !workspace.hasWorkspaceFolder(normalizedRootUri)) { + workspace.addWorkspaceFolder(normalizedRootUri); + } + } + return existing; + } + + // If initialization is already in progress, wait for it + if (this.#pendingClients.has(key)) { + return this.#pendingClients.get(key)!; + } + + // Create and track the pending initialization + const initPromise = this.#initializeClient(server, context, { + key, + normalizedRootUri: useWsFolders ? null : normalizedRootUri, + originalRootUri: useWsFolders ? null : originalRootUri, + }); + this.#pendingClients.set(key, initPromise); + + try { + return await initPromise; + } finally { + this.#pendingClients.delete(key); + } + } + + async #initializeClient( + server: LspServerDefinition, + context: RootUriContext, + initContext: InitContext, + ): Promise { + const { key, normalizedRootUri, originalRootUri } = initContext; + + const workspaceOptions = { + displayFile: this.options.displayFile, + openFile: this.options.openFile, + resolveLanguageId: this.options.resolveLanguageId, + }; + + const clientConfig = { ...(server.clientConfig ?? {}) }; + const builtinConfig = clientConfig.builtinExtensions ?? {}; + const useDefaultExtensions = clientConfig.useDefaultExtensions !== false; + const { extensions: defaultExtensions, diagnosticsExtension } = + useDefaultExtensions + ? buildBuiltinExtensions({ + hover: builtinConfig.hover !== false, + completion: builtinConfig.completion !== false, + signature: builtinConfig.signature !== false, + keymaps: builtinConfig.keymaps !== false, + diagnostics: builtinConfig.diagnostics !== false, + inlayHints: builtinConfig.inlayHints !== false, + documentHighlights: builtinConfig.documentHighlights !== false, + }) + : { extensions: [], diagnosticsExtension: null }; + + const extraExtensions = asArray(this.options.clientExtensions); + const serverExtensions = asArray(clientConfig.extensions); + + interface ExtensionWithCapabilities { + clientCapabilities?: { + textDocument?: { + publishDiagnostics?: unknown; + }; + }; + } + + const wantsCustomDiagnostics = [ + ...extraExtensions, + ...serverExtensions, + ].some((ext) => { + const extWithCaps = ext as ExtensionWithCapabilities; + return !!extWithCaps?.clientCapabilities?.textDocument + ?.publishDiagnostics; + }); + + const filteredBuiltins = + wantsCustomDiagnostics && diagnosticsExtension + ? defaultExtensions.filter((ext) => ext !== diagnosticsExtension) + : defaultExtensions; + + const progressCapabilities: LSPClientExtension = { + clientCapabilities: { + window: { + workDoneProgress: true, + }, + }, + }; + + const mergedExtensions = [ + ...filteredBuiltins, + ...extraExtensions, + ...serverExtensions, + progressCapabilities, + ]; + clientConfig.extensions = mergedExtensions; + + const existingHandlers = clientConfig.notificationHandlers ?? {}; + + type LogLevel = "error" | "warn" | "log" | "info"; + interface LogMessageParams { + type?: number; + message?: string; + } + interface ShowMessageParams { + type?: number; + message?: string; + } + + clientConfig.notificationHandlers = { + ...existingHandlers, + "window/logMessage": (_client: LSPClient, params: unknown): boolean => { + const logParams = params as LogMessageParams; + if (!logParams?.message) return false; + const { type, message } = logParams; + let level: LogLevel = "info"; + switch (type) { + case 1: + level = "error"; + break; + case 2: + level = "warn"; + break; + case 4: + level = "log"; + break; + default: + level = "info"; + } + const logFn = console[level] ?? console.info; + logFn(`[LSP:${server.id}] ${message}`); + return true; + }, + "window/showMessage": (_client: LSPClient, params: unknown): boolean => { + const showParams = params as ShowMessageParams; + if (!showParams?.message) return false; + const { type, message } = showParams; + const serverLabel = server.label || server.id; + + // Helper to clean and truncate message for notifications + const cleanMessage = (msg: string, maxLen = 150): string => { + // Take only first line + let cleaned = msg.split("\n")[0].trim(); + if (cleaned.length > maxLen) { + cleaned = cleaned.slice(0, maxLen - 3) + "..."; + } + return cleaned; + }; + + // Use notifications for errors and warnings + if (type === 1 || type === 2) { + const notificationManager = new NotificationManager(); + notificationManager.pushNotification({ + title: serverLabel, + message: cleanMessage(message), + icon: type === 1 ? "error" : "warningreport_problem", + type: type === 1 ? "error" : "warning", + }); + // Log full message to console for debugging + console.info(`[LSP:${server.id}] ${message}`); + return true; + } + + // For info/log messages, use status bar briefly + lspStatusBar.show({ + message: cleanMessage(message, 80), + title: serverLabel, + type: "info", + icon: type === 4 ? "autorenew" : "info", + duration: 5000, + }); + console.info(`[LSP:${server.id}] ${message}`); + return true; + }, + "$/progress": (_client: LSPClient, params: unknown): boolean => { + interface ProgressParams { + token?: string | number; + value?: { + kind?: "begin" | "report" | "end"; + title?: string; + message?: string; + percentage?: number; + cancellable?: boolean; + }; + } + const progressParams = params as ProgressParams; + if (!progressParams?.value) return false; + + const { kind, title, message, percentage } = progressParams.value; + const displayTitle = title || server.label || server.id; + // Use server ID + token as unique status ID for concurrent progress tracking + const progressToken = progressParams.token; + const statusId = `${server.id}-progress-${progressToken ?? "default"}`; + + if (kind === "begin") { + lspStatusBar.show({ + id: statusId, + message: message || title || "Starting...", + title: displayTitle, + type: "info", + icon: "autorenew", + duration: false, + showProgress: typeof percentage === "number", + progress: percentage, + }); + } else if (kind === "report") { + lspStatusBar.update({ + id: statusId, + message: message, + progress: percentage, + }); + } else if (kind === "end") { + // Just hide the progress item silently, no "Complete" message + lspStatusBar.hideById(statusId); + } + + console.info( + `[LSP:${server.id}] Progress: ${kind} - ${message || title || ""} ${typeof percentage === "number" ? `(${percentage}%)` : ""}`, + ); + return true; + }, + "$/typescriptVersion": (_client: LSPClient, params: unknown): boolean => { + interface TypeScriptVersionParams { + version?: string; + source?: string; + } + const versionParams = params as TypeScriptVersionParams; + if (!versionParams?.version) return false; + + const serverLabel = server.label || server.id; + const source = versionParams.source || "bundled"; + console.info( + `[LSP:${server.id}] TypeScript ${versionParams.version} (${source})`, + ); + + // Show briefly in status bar + lspStatusBar.show({ + message: `TypeScript ${versionParams.version}`, + title: serverLabel, + type: "info", + icon: "code", + duration: 3000, + }); + return true; + }, + }; + + // Log unhandled notifications to help debug what servers are sending + const unhandledNotificationKey = + "unhandledNotification" as keyof typeof clientConfig; + if (!(unhandledNotificationKey in clientConfig)) { + ( + clientConfig as Record< + string, + (client: LSPClient, method: string, params: unknown) => void + > + ).unhandledNotification = ( + _client: LSPClient, + method: string, + params: unknown, + ) => { + console.info( + `[LSP:${server.id}] Unhandled notification: ${method}`, + params, + ); + }; + } + + if (!clientConfig.workspace) { + clientConfig.workspace = (client: LSPClient) => + new AcodeWorkspace(client, workspaceOptions); + } + + if (normalizedRootUri && !clientConfig.rootUri) { + clientConfig.rootUri = normalizedRootUri; + } + + if (!normalizedRootUri && clientConfig.rootUri) { + delete clientConfig.rootUri; + } + + if (server.startupTimeout && !clientConfig.timeout) { + clientConfig.timeout = server.startupTimeout; + } + + let transportHandle: TransportHandle | undefined; + let client: ExtendedLSPClient | undefined; + + try { + // Get session from server ID for auto-port discovery + const session = server.id; + const serverResult = await ensureServerRunning(server, session); + + // Use discovered port if available (for auto-port discovery) + const dynamicPort = serverResult.discoveredPort; + + transportHandle = createTransport(server, { + ...context, + rootUri: normalizedRootUri ?? null, + originalRootUri: originalRootUri ?? undefined, + dynamicPort, + }); + await transportHandle.ready; + client = new LSPClient(clientConfig) as ExtendedLSPClient; + client.connect(transportHandle.transport); + await client.initializing; + if (!client.__acodeLoggedInfo) { + // Log root URI info to console + if (normalizedRootUri) { + if (originalRootUri && originalRootUri !== normalizedRootUri) { + console.info( + `[LSP:${server.id}] root ${normalizedRootUri} (from ${originalRootUri})`, + ); + } else { + console.info(`[LSP:${server.id}] root`, normalizedRootUri); + } + } else if (originalRootUri) { + console.info(`[LSP:${server.id}] root ignored`, originalRootUri); + } + console.info(`[LSP:${server.id}] initialized`); + client.__acodeLoggedInfo = true; + } + } catch (error) { + transportHandle?.dispose?.(); + throw error; + } + + const state = this.#createClientState({ + key, + server, + client, + transportHandle, + normalizedRootUri, + originalRootUri, + }); + + this.#clients.set(key, state); + return state; + } + + #createClientState(params: { + key: string; + server: LspServerDefinition; + client: LSPClient; + transportHandle: TransportHandle; + normalizedRootUri: string | null; + originalRootUri: string | null; + }): ClientState { + const { + key, + server, + client, + transportHandle, + normalizedRootUri, + originalRootUri, + } = params; + const fileRefs = new Map>(); + const effectiveRoot = normalizedRootUri ?? originalRootUri ?? null; + + const attach = (uri: string, view: EditorView): void => { + const existing = fileRefs.get(uri) ?? new Set(); + existing.add(view); + fileRefs.set(uri, existing); + const suffix = effectiveRoot ? ` (root ${effectiveRoot})` : ""; + console.info(`[LSP:${server.id}] attached to ${uri}${suffix}`); + }; + + const detach = (uri: string, view?: EditorView): void => { + const existing = fileRefs.get(uri); + if (!existing) return; + if (view) existing.delete(view); + if (!view || !existing.size) { + fileRefs.delete(uri); + try { + // Only pass uri to closeFile - view is not needed for closing + // and passing it may cause issues if the view is already disposed + (client.workspace as AcodeWorkspace)?.closeFile?.(uri); + } catch (error) { + console.warn(`Failed to close LSP file ${uri}`, error); + } + } + + if (!fileRefs.size) { + this.options.onClientIdle?.({ + server, + client, + rootUri: effectiveRoot, + }); + } + }; + + const dispose = async (): Promise => { + try { + client.disconnect(); + } catch (error) { + console.warn(`Error disconnecting LSP client ${server.id}`, error); + } + try { + await transportHandle.dispose?.(); + } catch (error) { + console.warn(`Error disposing LSP transport ${server.id}`, error); + } + this.#clients.delete(key); + }; + + return { + server, + client, + transport: transportHandle, + rootUri: effectiveRoot, + attach, + detach, + dispose, + }; + } + + async #resolveRootUri( + server: LspServerDefinition, + context: RootUriContext, + ): Promise { + if (context?.rootUri) return context.rootUri; + + if (typeof server.rootUri === "function") { + try { + const value = await server.rootUri(context?.uri ?? "", context); + if (value) return safeString(value); + } catch (error) { + console.warn(`Server root resolver failed for ${server.id}`, error); + } + } + + if (typeof this.options.resolveRoot === "function") { + try { + const value = await this.options.resolveRoot(context); + if (value) return safeString(value); + } catch (error) { + console.warn("Global LSP root resolver failed", error); + } + } + + return null; + } +} + +interface Change { + from: number; + to: number; + insert: string; +} + +function applyTextEdits( + plugin: LSPPlugin, + view: EditorView, + edits: TextEdit[], +): boolean { + const changes: Change[] = []; + for (const edit of edits) { + if (!edit?.range) continue; + let fromBase: number; + let toBase: number; + try { + fromBase = plugin.fromPosition(edit.range.start, plugin.syncedDoc); + toBase = plugin.fromPosition(edit.range.end, plugin.syncedDoc); + } catch (_) { + continue; + } + const fromResult = plugin.unsyncedChanges.mapPos( + fromBase, + 1, + MapMode.TrackDel, + ); + const toResult = plugin.unsyncedChanges.mapPos( + toBase, + -1, + MapMode.TrackDel, + ); + if (fromResult == null || toResult == null) continue; + const insert = + typeof edit.newText === "string" + ? edit.newText.replace(/\r\n/g, "\n") + : ""; + changes.push({ from: fromResult, to: toResult, insert }); + } + if (!changes.length) return false; + changes.sort((a, b) => a.from - b.from || a.to - b.to); + view.dispatch({ changes }); + return true; +} + +function buildFormattingOptions( + view: EditorView, + overrides: FormattingOptions = {}, +): FormattingOptions { + const state = view?.state; + if (!state) return { ...overrides }; + + const unitValue = state.facet(indentUnit); + const unit = + typeof unitValue === "string" && unitValue.length + ? unitValue + : String(unitValue ?? "\t"); + let tabSize = getIndentUnit(state); + if ( + typeof tabSize !== "number" || + !Number.isFinite(tabSize) || + tabSize <= 0 + ) { + tabSize = resolveIndentWidth(unit); + } + const insertSpaces = !unit.includes("\t"); + + return { + tabSize, + insertSpaces, + ...overrides, + }; +} + +function resolveIndentWidth(unit: string): number { + if (typeof unit !== "string" || !unit.length) return 4; + let width = 0; + for (const ch of unit) { + if (ch === "\t") return 4; + width += 1; + } + return width || 4; +} + +const defaultManager = new LspClientManager(); + +export default defaultManager; + +function normalizeRootUriForServer( + _server: LspServerDefinition, + rootUri: string | null, +): NormalizedRootUri { + if (!rootUri || typeof rootUri !== "string") { + return { normalizedRootUri: null, originalRootUri: null }; + } + const schemeMatch = /^([a-zA-Z][\w+\-.]*):/.exec(rootUri); + const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null; + + // Already a file:// URI - use as-is + if (scheme === "file") { + return { normalizedRootUri: rootUri, originalRootUri: rootUri }; + } + + // Try to convert content:// URIs to file:// URIs + if (scheme === "content") { + const fileUri = contentUriToFileUri(rootUri); + if (fileUri) { + return { normalizedRootUri: fileUri, originalRootUri: rootUri }; + } + // Can't convert to file:// - server won't work properly + return { normalizedRootUri: null, originalRootUri: rootUri }; + } + + // Unknown scheme - try to use as-is + return { normalizedRootUri: rootUri, originalRootUri: rootUri }; +} + +function normalizeDocumentUri(uri: string | null | undefined): string | null { + if (!uri || typeof uri !== "string") return null; + + const schemeMatch = /^([a-zA-Z][\w+\-.]*):/.exec(uri); + const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null; + + // Already a file:// URI or untitled use as-is + if (scheme === "file" || scheme === "untitled") { + return uri; + } + + // Convert content:// URIs to file:// URIs + if (scheme === "content") { + const fileUri = contentUriToFileUri(uri); + if (fileUri) { + return fileUri; + } + return null; + } + + // Unknown scheme + return uri; +} + +function contentUriToFileUri(uri: string): string | null { + try { + const parsed = Uri.parse(uri) as ParsedUri | null; + if (!parsed || typeof parsed !== "object") return null; + const { docId, rootUri, isFileUri } = parsed; + if (!docId) return null; + + if (isFileUri && rootUri) { + return rootUri; + } + + const providerMatch = + /^content:\/\/com\.((?![:<>"/\\|?*]).*?)\.documents\//.exec( + rootUri ?? "", + ); + const providerId = providerMatch ? providerMatch[1] : null; + + let normalized = docId.trim(); + if (!normalized) return null; + + switch (providerId) { + case "foxdebug.acode": + case "foxdebug.acodefree": + normalized = normalized.replace(/:+$/, ""); + if (!normalized) return null; + if (normalized.startsWith("raw:/")) { + normalized = normalized.slice(4); + } else if (normalized.startsWith("raw:")) { + normalized = normalized.slice(4); + } + if (!normalized.startsWith("/")) return null; + return buildFileUri(normalized); + case "android.externalstorage": + normalized = normalized.replace(/:+$/, ""); + if (!normalized) return null; + + if (normalized.startsWith("/")) { + return buildFileUri(normalized); + } + + if (normalized.startsWith("raw:/")) { + return buildFileUri(normalized.slice(4)); + } + + if (normalized.startsWith("raw:")) { + return buildFileUri(normalized.slice(4)); + } + + const separator = normalized.indexOf(":"); + if (separator === -1) return null; + + const root = normalized.slice(0, separator); + const remainder = normalized.slice(separator + 1); + if (!remainder) return null; + + switch (root) { + case "primary": + return buildFileUri(`/storage/emulated/0/${remainder}`); + default: + if (/^[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}$/.test(root)) { + return buildFileUri(`/storage/${root}/${remainder}`); + } + } + return null; + default: + return null; + } + } catch (_) { + return null; + } +} + +function buildFileUri(pathname: string): string | null { + if (!pathname) return null; + const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`; + const encoded = encodeURI(normalized).replace(/#/g, "%23"); + return `file://${encoded}`; +} diff --git a/src/cm/lsp/codeActions.ts b/src/cm/lsp/codeActions.ts new file mode 100644 index 000000000..2570f56bb --- /dev/null +++ b/src/cm/lsp/codeActions.ts @@ -0,0 +1,418 @@ +import { LSPPlugin } from "@codemirror/lsp-client"; +import { EditorView } from "@codemirror/view"; +import toast from "components/toast"; +import select from "dialogs/select"; +import type { + CodeAction, + CodeActionContext, + CodeActionKind, + Command, + Diagnostic, + Range as LspRange, + WorkspaceEdit, +} from "vscode-languageserver-types"; +import type { Position, Range } from "./types"; +import type AcodeWorkspace from "./workspace"; + +type CodeActionResponse = (CodeAction | Command)[] | null; + +const CODE_ACTION_KINDS = { + QUICK_FIX: "quickfix", + REFACTOR: "refactor", + REFACTOR_EXTRACT: "refactor.extract", + REFACTOR_INLINE: "refactor.inline", + REFACTOR_REWRITE: "refactor.rewrite", + SOURCE: "source", + SOURCE_ORGANIZE_IMPORTS: "source.organizeImports", + SOURCE_FIX_ALL: "source.fixAll", +} as const; + +const CODE_ACTION_ICONS: Record = { + quickfix: "build", + refactor: "code", + "refactor.extract": "call_split", + "refactor.inline": "call_merge", + "refactor.rewrite": "edit", + source: "settings", + "source.organizeImports": "sort", + "source.fixAll": "done_all", +}; + +function getCodeActionIcon(kind?: CodeActionKind): string { + if (!kind) return "licons zap"; + for (const [prefix, icon] of Object.entries(CODE_ACTION_ICONS)) { + if (kind.startsWith(prefix)) return icon; + } + return "licons zap"; +} + +function formatCodeActionKind(kind?: CodeActionKind): string { + if (!kind) return ""; + return kind + .split(".") + .map((p) => p.charAt(0).toUpperCase() + p.slice(1)) + .join(" › "); +} + +function isCommand(item: CodeAction | Command): item is Command { + return ( + "command" in item && typeof item.command === "string" && !("edit" in item) + ); +} + +function lspPositionToOffset( + doc: { line: (n: number) => { from: number } }, + pos: Position, +): number { + return doc.line(pos.line + 1).from + pos.character; +} + +async function requestCodeActions( + plugin: LSPPlugin, + range: LspRange, + diagnostics: Diagnostic[] = [], +): Promise { + const context: CodeActionContext = { + diagnostics, + triggerKind: 1, // CodeActionTriggerKind.Invoked + }; + + return plugin.client.request< + { + textDocument: { uri: string }; + range: LspRange; + context: CodeActionContext; + }, + CodeActionResponse + >("textDocument/codeAction", { + textDocument: { uri: plugin.uri }, + range, + context, + }); +} + +async function resolveCodeAction( + plugin: LSPPlugin, + action: CodeAction, +): Promise { + // If action already has an edit, no need to resolve + if (action.edit) return action; + + const capabilities = plugin.client.serverCapabilities; + const provider = capabilities?.codeActionProvider; + const supportsResolve = + typeof provider === "object" && + provider !== null && + "resolveProvider" in provider && + provider.resolveProvider === true; + + if (!supportsResolve) return action; + + // Resolve to get the edit property (lazy computation per LSP 3.16+) + try { + const resolved = await plugin.client.request( + "codeAction/resolve", + action, + ); + return resolved ?? action; + } catch (error) { + console.warn("[LSP:CodeAction] Failed to resolve:", error); + return action; + } +} + +async function executeCommand( + plugin: LSPPlugin, + command: Command, +): Promise { + try { + await plugin.client.request< + { command: string; arguments?: unknown[] }, + unknown + >("workspace/executeCommand", { + command: command.command, + arguments: command.arguments, + }); + return true; + } catch (error) { + // -32601 = Method not implemented (expected for some LSP servers) + const lspError = error as { code?: number }; + if (lspError?.code !== -32601) { + console.warn("[LSP:CodeAction] Command execution failed:", error); + } + return false; + } +} + +interface LspChange { + range: Range; + newText: string; +} + +async function applyChangesToFile( + workspace: AcodeWorkspace, + uri: string, + changes: LspChange[], + mapping: { mapPosition: (uri: string, pos: Position) => number }, +): Promise { + const file = workspace.getFile(uri); + if (file) { + const view = file.getView(); + if (view) { + view.dispatch({ + changes: changes.map((c) => ({ + from: mapping.mapPosition(uri, c.range.start), + to: mapping.mapPosition(uri, c.range.end), + insert: c.newText, + })), + userEvent: "codeAction", + }); + return true; + } + } + + const displayedView = await workspace.displayFile(uri); + if (!displayedView?.state?.doc) { + console.warn(`[LSP:CodeAction] Could not open file: ${uri}`); + return false; + } + + displayedView.dispatch({ + changes: changes.map((c) => ({ + from: lspPositionToOffset(displayedView.state.doc, c.range.start), + to: lspPositionToOffset(displayedView.state.doc, c.range.end), + insert: c.newText, + })), + userEvent: "codeAction", + }); + return true; +} + +async function applyWorkspaceEdit( + view: EditorView, + edit: WorkspaceEdit, +): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) return false; + + const workspace = plugin.client.workspace as AcodeWorkspace; + if (!workspace) return false; + + let filesChanged = 0; + + const result = await plugin.client.withMapping(async (mapping) => { + // Handle simple changes format + if (edit.changes) { + for (const uri in edit.changes) { + const changes = edit.changes[uri] as LspChange[]; + if ( + changes.length && + (await applyChangesToFile(workspace, uri, changes, mapping)) + ) { + filesChanged++; + } + } + } + + // Handle documentChanges format (supports versioned edits) + if (edit.documentChanges) { + for (const docChange of edit.documentChanges) { + if ("textDocument" in docChange && "edits" in docChange) { + const uri = docChange.textDocument.uri; + const edits = docChange.edits as LspChange[]; + if ( + edits.length && + (await applyChangesToFile(workspace, uri, edits, mapping)) + ) { + filesChanged++; + } + } + } + } + return filesChanged; + }); + + return (result ?? 0) > 0; +} + +/** + * Apply a code action following the LSP spec: + * "If both edit and command are supplied, first the edit is applied, then the command is executed" + */ +async function applyCodeAction( + view: EditorView, + action: CodeAction, +): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) return false; + + plugin.client.sync(); + + // Resolve to get the edit if not already present + const resolved = await resolveCodeAction(plugin, action); + let success = false; + + // Step 1: Apply workspace edit if present + if (resolved.edit) { + success = await applyWorkspaceEdit(view, resolved.edit); + } + + // Step 2: Execute command if present (after edit per LSP spec) + if (resolved.command) { + const commandSuccess = await executeCommand(plugin, resolved.command); + success = success || commandSuccess; + } + + plugin.client.sync(); + return success; +} + +export interface CodeActionItem { + title: string; + kind?: CodeActionKind; + icon: string; + isPreferred?: boolean; + disabled?: boolean; + disabledReason?: string; + action: CodeAction | Command; +} + +export async function fetchCodeActions( + view: EditorView, +): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) return []; + + const capabilities = plugin.client.serverCapabilities; + if (!capabilities?.codeActionProvider) return []; + + const { from, to } = view.state.selection.main; + const range: LspRange = { + start: plugin.toPosition(from), + end: plugin.toPosition(to), + }; + + plugin.client.sync(); + + try { + const response = await requestCodeActions(plugin, range); + if (!response?.length) return []; + + const items: CodeActionItem[] = response.map((item) => { + if (isCommand(item)) { + return { title: item.title, icon: "terminal", action: item }; + } + return { + title: item.title, + kind: item.kind, + icon: getCodeActionIcon(item.kind), + isPreferred: item.isPreferred, + disabled: !!item.disabled, + disabledReason: item.disabled?.reason, + action: item, + }; + }); + + // Sort: preferred first, then quickfixes, then alphabetically + items.sort((a, b) => { + if (a.isPreferred && !b.isPreferred) return -1; + if (!a.isPreferred && b.isPreferred) return 1; + if (a.kind?.startsWith("quickfix") && !b.kind?.startsWith("quickfix")) + return -1; + if (!a.kind?.startsWith("quickfix") && b.kind?.startsWith("quickfix")) + return 1; + return a.title.localeCompare(b.title); + }); + + return items; + } catch (error) { + console.error("[LSP:CodeAction] Failed to fetch:", error); + return []; + } +} + +export async function executeCodeAction( + view: EditorView, + item: CodeActionItem, +): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) return false; + + try { + plugin.client.sync(); + + // Handle standalone Command (not CodeAction) + if (isCommand(item.action)) { + return executeCommand(plugin, item.action); + } + + // Handle CodeAction + return applyCodeAction(view, item.action); + } catch (error) { + console.error("[LSP:CodeAction] Failed to execute:", error); + return false; + } +} + +export function supportsCodeActions(view: EditorView): boolean { + const plugin = LSPPlugin.get(view); + return !!plugin?.client.serverCapabilities?.codeActionProvider; +} + +export async function showCodeActionsMenu(view: EditorView): Promise { + if (!supportsCodeActions(view)) return false; + + const items = await fetchCodeActions(view); + if (!items.length) { + toast("No code actions available"); + return false; + } + + const selectItems = items.map((item, i) => ({ + value: String(i), + text: item.title, + icon: item.icon, + disabled: item.disabled, + })); + + try { + const result = await select( + strings["code actions"] || "Code Actions", + selectItems as unknown as string[], + { hideOnSelect: true }, + ); + + if (result !== null && result !== undefined) { + const index = Number.parseInt(String(result), 10); + if (!Number.isNaN(index) && index >= 0 && index < items.length) { + await executeCodeAction(view, items[index]); + view.focus(); + return true; + } + } + } catch { + // User cancelled selection + } + + view.focus(); + return false; +} + +export async function performQuickFix(view: EditorView): Promise { + const items = await fetchCodeActions(view); + if (!items.length) return false; + + // Find preferred action or first quickfix + const quickFix = + items.find((i) => i.isPreferred) ?? + items.find((i) => i.kind?.startsWith("quickfix")); + + if (quickFix) { + return executeCodeAction(view, quickFix); + } + + // Fall back to showing menu + return showCodeActionsMenu(view); +} + +export { CODE_ACTION_KINDS, getCodeActionIcon, formatCodeActionKind }; diff --git a/src/cm/lsp/diagnostics.ts b/src/cm/lsp/diagnostics.ts new file mode 100644 index 000000000..c442bec3a --- /dev/null +++ b/src/cm/lsp/diagnostics.ts @@ -0,0 +1,252 @@ +import { Diagnostic, forceLinting, linter, lintGutter } from "@codemirror/lint"; +import type { LSPClient } from "@codemirror/lsp-client"; +import { LSPPlugin } from "@codemirror/lsp-client"; +import type { Extension } from "@codemirror/state"; +import { + EditorState, + MapMode, + StateEffect, + StateField, +} from "@codemirror/state"; +import type { EditorView } from "@codemirror/view"; +import type { + LSPClientWithWorkspace, + LSPPluginAPI, + LspDiagnostic, + PublishDiagnosticsParams, + RawDiagnostic, +} from "./types"; + +const setPublishedDiagnostics = StateEffect.define(); + +export const LSP_DIAGNOSTICS_EVENT = "acode:lsp-diagnostics-updated"; + +function emitDiagnosticsUpdated(): void { + if ( + typeof document === "undefined" || + typeof document.dispatchEvent !== "function" + ) { + return; + } + + let event: CustomEvent | Event; + try { + event = new CustomEvent(LSP_DIAGNOSTICS_EVENT); + } catch (_) { + try { + event = document.createEvent("CustomEvent"); + (event as CustomEvent).initCustomEvent( + LSP_DIAGNOSTICS_EVENT, + false, + false, + undefined, + ); + } catch (_) { + return; + } + } + + document.dispatchEvent(event); +} + +const lspPublishedDiagnostics = StateField.define({ + create(): LspDiagnostic[] { + return []; + }, + update(value: LspDiagnostic[], tr): LspDiagnostic[] { + for (const effect of tr.effects) { + if (effect.is(setPublishedDiagnostics)) { + value = effect.value; + } + } + return value; + }, +}); + +type DiagnosticSeverity = "error" | "warning" | "info" | "hint"; +const severities: DiagnosticSeverity[] = [ + "hint", + "error", + "warning", + "info", + "hint", +]; + +function storeLspDiagnostics( + plugin: LSPPluginAPI, + diagnostics: RawDiagnostic[], +): StateEffect { + const items: LspDiagnostic[] = []; + const { syncedDoc } = plugin; + + for (const diagnostic of diagnostics) { + let from: number; + let to: number; + try { + const mappedFrom = plugin.fromPosition( + diagnostic.range.start, + plugin.syncedDoc, + ); + const mappedTo = plugin.fromPosition( + diagnostic.range.end, + plugin.syncedDoc, + ); + const fromResult = plugin.unsyncedChanges.mapPos(mappedFrom); + const toResult = plugin.unsyncedChanges.mapPos(mappedTo); + if (fromResult === null || toResult === null) continue; + from = fromResult; + to = toResult; + } catch (_) { + continue; + } + if (to > syncedDoc.length) continue; + + const severity = severities[diagnostic.severity ?? 0] ?? "info"; + const source = diagnostic.code + ? `${diagnostic.source ? `${diagnostic.source}-` : ""}${diagnostic.code}` + : undefined; + + items.push({ + from, + to, + severity, + message: diagnostic.message, + source, + }); + } + + return setPublishedDiagnostics.of(items); +} + +function mapDiagnostics( + plugin: LSPPluginAPI, + state: EditorState, +): Diagnostic[] { + plugin.client.sync(); + const stored = state.field(lspPublishedDiagnostics); + const changes = plugin.unsyncedChanges; + const mapped: Diagnostic[] = []; + + for (const diagnostic of stored) { + let from: number | null; + let to: number | null; + try { + from = changes.mapPos(diagnostic.from, 1, MapMode.TrackDel); + to = changes.mapPos(diagnostic.to, -1, MapMode.TrackDel); + } catch (_) { + continue; + } + if (from != null && to != null) { + mapped.push({ ...diagnostic, from, to }); + } + } + + return mapped; +} + +function lspLinterSource(view: EditorView): Diagnostic[] { + const plugin = LSPPlugin.get(view) as LSPPluginAPI | null; + if (!plugin) return []; + return mapDiagnostics(plugin, view.state); +} + +export function lspDiagnosticsClientExtension(): { + clientCapabilities: Record; + notificationHandlers: Record< + string, + (client: LSPClient, params: PublishDiagnosticsParams) => boolean + >; +} { + return { + clientCapabilities: { + textDocument: { + publishDiagnostics: { + relatedInformation: true, + codeDescriptionSupport: true, + dataSupport: true, + versionSupport: true, + }, + }, + }, + notificationHandlers: { + "textDocument/publishDiagnostics": ( + client: LSPClient, + params: PublishDiagnosticsParams, + ): boolean => { + const clientWithWorkspace = client as unknown as LSPClientWithWorkspace; + const file = clientWithWorkspace.workspace.getFile(params.uri); + if ( + !file || + (params.version != null && params.version !== file.version) + ) { + return false; + } + const view = file.getView(); + if (!view) return false; + const plugin = LSPPlugin.get(view) as LSPPluginAPI | null; + if (!plugin) return false; + + view.dispatch({ + effects: storeLspDiagnostics(plugin, params.diagnostics), + }); + forceLinting(view); + emitDiagnosticsUpdated(); + return true; + }, + }, + }; +} + +export function lspDiagnosticsUiExtension(includeGutter = true): Extension[] { + const extensions: Extension[] = [ + lspPublishedDiagnostics, + linter(lspLinterSource, { + needsRefresh(update) { + return update.transactions.some((tr) => + tr.effects.some((effect) => effect.is(setPublishedDiagnostics)), + ); + }, + // keep panel closed by default + autoPanel: false, + }), + ]; + if (includeGutter) { + extensions.splice(1, 0, lintGutter()); + } + return extensions; +} + +interface DiagnosticsExtension { + clientCapabilities: Record; + notificationHandlers: Record< + string, + (client: LSPClient, params: PublishDiagnosticsParams) => boolean + >; + editorExtension: Extension[]; +} + +export function lspDiagnosticsExtension( + includeGutter = true, +): DiagnosticsExtension { + return { + ...lspDiagnosticsClientExtension(), + editorExtension: lspDiagnosticsUiExtension(includeGutter), + }; +} + +export default lspDiagnosticsExtension; + +export function clearDiagnosticsEffect(): StateEffect { + return setPublishedDiagnostics.of([]); +} + +export function getLspDiagnostics(state: EditorState | null): LspDiagnostic[] { + if (!state || typeof state.field !== "function") return []; + try { + const stored = state.field(lspPublishedDiagnostics, false); + if (!stored || !Array.isArray(stored)) return []; + return stored.map((diagnostic) => ({ ...diagnostic })); + } catch (_) { + return []; + } +} diff --git a/src/cm/lsp/documentHighlights.ts b/src/cm/lsp/documentHighlights.ts new file mode 100644 index 000000000..141b3ac76 --- /dev/null +++ b/src/cm/lsp/documentHighlights.ts @@ -0,0 +1,320 @@ +/** + * LSP Document Highlights Extension for CodeMirror + * + * Highlights all occurrences of the word under cursor using LSP documentHighlight request. + * Supports read/write distinction for variables (e.g., assignments vs. references). + */ + +import type { LSPClient, LSPClientExtension } from "@codemirror/lsp-client"; +import { LSPPlugin } from "@codemirror/lsp-client"; +import type { Extension, Range } from "@codemirror/state"; +import { RangeSet, StateEffect, StateField } from "@codemirror/state"; +import { + Decoration, + type DecorationSet, + EditorView, + ViewPlugin, + type ViewUpdate, +} from "@codemirror/view"; +import type { + DocumentHighlight, + DocumentHighlightKind, + Position, +} from "vscode-languageserver-types"; +import type { LSPPluginAPI } from "./types"; + +/** + * LSP DocumentHighlightKind + * 1 = Text (general highlight) + * 2 = Read (read access of a symbol) + * 3 = Write (write access of a symbol) + */ + +interface DocumentHighlightParams { + textDocument: { uri: string }; + position: Position; +} + +interface ProcessedHighlight { + from: number; + to: number; + kind: DocumentHighlightKind; +} + +export interface DocumentHighlightsConfig { + /** Whether to enable document highlights. Default: true */ + enabled?: boolean; + /** Debounce delay in milliseconds. Default: 150ms */ + debounceMs?: number; + /** Show different colors for read vs write. Default: true */ + distinguishReadWrite?: boolean; +} + +// DocumentHighlightKind constants +const HIGHLIGHT_TEXT = 1 as const; +const HIGHLIGHT_READ = 2 as const; +const HIGHLIGHT_WRITE = 3 as const; + +const setHighlights = StateEffect.define(); + +const highlightsField = StateField.define({ + create: () => [], + update(highlights, tr) { + for (const e of tr.effects) { + if (e.is(setHighlights)) return e.value; + } + // Clear highlights on doc change (will be refreshed by plugin) + if (tr.docChanged) return []; + return highlights; + }, +}); + +const textMark = Decoration.mark({ class: "cm-lsp-highlight" }); +const readMark = Decoration.mark({ + class: "cm-lsp-highlight cm-lsp-highlight-read", +}); +const writeMark = Decoration.mark({ + class: "cm-lsp-highlight cm-lsp-highlight-write", +}); + +function getMarkForKind( + kind: DocumentHighlightKind, + distinguishReadWrite: boolean, +): typeof textMark { + if (!distinguishReadWrite) return textMark; + switch (kind) { + case HIGHLIGHT_READ: + return readMark; + case HIGHLIGHT_WRITE: + return writeMark; + default: + return textMark; + } +} + +function buildDecos( + highlights: ProcessedHighlight[], + docLen: number, + distinguishReadWrite: boolean, +): DecorationSet { + if (!highlights.length) return Decoration.none; + + const decos: Range[] = []; + for (const h of highlights) { + if (h.from < 0 || h.to > docLen || h.from >= h.to) continue; + decos.push( + getMarkForKind(h.kind, distinguishReadWrite).range(h.from, h.to), + ); + } + // Sort by position for RangeSet + decos.sort((a, b) => a.from - b.from || a.to - b.to); + return RangeSet.of(decos); +} + +function createPlugin(config: DocumentHighlightsConfig) { + const delay = config.debounceMs ?? 150; + const distinguishReadWrite = config.distinguishReadWrite !== false; + + return ViewPlugin.fromClass( + class { + decorations: DecorationSet = Decoration.none; + timer: ReturnType | null = null; + reqId = 0; + lastPos = -1; + + constructor(private view: EditorView) {} + + update(update: ViewUpdate): void { + // Rebuild decorations if highlights changed + if ( + update.transactions.some((t) => + t.effects.some((e) => e.is(setHighlights)), + ) + ) { + this.decorations = buildDecos( + update.state.field(highlightsField, false) ?? [], + update.state.doc.length, + distinguishReadWrite, + ); + } + + // Schedule fetch on selection or doc change + if (update.docChanged || update.selectionSet) { + this.schedule(); + } + } + + schedule(): void { + if (this.timer) clearTimeout(this.timer); + this.timer = setTimeout(() => { + this.timer = null; + this.fetch(); + }, delay); + } + + async fetch(): Promise { + const lsp = LSPPlugin.get(this.view) as LSPPluginAPI | null; + if (!lsp?.client.connected) { + this.clear(); + return; + } + + const caps = lsp.client.serverCapabilities; + if (!caps?.documentHighlightProvider) { + this.clear(); + return; + } + + // Get current cursor position + const selection = this.view.state.selection.main; + const pos = selection.head; + + // Skip if position hasn't changed (and no doc changes) + if (pos === this.lastPos) return; + this.lastPos = pos; + + // Don't highlight if there's a selection range + if (!selection.empty) { + this.clear(); + return; + } + + lsp.client.sync(); + const id = ++this.reqId; + + try { + const highlights = await lsp.client.request< + DocumentHighlightParams, + DocumentHighlight[] | null + >("textDocument/documentHighlight", { + textDocument: { uri: lsp.uri }, + position: lsp.toPosition(pos), + }); + + // Stale request check + if (id !== this.reqId) return; + + if (!highlights || !highlights.length) { + this.clear(); + return; + } + + const processed = this.process(lsp, highlights); + this.view.dispatch({ effects: setHighlights.of(processed) }); + } catch { + // Non-critical - silently ignore + this.clear(); + } + } + + process( + lsp: LSPPluginAPI, + highlights: DocumentHighlight[], + ): ProcessedHighlight[] { + const result: ProcessedHighlight[] = []; + const doc = this.view.state.doc; + + for (const h of highlights) { + let from: number; + let to: number; + try { + from = lsp.fromPosition(h.range.start, lsp.syncedDoc); + to = lsp.fromPosition(h.range.end, lsp.syncedDoc); + + // Map through unsynced changes + const mappedFrom = lsp.unsyncedChanges.mapPos(from); + const mappedTo = lsp.unsyncedChanges.mapPos(to); + if (mappedFrom === null || mappedTo === null) continue; + from = mappedFrom; + to = mappedTo; + } catch { + continue; + } + + if (from < 0 || to > doc.length || from >= to) continue; + + result.push({ + from, + to, + kind: h.kind ?? HIGHLIGHT_TEXT, + }); + } + + return result.sort((a, b) => a.from - b.from); + } + + clear(): void { + const current = this.view.state.field(highlightsField, false); + if (current && current.length > 0) { + this.view.dispatch({ effects: setHighlights.of([]) }); + } + } + + destroy(): void { + if (this.timer) clearTimeout(this.timer); + } + }, + { decorations: (v) => v.decorations }, + ); +} + +const styles = EditorView.baseTheme({ + // Base highlight style (for text/unspecified kind) + ".cm-lsp-highlight": { + backgroundColor: "rgba(150, 150, 150, 0.2)", + borderRadius: "2px", + }, + // Read access highlight (slightly lighter) + "&light .cm-lsp-highlight-read": { + backgroundColor: "rgba(121, 196, 142, 0.25)", + }, + "&dark .cm-lsp-highlight-read": { + backgroundColor: "rgba(121, 196, 142, 0.15)", + }, + // Write access highlight (more prominent) + "&light .cm-lsp-highlight-write": { + backgroundColor: "rgba(196, 121, 121, 0.25)", + }, + "&dark .cm-lsp-highlight-write": { + backgroundColor: "rgba(196, 121, 121, 0.15)", + }, +}); + +/** + * Client extension that adds documentHighlight capabilities to the LSP client. + */ +export function documentHighlightsClientExtension(): LSPClientExtension { + return { + clientCapabilities: { + textDocument: { + documentHighlight: { + dynamicRegistration: true, + }, + }, + }, + }; +} + +/** + * Editor extension that handles document highlights display. + */ +export function documentHighlightsEditorExtension( + config: DocumentHighlightsConfig = {}, +): Extension { + if (config.enabled === false) return []; + return [highlightsField, createPlugin(config), styles]; +} + +/** + * Combined extension for document highlights. + */ +export function documentHighlightsExtension( + config: DocumentHighlightsConfig = {}, +): LSPClientExtension & { editorExtension: Extension } { + return { + ...documentHighlightsClientExtension(), + editorExtension: documentHighlightsEditorExtension(config), + }; +} + +export default documentHighlightsExtension; diff --git a/src/cm/lsp/documentSymbols.ts b/src/cm/lsp/documentSymbols.ts new file mode 100644 index 000000000..8e4dc3d92 --- /dev/null +++ b/src/cm/lsp/documentSymbols.ts @@ -0,0 +1,338 @@ +/** + * LSP Document Symbols Extension for CodeMirror + * + * Provides document symbol information (functions, classes, variables, etc.) from language servers. + */ + +import { LSPPlugin } from "@codemirror/lsp-client"; +import type { EditorView } from "@codemirror/view"; +import type { + DocumentSymbol, + Position, + Range, + SymbolInformation, + SymbolKind, +} from "vscode-languageserver-types"; +import type { LSPPluginAPI } from "./types"; + +interface DocumentSymbolParams { + textDocument: { uri: string }; +} + +export interface ProcessedSymbol { + name: string; + kind: SymbolKind; + kindName: string; + detail?: string; + range: { + startLine: number; + startCharacter: number; + endLine: number; + endCharacter: number; + }; + selectionRange: { + startLine: number; + startCharacter: number; + endLine: number; + endCharacter: number; + }; + children?: ProcessedSymbol[]; + depth: number; + containerName?: string; +} + +export interface FlatSymbol { + name: string; + kind: SymbolKind; + kindName: string; + detail?: string; + line: number; + character: number; + endLine: number; + endCharacter: number; + containerName?: string; + depth: number; +} + +const SYMBOL_KIND_NAMES: Record = { + 1: "File", + 2: "Module", + 3: "Namespace", + 4: "Package", + 5: "Class", + 6: "Method", + 7: "Property", + 8: "Field", + 9: "Constructor", + 10: "Enum", + 11: "Interface", + 12: "Function", + 13: "Variable", + 14: "Constant", + 15: "String", + 16: "Number", + 17: "Boolean", + 18: "Array", + 19: "Object", + 20: "Key", + 21: "Null", + 22: "EnumMember", + 23: "Struct", + 24: "Event", + 25: "Operator", + 26: "TypeParameter", +}; + +const SYMBOL_KIND_ICONS: Record = { + 1: "insert_drive_file", + 2: "view_module", + 3: "view_module", + 4: "folder", + 5: "class", + 6: "functions", + 7: "label", + 8: "label", + 9: "functions", + 10: "list", + 11: "category", + 12: "functions", + 13: "code", + 14: "lock", + 15: "text_fields", + 16: "pin", + 17: "toggle_on", + 18: "data_array", + 19: "data_object", + 20: "key", + 21: "not_interested", + 22: "list", + 23: "data_object", + 24: "bolt", + 25: "calculate", + 26: "text_fields", +}; + +export function getSymbolKindName(kind: SymbolKind): string { + return SYMBOL_KIND_NAMES[kind] || "Unknown"; +} + +export function getSymbolKindIcon(kind: SymbolKind): string { + return SYMBOL_KIND_ICONS[kind] || "code"; +} + +function isDocumentSymbol( + item: DocumentSymbol | SymbolInformation, +): item is DocumentSymbol { + return "selectionRange" in item; +} + +function processDocumentSymbol( + symbol: DocumentSymbol, + depth = 0, + containerName?: string, +): ProcessedSymbol { + const processed: ProcessedSymbol = { + name: symbol.name, + kind: symbol.kind, + kindName: getSymbolKindName(symbol.kind), + detail: symbol.detail, + range: { + startLine: symbol.range.start.line, + startCharacter: symbol.range.start.character, + endLine: symbol.range.end.line, + endCharacter: symbol.range.end.character, + }, + selectionRange: { + startLine: symbol.selectionRange.start.line, + startCharacter: symbol.selectionRange.start.character, + endLine: symbol.selectionRange.end.line, + endCharacter: symbol.selectionRange.end.character, + }, + depth, + containerName, + }; + + if (symbol.children && symbol.children.length > 0) { + processed.children = symbol.children.map((child) => + processDocumentSymbol(child, depth + 1, symbol.name), + ); + } + + return processed; +} + +function processSymbolInformation( + symbol: SymbolInformation, + depth = 0, +): ProcessedSymbol { + return { + name: symbol.name, + kind: symbol.kind, + kindName: getSymbolKindName(symbol.kind), + range: { + startLine: symbol.location.range.start.line, + startCharacter: symbol.location.range.start.character, + endLine: symbol.location.range.end.line, + endCharacter: symbol.location.range.end.character, + }, + selectionRange: { + startLine: symbol.location.range.start.line, + startCharacter: symbol.location.range.start.character, + endLine: symbol.location.range.end.line, + endCharacter: symbol.location.range.end.character, + }, + containerName: symbol.containerName, + depth, + }; +} + +function flattenSymbols( + symbols: ProcessedSymbol[], + result: FlatSymbol[] = [], +): FlatSymbol[] { + for (const symbol of symbols) { + result.push({ + name: symbol.name, + kind: symbol.kind, + kindName: symbol.kindName, + detail: symbol.detail, + line: symbol.selectionRange.startLine, + character: symbol.selectionRange.startCharacter, + endLine: symbol.selectionRange.endLine, + endCharacter: symbol.selectionRange.endCharacter, + containerName: symbol.containerName, + depth: symbol.depth, + }); + + if (symbol.children) { + flattenSymbols(symbol.children, result); + } + } + + return result; +} + +export async function fetchDocumentSymbols( + view: EditorView, +): Promise { + const plugin = LSPPlugin.get(view) as LSPPluginAPI | null; + if (!plugin) { + return null; + } + + const client = plugin.client; + const capabilities = client.serverCapabilities; + + if (!capabilities?.documentSymbolProvider) { + return null; + } + + client.sync(); + + const params: DocumentSymbolParams = { + textDocument: { uri: plugin.uri }, + }; + + try { + const response = await client.request< + DocumentSymbolParams, + (DocumentSymbol | SymbolInformation)[] | null + >("textDocument/documentSymbol", params); + + if (!response || response.length === 0) { + return []; + } + + if (isDocumentSymbol(response[0])) { + return (response as DocumentSymbol[]).map((sym) => + processDocumentSymbol(sym), + ); + } + + return (response as SymbolInformation[]).map((sym) => + processSymbolInformation(sym), + ); + } catch (error) { + console.warn("Failed to fetch document symbols:", error); + return null; + } +} + +export async function getDocumentSymbolsFlat( + view: EditorView, +): Promise { + const symbols = await fetchDocumentSymbols(view); + if (!symbols) { + return []; + } + + return flattenSymbols(symbols); +} + +export async function navigateToSymbol( + view: EditorView, + symbol: FlatSymbol | ProcessedSymbol, +): Promise { + try { + const doc = view.state.doc; + let targetLine: number; + let targetChar: number; + + if ("line" in symbol) { + targetLine = symbol.line; + targetChar = symbol.character; + } else { + targetLine = symbol.selectionRange.startLine; + targetChar = symbol.selectionRange.startCharacter; + } + + const lineNumber = targetLine + 1; + if (lineNumber < 1 || lineNumber > doc.lines) { + return false; + } + + const line = doc.line(lineNumber); + const pos = Math.min(line.from + targetChar, line.to); + + view.dispatch({ + selection: { anchor: pos }, + scrollIntoView: true, + }); + + view.focus(); + return true; + } catch (error) { + console.warn("Failed to navigate to symbol:", error); + return false; + } +} + +export function supportsDocumentSymbols(view: EditorView): boolean { + const plugin = LSPPlugin.get(view) as LSPPluginAPI | null; + if (!plugin?.client.connected) { + return false; + } + + return !!plugin.client.serverCapabilities?.documentSymbolProvider; +} + +export interface DocumentSymbolsResult { + symbols: ProcessedSymbol[]; + flat: FlatSymbol[]; +} + +export async function getDocumentSymbols( + view: EditorView, +): Promise { + const symbols = await fetchDocumentSymbols(view); + if (symbols === null) { + return null; + } + + return { + symbols, + flat: flattenSymbols(symbols), + }; +} + +export { SymbolKind } from "vscode-languageserver-types"; diff --git a/src/cm/lsp/formatter.ts b/src/cm/lsp/formatter.ts new file mode 100644 index 000000000..224fad530 --- /dev/null +++ b/src/cm/lsp/formatter.ts @@ -0,0 +1,117 @@ +import type { EditorView } from "@codemirror/view"; +import { getModes } from "cm/modelist"; +import toast from "components/toast"; +import lspClientManager from "./clientManager"; +import serverRegistry from "./serverRegistry"; +import type { AcodeApi, FileMetadata } from "./types"; + +interface Mode { + name?: string; + extensions?: string; +} + +interface EditorManagerWithLsp { + editor?: EditorView; + activeFile?: AcodeFile; + getLspMetadata?: (file: AcodeFile) => FileMetadata | null; +} + +function getActiveMetadata( + manager: EditorManagerWithLsp | undefined, + file: AcodeFile | undefined, +): (FileMetadata & { view?: EditorView }) | null { + if (!manager?.getLspMetadata || !file) return null; + const metadata = manager.getLspMetadata(file); + if (!metadata) return null; + return { + ...metadata, + view: manager.editor, + }; +} + +export function registerLspFormatter(acode: AcodeApi): void { + const languages = new Set(); + serverRegistry.listServers().forEach((server) => { + (server.languages || []).forEach((lang) => { + if (lang) languages.add(String(lang)); + }); + }); + const extensions = languages.size + ? collectFormatterExtensions(languages) + : ["*"]; + + acode.registerFormatter( + "lsp", + extensions, + async () => { + const manager = window.editorManager as EditorManagerWithLsp | undefined; + const file = manager?.activeFile; + const metadata = getActiveMetadata(manager, file); + if (!metadata) { + toast("LSP formatter unavailable"); + return false; + } + const languageId = metadata.languageId; + if (!languageId) { + toast("Unknown language for LSP formatting"); + return false; + } + const servers = serverRegistry.getServersForLanguage(languageId); + if (!servers.length) { + toast("No LSP formatter available"); + return false; + } + const fullMetadata = { + ...metadata, + languageName: metadata.languageName || languageId, + }; + const success = await lspClientManager.formatDocument(fullMetadata); + if (!success) { + toast("LSP formatter failed"); + } + return success; + }, + "Language Server", + ); +} + +function collectFormatterExtensions(languages: Set): string[] { + const extensions = new Set(); + const modeMap = new Map(); + + try { + const modes = getModes() as Mode[]; + modes.forEach((mode) => { + const key = String(mode?.name ?? "") + .trim() + .toLowerCase(); + if (key) modeMap.set(key, mode); + }); + } catch (_) { + // Ignore mode loading errors + } + + languages.forEach((language) => { + const key = String(language ?? "") + .trim() + .toLowerCase(); + if (!key) return; + extensions.add(key); + const mode = modeMap.get(key); + if (!mode?.extensions) return; + String(mode.extensions) + .split("|") + .forEach((part) => { + const ext = part.trim(); + if (ext && !ext.startsWith("^")) { + extensions.add(ext); + } + }); + }); + + if (!extensions.size) { + return ["*"]; + } + + return Array.from(extensions); +} diff --git a/src/cm/lsp/index.ts b/src/cm/lsp/index.ts new file mode 100644 index 000000000..8d48aa770 --- /dev/null +++ b/src/cm/lsp/index.ts @@ -0,0 +1,87 @@ +export { default as clientManager, LspClientManager } from "./clientManager"; +export type { CodeActionItem } from "./codeActions"; +export { + CODE_ACTION_KINDS, + executeCodeAction, + fetchCodeActions, + formatCodeActionKind, + getCodeActionIcon, + performQuickFix, + showCodeActionsMenu, + supportsCodeActions, +} from "./codeActions"; +export { + clearDiagnosticsEffect, + getLspDiagnostics, + LSP_DIAGNOSTICS_EVENT, + lspDiagnosticsClientExtension, + lspDiagnosticsExtension, + lspDiagnosticsUiExtension, +} from "./diagnostics"; +export type { DocumentHighlightsConfig } from "./documentHighlights"; +export { + documentHighlightsClientExtension, + documentHighlightsEditorExtension, + documentHighlightsExtension, +} from "./documentHighlights"; +export type { + DocumentSymbolsResult, + FlatSymbol, + ProcessedSymbol, +} from "./documentSymbols"; +export { + fetchDocumentSymbols, + getDocumentSymbols, + getDocumentSymbolsFlat, + getSymbolKindIcon, + getSymbolKindName, + navigateToSymbol, + SymbolKind, + supportsDocumentSymbols, +} from "./documentSymbols"; +export { registerLspFormatter } from "./formatter"; +export type { InlayHintsConfig } from "./inlayHints"; +export { + inlayHintsClientExtension, + inlayHintsEditorExtension, + inlayHintsExtension, +} from "./inlayHints"; +export { + closeReferencesPanel, + findAllReferences, + findAllReferencesInTab, +} from "./references"; +export { + acodeRenameExtension, + acodeRenameKeymap, + renameSymbol, +} from "./rename"; +export { + ensureServerRunning, + resetManagedServers, + stopManagedServer, +} from "./serverLauncher"; +export { default as serverRegistry } from "./serverRegistry"; +export { createTransport } from "./transport"; + +export type { + BuiltinExtensionsConfig, + ClientManagerOptions, + ClientState, + DiagnosticRelatedInformation, + FileMetadata, + FormattingOptions, + LSPClientWithWorkspace, + LSPDiagnostic, + LSPFormattingOptions, + LSPPluginAPI, + LspDiagnostic, + LspServerDefinition, + Position, + Range, + TextEdit, + TransportDescriptor, + TransportHandle, + WorkspaceOptions, +} from "./types"; +export { default as AcodeWorkspace } from "./workspace"; diff --git a/src/cm/lsp/inlayHints.ts b/src/cm/lsp/inlayHints.ts new file mode 100644 index 000000000..b68080665 --- /dev/null +++ b/src/cm/lsp/inlayHints.ts @@ -0,0 +1,345 @@ +/** + * LSP Inlay Hints Extension for CodeMirror + * + * Provides inline hints (type annotations, parameter names, etc.) from language servers. + */ + +import type { LSPClient, LSPClientExtension } from "@codemirror/lsp-client"; +import { LSPPlugin } from "@codemirror/lsp-client"; +import type { Extension, Range } from "@codemirror/state"; +import { RangeSet, StateEffect, StateField } from "@codemirror/state"; +import { + Decoration, + type DecorationSet, + EditorView, + ViewPlugin, + type ViewUpdate, + WidgetType, +} from "@codemirror/view"; +import type { + InlayHint, + InlayHintLabelPart, + Position, +} from "vscode-languageserver-types"; +import type { LSPPluginAPI } from "./types"; + +// ============================================================================ +// Types +// ============================================================================ + +interface InlayHintParams { + textDocument: { uri: string }; + range: { start: Position; end: Position }; +} + +interface ProcessedHint { + pos: number; + label: string; + paddingLeft?: boolean; + paddingRight?: boolean; + tooltip?: string; +} + +export interface InlayHintsConfig { + enabled?: boolean; + debounceMs?: number; + showTypes?: boolean; + showParameters?: boolean; + maxHints?: number; +} + +// LSP InlayHintKind constants +const TYPE_HINT = 1; +const PARAM_HINT = 2; + +// ============================================================================ +// State +// ============================================================================ + +const setHints = StateEffect.define(); + +const hintsField = StateField.define({ + create: () => [], + update(hints, tr) { + for (const e of tr.effects) { + if (e.is(setHints)) return e.value; + } + return hints; + }, +}); + +// ============================================================================ +// Widget +// ============================================================================ + +class HintWidget extends WidgetType { + constructor( + readonly label: string, + readonly padLeft: boolean, + readonly padRight: boolean, + readonly tooltip: string | undefined, + ) { + super(); + } + + eq(other: HintWidget): boolean { + return ( + this.label === other.label && + this.padLeft === other.padLeft && + this.padRight === other.padRight + ); + } + + toDOM(): HTMLSpanElement { + const el = document.createElement("span"); + el.className = `cm-inlay-hint${this.padLeft ? " cm-inlay-hint-pl" : ""}${this.padRight ? " cm-inlay-hint-pr" : ""}`; + el.textContent = this.label; + if (this.tooltip) el.title = this.tooltip; + return el; + } + + ignoreEvent(): boolean { + return true; + } +} + +// ============================================================================ +// Decorations +// ============================================================================ + +function buildDecos(hints: ProcessedHint[], docLen: number): DecorationSet { + if (!hints.length) return Decoration.none; + + const decos: Range[] = []; + for (const h of hints) { + if (h.pos < 0 || h.pos > docLen) continue; + decos.push( + Decoration.widget({ + widget: new HintWidget( + h.label, + h.paddingLeft ?? false, + h.paddingRight ?? false, + h.tooltip, + ), + side: 1, + }).range(h.pos), + ); + } + return RangeSet.of(decos, true); +} + +// ============================================================================ +// Plugin +// ============================================================================ + +function createPlugin(config: InlayHintsConfig) { + const delay = config.debounceMs ?? 200; + const max = config.maxHints ?? 500; + const showTypes = config.showTypes !== false; + const showParams = config.showParameters !== false; + + return ViewPlugin.fromClass( + class { + decorations: DecorationSet = Decoration.none; + timer: ReturnType | null = null; + reqId = 0; + + constructor(private view: EditorView) { + this.fetch(); + } + + update(update: ViewUpdate): void { + if ( + update.transactions.some((t) => t.effects.some((e) => e.is(setHints))) + ) { + this.decorations = buildDecos( + update.state.field(hintsField, false) ?? [], + update.state.doc.length, + ); + } + if (update.docChanged || update.viewportChanged) { + this.schedule(); + } + } + + schedule(): void { + if (this.timer) clearTimeout(this.timer); + this.timer = setTimeout(() => { + this.timer = null; + this.fetch(); + }, delay); + } + + async fetch(): Promise { + const lsp = LSPPlugin.get(this.view) as LSPPluginAPI | null; + if (!lsp?.client.connected) return; + + const caps = lsp.client.serverCapabilities; + if (!caps?.inlayHintProvider) return; + + lsp.client.sync(); + const id = ++this.reqId; + const doc = this.view.state.doc; + + // Visible range with buffer + const { from, to } = this.view.viewport; + const buf = 20; + const startLn = Math.max(1, doc.lineAt(Math.max(0, from)).number - buf); + const endLn = Math.min( + doc.lines, + doc.lineAt(Math.min(doc.length, to)).number + buf, + ); + + try { + const hints = await lsp.client.request< + InlayHintParams, + InlayHint[] | null + >("textDocument/inlayHint", { + textDocument: { uri: lsp.uri }, + range: { + start: lsp.toPosition(doc.line(startLn).from), + end: lsp.toPosition(doc.line(endLn).to), + }, + }); + + if (id !== this.reqId) return; + + const processed = this.process(lsp, hints ?? [], doc.length); + this.view.dispatch({ effects: setHints.of(processed) }); + } catch { + // Non-critical - silently ignore + } + } + + process( + lsp: LSPPluginAPI, + hints: InlayHint[], + docLen: number, + ): ProcessedHint[] { + const result: ProcessedHint[] = []; + + for (const h of hints) { + if (h.kind === TYPE_HINT && !showTypes) continue; + if (h.kind === PARAM_HINT && !showParams) continue; + + let pos: number; + try { + pos = lsp.fromPosition(h.position, lsp.syncedDoc); + const mapped = lsp.unsyncedChanges.mapPos(pos); + if (mapped === null) continue; + pos = mapped; + } catch { + continue; + } + + if (pos < 0 || pos > docLen) continue; + + const label = + typeof h.label === "string" + ? h.label + : Array.isArray(h.label) + ? h.label.map((p: InlayHintLabelPart) => p.value).join("") + : ""; + if (!label) continue; + + const tooltip = + typeof h.tooltip === "string" + ? h.tooltip + : h.tooltip && + typeof h.tooltip === "object" && + "value" in h.tooltip + ? (h.tooltip as { value: string }).value + : undefined; + + result.push({ + pos, + label, + paddingLeft: h.paddingLeft, + paddingRight: h.paddingRight, + tooltip, + }); + + if (result.length >= max) break; + } + + return result.sort((a, b) => a.pos - b.pos); + } + + destroy(): void { + if (this.timer) clearTimeout(this.timer); + } + }, + { decorations: (v) => v.decorations }, + ); +} + +// ============================================================================ +// Styles +// ============================================================================ + +const styles = EditorView.baseTheme({ + ".cm-inlay-hint": { + display: "inline-block", + fontFamily: "inherit", + fontSize: "0.9em", + fontStyle: "italic", + borderRadius: "3px", + padding: "0 3px", + margin: "0 2px", + verticalAlign: "baseline", + pointerEvents: "none", + }, + "&light .cm-inlay-hint": { + color: "#6a737d", + backgroundColor: "rgba(27, 31, 35, 0.05)", + }, + "&dark .cm-inlay-hint": { + color: "#6a9955", + backgroundColor: "rgba(255, 255, 255, 0.05)", + }, + ".cm-inlay-hint-pl": { marginLeft: "4px" }, + ".cm-inlay-hint-pr": { marginRight: "4px" }, +}); + +// ============================================================================ +// Exports +// ============================================================================ + +export function inlayHintsClientExtension(): LSPClientExtension { + return { + clientCapabilities: { + textDocument: { + inlayHint: { + dynamicRegistration: true, + resolveSupport: { + properties: [ + "tooltip", + "textEdits", + "label.tooltip", + "label.location", + "label.command", + ], + }, + }, + }, + }, + }; +} + +export function inlayHintsEditorExtension( + config: InlayHintsConfig = {}, +): Extension { + if (config.enabled === false) return []; + return [hintsField, createPlugin(config), styles]; +} + +export function inlayHintsExtension( + config: InlayHintsConfig = {}, +): LSPClientExtension & { editorExtension: Extension } { + return { + ...inlayHintsClientExtension(), + editorExtension: inlayHintsEditorExtension(config), + }; +} + +export default inlayHintsExtension; diff --git a/src/cm/lsp/references.ts b/src/cm/lsp/references.ts new file mode 100644 index 000000000..53bf8e7cf --- /dev/null +++ b/src/cm/lsp/references.ts @@ -0,0 +1,226 @@ +import fsOperation from "fileSystem"; +import { LSPPlugin } from "@codemirror/lsp-client"; +import type { EditorView } from "@codemirror/view"; +import { + openReferencesTab, + showReferencesPanel, +} from "components/referencesPanel"; +import settings from "lib/settings"; + +interface Position { + line: number; + character: number; +} + +interface Range { + start: Position; + end: Position; +} + +interface Location { + uri: string; + range: Range; +} + +interface ReferenceWithContext extends Location { + lineText?: string; +} + +interface ReferenceParams { + textDocument: { uri: string }; + position: Position; + context: { includeDeclaration: boolean }; +} + +async function fetchLineText(uri: string, line: number): Promise { + try { + interface EditorManagerLike { + getFile?: (uri: string, type: string) => EditorFileLike | null; + } + + interface EditorFileLike { + session?: { + doc?: { + line?: (n: number) => { text?: string } | null; + toString?: () => string; + }; + }; + } + + const em = (globalThis as Record).editorManager as + | EditorManagerLike + | undefined; + + const openFile = em?.getFile?.(uri, "uri"); + if (openFile?.session?.doc) { + const doc = openFile.session.doc; + if (typeof doc.line === "function") { + const lineObj = doc.line(line + 1); + if (lineObj && typeof lineObj.text === "string") { + return lineObj.text; + } + } + if (typeof doc.toString === "function") { + const content = doc.toString(); + const lines = content.split("\n"); + if (lines[line] !== undefined) { + return lines[line]; + } + } + } + + const fs = fsOperation(uri); + if (fs && (await fs.exists())) { + const encoding = + (settings as { value?: { defaultFileEncoding?: string } })?.value + ?.defaultFileEncoding || "utf-8"; + const content = await fs.readFile(encoding); + if (typeof content === "string") { + const lines = content.split("\n"); + if (lines[line] !== undefined) { + return lines[line]; + } + } + } + } catch (error) { + console.warn(`Failed to fetch line text for ${uri}:${line}`, error); + } + return ""; +} + +function getWordAtCursor(view: EditorView): string { + const { state } = view; + const pos = state.selection.main.head; + const word = state.wordAt(pos); + if (word) { + return state.doc.sliceString(word.from, word.to); + } + return ""; +} + +async function fetchReferences( + view: EditorView, +): Promise<{ symbolName: string; references: ReferenceWithContext[] } | null> { + const plugin = LSPPlugin.get(view); + if (!plugin) { + return null; + } + + const client = plugin.client; + const capabilities = client.serverCapabilities; + + if (!capabilities?.referencesProvider) { + const toast = (globalThis as Record).toast as + | ((msg: string) => void) + | undefined; + toast?.("Language server does not support find references"); + return null; + } + + const { state } = view; + const pos = state.selection.main.head; + const line = state.doc.lineAt(pos); + const lineNumber = line.number - 1; + const character = pos - line.from; + const uri = plugin.uri; + + const symbolName = getWordAtCursor(view); + + client.sync(); + + const params: ReferenceParams = { + textDocument: { uri }, + position: { line: lineNumber, character }, + context: { includeDeclaration: true }, + }; + + const locations = await client.request( + "textDocument/references", + params, + ); + + if (!locations || locations.length === 0) { + return { symbolName, references: [] }; + } + + const refsWithContext: ReferenceWithContext[] = await Promise.all( + locations.map(async (loc) => { + const lineText = await fetchLineText(loc.uri, loc.range.start.line); + return { + ...loc, + lineText, + }; + }), + ); + + return { symbolName, references: refsWithContext }; +} + +export async function findAllReferences(view: EditorView): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) { + return false; + } + + const symbolName = getWordAtCursor(view); + const panel = showReferencesPanel({ symbolName }); + + try { + const result = await fetchReferences(view); + if (result === null) { + panel.setError("Failed to fetch references"); + return false; + } + panel.setReferences(result.references); + return true; + } catch (error) { + console.error("Find references failed:", error); + const errorMessage = + error instanceof Error ? error.message : "Unknown error occurred"; + panel.setError(errorMessage); + return false; + } +} + +export async function findAllReferencesInTab( + view: EditorView, +): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) { + const toast = (globalThis as Record).toast as + | ((msg: string) => void) + | undefined; + toast?.("Language server not available"); + return false; + } + + try { + const result = await fetchReferences(view); + if (result === null) { + return false; + } + + if (result.references.length === 0) { + const toast = (globalThis as Record).toast as + | ((msg: string) => void) + | undefined; + toast?.("No references found"); + return true; + } + + openReferencesTab({ + symbolName: result.symbolName, + references: result.references, + }); + return true; + } catch (error) { + console.error("Find references in tab failed:", error); + return false; + } +} + +export function closeReferencesPanel(): boolean { + const { hideReferencesPanel } = require("components/referencesPanel"); + hideReferencesPanel(); + return true; +} diff --git a/src/cm/lsp/rename.ts b/src/cm/lsp/rename.ts new file mode 100644 index 000000000..1ba871f91 --- /dev/null +++ b/src/cm/lsp/rename.ts @@ -0,0 +1,271 @@ +import { LSPPlugin } from "@codemirror/lsp-client"; +import { + type Command, + EditorView, + type KeyBinding, + keymap, +} from "@codemirror/view"; +import prompt from "dialogs/prompt"; +import type * as lsp from "vscode-languageserver-protocol"; +import type AcodeWorkspace from "./workspace"; + +interface RenameParams { + newName: string; + position: lsp.Position; + textDocument: { uri: string }; +} + +interface TextDocumentEdit { + range: lsp.Range; + newText: string; +} + +interface PrepareRenameResponse { + range?: lsp.Range; + placeholder?: string; + defaultBehavior?: boolean; +} + +interface LspChange { + range: lsp.Range; + newText: string; +} + +function getRename(plugin: LSPPlugin, pos: number, newName: string) { + return plugin.client.request( + "textDocument/rename", + { + newName, + position: plugin.toPosition(pos), + textDocument: { uri: plugin.uri }, + }, + ); +} + +function getPrepareRename(plugin: LSPPlugin, pos: number) { + return plugin.client.request< + { position: lsp.Position; textDocument: { uri: string } }, + PrepareRenameResponse | lsp.Range | null + >("textDocument/prepareRename", { + position: plugin.toPosition(pos), + textDocument: { uri: plugin.uri }, + }); +} + +async function performRename(view: EditorView): Promise { + const wordRange = view.state.wordAt(view.state.selection.main.head); + const plugin = LSPPlugin.get(view); + + if (!plugin) { + return false; + } + + const capabilities = plugin.client.serverCapabilities; + const renameProvider = capabilities?.renameProvider; + + if (renameProvider === false || renameProvider === undefined) { + return false; + } + + if (!wordRange) { + return false; + } + + const word = view.state.sliceDoc(wordRange.from, wordRange.to); + let initialValue = word; + let canRename = true; + + const supportsPrepare = + typeof renameProvider === "object" && + renameProvider !== null && + "prepareProvider" in renameProvider && + renameProvider.prepareProvider === true; + + if (supportsPrepare) { + try { + plugin.client.sync(); + const prepareResult = await getPrepareRename(plugin, wordRange.from); + if (prepareResult === null) { + canRename = false; + } else if (typeof prepareResult === "object" && prepareResult !== null) { + if ("placeholder" in prepareResult && prepareResult.placeholder) { + initialValue = prepareResult.placeholder; + } else if ( + "defaultBehavior" in prepareResult && + prepareResult.defaultBehavior + ) { + initialValue = word; + } else if ("start" in prepareResult && "end" in prepareResult) { + const from = plugin.fromPosition(prepareResult.start); + const to = plugin.fromPosition(prepareResult.end); + initialValue = view.state.sliceDoc(from, to); + } else if ("range" in prepareResult && prepareResult.range) { + const from = plugin.fromPosition(prepareResult.range.start); + const to = plugin.fromPosition(prepareResult.range.end); + initialValue = view.state.sliceDoc(from, to); + } + } + } catch (error) { + console.warn("[LSP:Rename] prepareRename failed, using word:", error); + } + } + + if (!canRename) { + const alert = (await import("dialogs/alert")).default; + alert("Rename", "Cannot rename this symbol."); + return true; + } + + const newName = await prompt( + strings["new name"] || "New name", + initialValue, + "text", + { + required: true, + placeholder: strings["enter new name"] || "Enter new name", + }, + ); + + if (newName === null || newName === initialValue) { + return true; + } + + try { + await doRename(view, String(newName), wordRange.from); + } catch (error) { + console.error("[LSP:Rename] Rename failed:", error); + const errorMessage = + error instanceof Error ? error.message : "Failed to rename symbol"; + const alert = (await import("dialogs/alert")).default; + alert("Rename Error", errorMessage); + } + + return true; +} + +function lspPositionToOffset( + doc: { line: (n: number) => { from: number } }, + pos: lsp.Position, +): number { + const line = doc.line(pos.line + 1); + return line.from + pos.character; +} + +async function applyChangesToFile( + workspace: AcodeWorkspace, + uri: string, + lspChanges: LspChange[], + mapping: { mapPosition: (uri: string, pos: lsp.Position) => number }, +): Promise { + const file = workspace.getFile(uri); + + if (file) { + const view = file.getView(); + if (view) { + view.dispatch({ + changes: lspChanges.map((change) => ({ + from: mapping.mapPosition(uri, change.range.start), + to: mapping.mapPosition(uri, change.range.end), + insert: change.newText, + })), + userEvent: "rename", + }); + return true; + } + } + + const displayedView = await workspace.displayFile(uri); + if (!displayedView?.state?.doc) { + console.warn(`[LSP:Rename] Could not open file: ${uri}`); + return false; + } + + const doc = displayedView.state.doc; + displayedView.dispatch({ + changes: lspChanges.map((change) => ({ + from: lspPositionToOffset(doc, change.range.start), + to: lspPositionToOffset(doc, change.range.end), + insert: change.newText, + })), + userEvent: "rename", + }); + + return true; +} + +async function doRename( + view: EditorView, + newName: string, + position: number, +): Promise { + const plugin = LSPPlugin.get(view); + if (!plugin) return; + + plugin.client.sync(); + + const response = await plugin.client.withMapping((mapping) => + getRename(plugin, position, newName).then((response) => { + if (!response) return null; + return { response, mapping }; + }), + ); + + if (!response) { + console.info("[LSP:Rename] No changes returned from server"); + return; + } + + const { response: workspaceEdit, mapping } = response; + const workspace = plugin.client.workspace as AcodeWorkspace; + let filesChanged = 0; + + if (workspaceEdit.changes) { + for (const uri in workspaceEdit.changes) { + const lspChanges = workspaceEdit.changes[uri] as TextDocumentEdit[]; + if (!lspChanges.length) continue; + + const success = await applyChangesToFile( + workspace, + uri, + lspChanges, + mapping, + ); + if (success) filesChanged++; + } + } + + if (workspaceEdit.documentChanges) { + for (const docChange of workspaceEdit.documentChanges) { + if ("textDocument" in docChange && "edits" in docChange) { + const uri = docChange.textDocument.uri; + const edits = docChange.edits as TextDocumentEdit[]; + if (!edits.length) continue; + + const success = await applyChangesToFile( + workspace, + uri, + edits, + mapping, + ); + if (success) filesChanged++; + } + } + } + + console.info( + `[LSP:Rename] Renamed to "${newName}" in ${filesChanged} file(s)`, + ); +} + +export const renameSymbol: Command = (view) => { + performRename(view).catch((error) => { + console.error("[LSP:Rename] Rename command failed:", error); + }); + return true; +}; + +export const acodeRenameKeymap: readonly KeyBinding[] = [ + { key: "F2", run: renameSymbol, preventDefault: true }, +]; + +export const acodeRenameExtension = () => keymap.of([...acodeRenameKeymap]); diff --git a/src/cm/lsp/serverLauncher.ts b/src/cm/lsp/serverLauncher.ts new file mode 100644 index 000000000..8c0fb3c76 --- /dev/null +++ b/src/cm/lsp/serverLauncher.ts @@ -0,0 +1,807 @@ +import lspStatusBar from "components/lspStatusBar"; +import toast from "components/toast"; +import confirm from "dialogs/confirm"; +import loader from "dialogs/loader"; +import type { + BridgeConfig, + InstallStatus, + LauncherConfig, + LspServerDefinition, + LspServerStats, + LspServerStatsFormatted, + ManagedServerEntry, + PortInfo, + WaitOptions, +} from "./types"; + +const managedServers = new Map(); +const checkedCommands = new Map(); +const pendingInstallChecks = new Map>(); +const announcedServers = new Set(); + +const STATUS_PRESENT: InstallStatus = "present"; +const STATUS_DECLINED: InstallStatus = "declined"; +const STATUS_FAILED: InstallStatus = "failed"; + +const AXS_BINARY = "$PREFIX/axs"; + +function getExecutor(): Executor { + const executor = (globalThis as unknown as { Executor?: Executor }).Executor; + if (!executor) { + throw new Error("Executor plugin is not available"); + } + return executor; +} + +/** + * Get the background executor + */ +function getBackgroundExecutor(): Executor { + const executor = getExecutor(); + return executor.BackgroundExecutor ?? executor; +} + +function joinCommand(command: string, args: string[] = []): string { + if (!Array.isArray(args)) return command; + return [command, ...args].join(" "); +} + +function wrapShellCommand(command: string): string { + const script = command.trim(); + const escaped = script.replace(/"/g, '\\"'); + return `sh -lc "set -e; ${escaped}"`; +} + +/** + * Run a quick shell command using the background executor. + */ +async function runQuickCommand(command: string): Promise { + const wrapped = wrapShellCommand(command); + return getBackgroundExecutor().execute(wrapped, true); +} + +/** + * Run a shell command using the foreground executor + */ +async function runForegroundCommand(command: string): Promise { + const wrapped = wrapShellCommand(command); + return getExecutor().execute(wrapped, true); +} + +function quoteArg(value: unknown): string { + const str = String(value ?? ""); + if (!str.length) return "''"; + if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(str)) return str; + return `'${str.replace(/'/g, "'\\''")}'`; +} + +// ============================================================================ +// Auto-Port Discovery +// ============================================================================ + +// Cache for the filesDir path +let cachedFilesDir: string | null = null; + +/** + * Get the terminal home directory from system.getFilesDir(). + * This is where axs stores port files. + */ +async function getTerminalHomeDir(): Promise { + if (cachedFilesDir) { + return `${cachedFilesDir}/alpine/home`; + } + + const system = ( + globalThis as unknown as { + system?: { + getFilesDir: ( + success: (filesDir: string) => void, + error: (error: string) => void, + ) => void; + }; + } + ).system; + + if (!system?.getFilesDir) { + throw new Error("System plugin is not available"); + } + + return new Promise((resolve, reject) => { + system.getFilesDir( + (filesDir: string) => { + cachedFilesDir = filesDir; + resolve(`${filesDir}/alpine/home`); + }, + (error: string) => reject(new Error(error)), + ); + }); +} + +/** + * Get the port file path for a given server and session. + * Port file format: ~/.axs/lsp_ports/{serverName}_{session} + */ +async function getPortFilePath( + serverName: string, + session: string, +): Promise { + const homeDir = await getTerminalHomeDir(); + // Use just the binary name (not full path), mirroring axs behavior + const baseName = serverName.split("/").pop() || serverName; + return `file://${homeDir}/.axs/lsp_ports/${baseName}_${session}`; +} + +/** + * Read the port from a port file using the filesystem API. + * Returns null if the file doesn't exist or contains invalid data. + */ +async function readPortFromFile(filePath: string): Promise { + try { + // Dynamic import to get fsOperation + const { default: fsOperation } = await import("fileSystem"); + const fs = fsOperation(filePath); + + // Check if file exists first + const exists = await fs.exists(); + if (!exists) { + return null; + } + + // Read the file content as text + const content = (await fs.readFile("utf-8")) as string; + const port = Number.parseInt(content.trim(), 10); + + if (!Number.isFinite(port) || port <= 0 || port > 65535) { + return null; + } + + return port; + } catch { + // File doesn't exist or couldn't be read + return null; + } +} + +/** + * Get the port for a running LSP server from the axs port file. + * @param serverName - The LSP server binary name (e.g., "typescript-language-server") + * @param session - Session ID for port file naming + */ +export async function getLspPort( + serverName: string, + session: string, +): Promise { + try { + const filePath = await getPortFilePath(serverName, session); + const port = await readPortFromFile(filePath); + + if (port === null) { + return null; + } + + return { port, filePath, session }; + } catch { + return null; + } +} + +/** + * Wait for the server ready signal (when axs prints "listening on"). + * The axs proxy writes the port file immediately after binding, then prints the message. + * So once the signal is received, the port file should be available. + */ +async function waitForServerReady( + serverId: string, + timeout = 10000, +): Promise { + const deadline = Date.now() + timeout; + const pollInterval = 50; + + while (Date.now() < deadline) { + if (serverReadySignals.has(serverId)) { + serverReadySignals.delete(serverId); + return true; + } + await sleep(pollInterval); + } + + return false; +} + +/** + * Wait for the port file to be available after server signals ready. + * This is the most efficient approach: wait for ready signal, then read port. + */ +async function waitForPort( + serverId: string, + serverName: string, + session: string, + timeout = 10000, +): Promise { + // First, wait for the server to signal it's ready + const ready = await waitForServerReady(serverId, timeout); + + if (!ready) { + console.warn( + `[LSP:${serverId}] Server did not signal ready within timeout`, + ); + } + + // The port file should be available now (axs writes it before printing "listening on") + // Read it directly + const portInfo = await getLspPort(serverName, session); + + if (!portInfo && ready) { + // Server signaled ready but port file not found - retry a few times + for (let i = 0; i < 5; i++) { + await sleep(100); + const retryPortInfo = await getLspPort(serverName, session); + if (retryPortInfo) { + return retryPortInfo; + } + } + } + + return portInfo; +} + +/** + * Quick check if a server is running and connectable. + * Attempts a fast WebSocket connection test. + */ +async function checkServerAlive(url: string, timeout = 1000): Promise { + return new Promise((resolve) => { + try { + const ws = new WebSocket(url); + const timer = setTimeout(() => { + try { + ws.close(); + } catch {} + resolve(false); + }, timeout); + + ws.onopen = () => { + clearTimeout(timer); + try { + ws.close(); + } catch {} + resolve(true); + }; + + ws.onerror = () => { + clearTimeout(timer); + resolve(false); + }; + + ws.onclose = () => { + clearTimeout(timer); + resolve(false); + }; + } catch { + resolve(false); + } + }); +} + +/** + * Check if we can reuse an existing server by testing the port. + * Returns the port number if the server is alive, null otherwise. + */ +export async function canReuseExistingServer( + server: LspServerDefinition, + session: string, +): Promise { + const bridge = server.launcher?.bridge; + const serverName = bridge?.command || server.launcher?.command || server.id; + + const portInfo = await getLspPort(serverName, session); + if (!portInfo) { + return null; + } + + const url = `ws://127.0.0.1:${portInfo.port}/`; + const alive = await checkServerAlive(url, 1000); + + if (alive) { + console.info( + `[LSP:${server.id}] Reusing existing server on port ${portInfo.port}`, + ); + return portInfo.port; + } + + console.info( + `[LSP:${server.id}] Found stale port file, will start new server`, + ); + return null; +} + +function buildAxsBridgeCommand( + bridge: BridgeConfig | undefined, + session?: string, +): string | null { + if (!bridge || bridge.kind !== "axs") return null; + + const binary = bridge.command + ? String(bridge.command) + : (() => { + throw new Error("Bridge requires a command to execute"); + })(); + const args: string[] = Array.isArray(bridge.args) + ? bridge.args.map((arg) => String(arg)) + : []; + + // Use session ID or bridge session or server command as fallback session + const effectiveSession = session || bridge.session || binary; + + const parts = [AXS_BINARY, "lsp"]; + + // Add --session flag for port file naming + parts.push("--session", quoteArg(effectiveSession)); + + // Only add --port if explicitly specified + if ( + typeof bridge.port === "number" && + bridge.port > 0 && + bridge.port <= 65535 + ) { + parts.push("--port", String(bridge.port)); + } + + parts.push(quoteArg(binary)); + + if (args.length) { + parts.push("--"); + args.forEach((arg) => parts.push(quoteArg(arg))); + } + return parts.join(" "); +} + +function resolveStartCommand( + server: LspServerDefinition, + session?: string, +): string | null { + const launcher = server.launcher; + if (!launcher) return null; + + if (launcher.startCommand) { + return Array.isArray(launcher.startCommand) + ? launcher.startCommand.join(" ") + : String(launcher.startCommand); + } + if (launcher.command) { + return joinCommand(launcher.command, launcher.args); + } + if (launcher.bridge) { + return buildAxsBridgeCommand(launcher.bridge, session); + } + return null; +} + +async function ensureInstalled(server: LspServerDefinition): Promise { + const launcher = server.launcher; + if (!launcher?.checkCommand) return true; + + const cacheKey = `${server.id}:${launcher.checkCommand}`; + + // Return cached result if already checked + if (checkedCommands.has(cacheKey)) { + return checkedCommands.get(cacheKey) === STATUS_PRESENT; + } + + // If there's already a pending check for this server, wait for it + if (pendingInstallChecks.has(cacheKey)) { + const pending = pendingInstallChecks.get(cacheKey); + if (pending) return pending; + } + + // Create and track the pending promise + const checkPromise = performInstallCheck(server, launcher, cacheKey); + pendingInstallChecks.set(cacheKey, checkPromise); + + try { + return await checkPromise; + } finally { + pendingInstallChecks.delete(cacheKey); + } +} + +interface LoaderDialog { + show: () => void; + destroy: () => void; +} + +async function performInstallCheck( + server: LspServerDefinition, + launcher: LauncherConfig, + cacheKey: string, +): Promise { + try { + if (launcher.checkCommand) { + await runQuickCommand(launcher.checkCommand); + } + checkedCommands.set(cacheKey, STATUS_PRESENT); + return true; + } catch (error) { + if (!launcher.install) { + checkedCommands.set(cacheKey, STATUS_FAILED); + console.warn( + `LSP server ${server.id} is missing check command result and has no installer.`, + error, + ); + throw error; + } + + const install = launcher.install; + const displayLabel = ( + server.label || + server.id || + "Language server" + ).trim(); + const promptMessage = `Install ${displayLabel} language server?`; + const shouldInstall = await confirm( + server.label || displayLabel, + promptMessage, + ); + + if (!shouldInstall) { + checkedCommands.set(cacheKey, STATUS_DECLINED); + return false; + } + + let loadingDialog: LoaderDialog | null = null; + try { + loadingDialog = loader.create( + server.label, + `Installing ${server.label}...`, + ); + loadingDialog.show(); + await runForegroundCommand(install.command); + toast(`${server.label} installed`); + checkedCommands.set(cacheKey, STATUS_PRESENT); + return true; + } catch (installError) { + console.error(`Failed to install ${server.id}`, installError); + toast(strings?.error ?? "Error"); + checkedCommands.set(cacheKey, STATUS_FAILED); + throw installError; + } finally { + loadingDialog?.destroy?.(); + } + } +} + +async function startInteractiveServer( + command: string, + serverId: string, +): Promise { + const executor = getExecutor(); + const callback: ExecutorCallback = (type, data) => { + if (type === "stderr") { + if (/proot warning/i.test(data)) return; + console.warn(`[LSP:${serverId}] ${data}`); + } else if (type === "stdout" && data && data.trim()) { + console.info(`[LSP:${serverId}] ${data}`); + // Detect when the axs proxy signals it's listening + if (/listening on/i.test(data)) { + signalServerReady(serverId); + } + } + }; + const uuid = await executor.start(command, callback, true); + managedServers.set(serverId, { + uuid, + command, + startedAt: Date.now(), + }); + return uuid; +} + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +/** + * Tracks servers that have signaled they're ready (listening) + * Key: serverId, Value: timestamp when ready + */ +const serverReadySignals = new Map(); + +/** + * Called when stdout contains a "listening" message from the axs proxy. + * This signals that the server is ready to accept connections. + */ +export function signalServerReady(serverId: string): void { + serverReadySignals.set(serverId, Date.now()); +} + +/** + * Wait for the LSP server to be ready. + * + * This function polls for a ready signal (set when stdout contains "listening") + */ +async function waitForWebSocket( + url: string, + options: WaitOptions = {}, +): Promise { + const { + delay = 100, // Poll interval + probeTimeout = 5000, // Max wait time + } = options; + + // Extract server ID from URL (e.g., "ws://127.0.0.1:2090" -> check by port) + const portMatch = url.match(/:(\d+)/); + const port = portMatch ? portMatch[1] : null; + + // Find the server ID that's starting on this port + let targetServerId: string | null = null; + const entries = Array.from(managedServers.entries()); + for (const [serverId, entry] of entries) { + if ( + entry.command.includes(`--port ${port}`) || + entry.command.includes(`:${port}`) + ) { + targetServerId = serverId; + break; + } + } + + const deadline = Date.now() + probeTimeout; + + while (Date.now() < deadline) { + // Check if we got a ready signal + if (targetServerId && serverReadySignals.has(targetServerId)) { + // Server is ready, clear the signal and return + serverReadySignals.delete(targetServerId); + return; + } + + await sleep(delay); + } + + // Timeout reached, proceed anyway (transport will retry if needed) + console.debug( + `[LSP] waitForWebSocket timed out for ${url}, proceeding anyway`, + ); +} + +interface LspError extends Error { + code?: string; +} + +export interface EnsureServerResult { + uuid: string | null; + /** Port discovered from port file (for auto-port discovery) */ + discoveredPort?: number; +} + +export async function ensureServerRunning( + server: LspServerDefinition, + session?: string, +): Promise { + const launcher = server.launcher; + if (!launcher) return { uuid: null }; + + // Derive session from server ID if not provided + const effectiveSession = session || server.id; + + // Check if server is already running via port file (dead client detection) + const bridge = launcher.bridge; + const serverName = bridge?.command || launcher.command || server.id; + + try { + const existingPort = await canReuseExistingServer(server, effectiveSession); + if (existingPort !== null) { + // Server is already running and responsive, no need to start + return { uuid: null, discoveredPort: existingPort }; + } + } catch { + // Failed to check, proceed with normal startup + } + + const installed = await ensureInstalled(server); + if (!installed) { + const unavailable: LspError = new Error( + `Language server ${server.id} is not available.`, + ); + unavailable.code = "LSP_SERVER_UNAVAILABLE"; + throw unavailable; + } + + const key = server.id; + if (managedServers.has(key)) { + const existing = managedServers.get(key); + return { uuid: existing?.uuid ?? null }; + } + + const command = resolveStartCommand(server, effectiveSession); + if (!command) { + return { uuid: null }; + } + + try { + const uuid = await startInteractiveServer(command, key); + + // For auto-port discovery, wait for server ready signal then read port + let discoveredPort: number | undefined; + if (bridge && !bridge.port) { + // Auto-port mode - wait for server ready signal and then read port file + const portInfo = await waitForPort( + key, + serverName, + effectiveSession, + 10000, + ); + if (portInfo) { + discoveredPort = portInfo.port; + console.info( + `[LSP:${server.id}] Auto-discovered port ${discoveredPort}`, + ); + // Update managed server entry with the port + const entry = managedServers.get(key); + if (entry) { + entry.port = discoveredPort; + } + } + } else if ( + server.transport?.url && + (server.transport.kind === "websocket" || + server.transport.kind === "stdio") + ) { + // Fixed port mode - wait for the server to signal ready + await waitForWebSocket(server.transport.url); + } + + if (!announcedServers.has(key)) { + console.info(`[LSP:${server.id}] ${server.label} connected`); + announcedServers.add(key); + } + return { uuid, discoveredPort }; + } catch (error) { + console.error(`Failed to start language server ${server.id}`, error); + const errorMessage = error instanceof Error ? error.message : String(error); + lspStatusBar.show({ + message: errorMessage || "Connection failed", + title: `${server.label} failed`, + type: "error", + icon: "error", + duration: false, + }); + const entry = managedServers.get(key); + if (entry) { + getExecutor() + .stop(entry.uuid) + .catch((err: Error) => { + console.warn( + `Failed to stop language server shell ${server.id}`, + err, + ); + }); + managedServers.delete(key); + } + const unavailable: LspError = new Error( + `Language server ${server.id} failed to start (${errorMessage})`, + ); + unavailable.code = "LSP_SERVER_UNAVAILABLE"; + throw unavailable; + } +} + +export function stopManagedServer(serverId: string): void { + const entry = managedServers.get(serverId); + if (!entry) return; + const executor = getExecutor(); + executor.stop(entry.uuid).catch((error: Error) => { + console.warn(`Failed to stop language server ${serverId}`, error); + }); + managedServers.delete(serverId); + announcedServers.delete(serverId); + + // Stop foreground service when all servers are stopped + if (managedServers.size === 0) { + executor.stopService().catch(() => {}); + } +} + +export function resetManagedServers(): void { + for (const id of Array.from(managedServers.keys())) { + stopManagedServer(id); + } + managedServers.clear(); + // Ensure foreground service is stopped + getExecutor() + .stopService() + .catch(() => {}); +} + +/** + * Get managed server info by server ID + */ +export function getManagedServerInfo( + serverId: string, +): ManagedServerEntry | null { + return managedServers.get(serverId) ?? null; +} + +/** + * Get all managed servers + */ +export function getAllManagedServers(): Map { + return new Map(managedServers); +} + +function formatMemory(bytes: number): string { + if (!bytes || bytes <= 0) return "—"; + const mb = bytes / (1024 * 1024); + if (mb >= 1) return `${mb.toFixed(1)} MB`; + const kb = bytes / 1024; + return `${kb.toFixed(0)} KB`; +} + +function formatUptime(seconds: number): string { + if (!seconds || seconds <= 0) return "—"; + if (seconds < 60) return `${seconds}s`; + const mins = Math.floor(seconds / 60); + const secs = seconds % 60; + if (mins < 60) return `${mins}m ${secs}s`; + const hours = Math.floor(mins / 60); + const remainingMins = mins % 60; + return `${hours}h ${remainingMins}m`; +} + +/** + * Fetch server stats from the axs proxy /status endpoint + * @param serverId - The server ID to fetch stats for + * @param timeout - Timeout in milliseconds (default: 2000) + */ +export async function getServerStats( + serverId: string, + timeout = 2000, +): Promise { + const entry = managedServers.get(serverId); + if (!entry?.port) { + return null; + } + + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeout); + + const response = await fetch(`http://127.0.0.1:${entry.port}/status`, { + signal: controller.signal, + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + return null; + } + + const data = (await response.json()) as LspServerStats; + + // Aggregate stats from all processes + let totalMemory = 0; + let maxUptime = 0; + let firstPid: number | null = null; + + for (const proc of data.processes || []) { + totalMemory += proc.memory_bytes || 0; + if (proc.uptime_secs > maxUptime) { + maxUptime = proc.uptime_secs; + } + if (firstPid === null && proc.pid) { + firstPid = proc.pid; + } + } + + return { + memoryBytes: totalMemory, + memoryFormatted: formatMemory(totalMemory), + uptimeSeconds: maxUptime, + uptimeFormatted: formatUptime(maxUptime), + pid: firstPid, + processCount: data.processes?.length ?? 0, + }; + } catch { + return null; + } +} diff --git a/src/cm/lsp/serverRegistry.ts b/src/cm/lsp/serverRegistry.ts new file mode 100644 index 000000000..b9af2ba47 --- /dev/null +++ b/src/cm/lsp/serverRegistry.ts @@ -0,0 +1,1043 @@ +import type { + AcodeClientConfig, + BridgeConfig, + LanguageResolverContext, + LauncherConfig, + LspServerDefinition, + RegistryEventListener, + RegistryEventType, + RootUriContext, + TransportDescriptor, + WebSocketTransportOptions, +} from "./types"; + +const registry = new Map(); +const listeners = new Set(); + +function toKey(id: string | undefined | null): string { + return String(id ?? "") + .trim() + .toLowerCase(); +} + +function clone(value: T): T | undefined { + if (!value || typeof value !== "object") return undefined; + try { + return JSON.parse(JSON.stringify(value)) as T; + } catch (_) { + return value; + } +} + +function sanitizeLanguages(languages: string[] = []): string[] { + if (!Array.isArray(languages)) return []; + return languages + .map((lang) => + String(lang ?? "") + .trim() + .toLowerCase(), + ) + .filter(Boolean); +} + +function parsePort(value: unknown): number | null { + const num = Number(value); + if (!Number.isFinite(num)) return null; + const int = Math.floor(num); + if (int !== num || int <= 0 || int > 65535) return null; + return int; +} + +interface RawBridgeConfig { + kind?: string; + port?: unknown; + command?: string; + args?: unknown[]; + session?: string; +} + +function sanitizeBridge( + serverId: string, + bridge: RawBridgeConfig | undefined | null, +): BridgeConfig | undefined { + if (!bridge || typeof bridge !== "object") return undefined; + const kind = bridge.kind ?? "axs"; + if (kind !== "axs") { + throw new Error( + `LSP server ${serverId} declares unsupported bridge kind ${kind}`, + ); + } + // Port is now optional - if not provided, auto-port discovery will be used + const port = bridge.port ? (parsePort(bridge.port) ?? undefined) : undefined; + const command = bridge.command ? String(bridge.command) : null; + if (!command) { + throw new Error(`LSP server ${serverId} bridge must supply a command`); + } + const args = Array.isArray(bridge.args) + ? bridge.args.map((arg) => String(arg)) + : undefined; + return { + kind: "axs", + port, + command, + args, + session: bridge.session ? String(bridge.session) : undefined, + }; +} + +interface RawTransportDescriptor { + kind?: string; + command?: string; + args?: unknown[]; + options?: Record | WebSocketTransportOptions; + url?: string; +} + +interface RawLauncherConfig { + command?: string; + args?: unknown[]; + startCommand?: string | string[]; + checkCommand?: string; + install?: { command?: string }; + bridge?: RawBridgeConfig; +} + +interface RawServerDefinition { + id?: string; + label?: string; + enabled?: boolean; + languages?: string[]; + transport?: RawTransportDescriptor | TransportDescriptor; + initializationOptions?: Record; + clientConfig?: Record | AcodeClientConfig; + startupTimeout?: number; + capabilityOverrides?: Record; + rootUri?: + | ((uri: string, context: unknown) => string | null) + | ((uri: string, context: RootUriContext) => string | null) + | null; + resolveLanguageId?: + | ((context: LanguageResolverContext) => string | null) + | null; + launcher?: RawLauncherConfig | LauncherConfig; + useWorkspaceFolders?: boolean; +} + +function sanitizeDefinition( + definition: RawServerDefinition, +): LspServerDefinition { + if (!definition || typeof definition !== "object") { + throw new TypeError("LSP server definition must be an object"); + } + + const id = toKey(definition.id); + if (!id) throw new Error("LSP server definition requires a non-empty id"); + + const transport: RawTransportDescriptor = definition.transport ?? {}; + const kind = (transport.kind ?? "stdio") as + | "stdio" + | "websocket" + | "external"; + + if (!transport || typeof transport !== "object") { + throw new Error(`LSP server ${id} is missing a transport descriptor`); + } + + if ( + !("languages" in definition) || + !sanitizeLanguages(definition.languages).length + ) { + throw new Error(`LSP server ${id} must declare supported languages`); + } + + if (kind === "stdio" && !transport.command) { + throw new Error(`LSP server ${id} (stdio) requires a command`); + } + + // Websocket transport requires a URL unless a bridge is configured for auto-port discovery + const hasBridge = definition.launcher?.bridge?.command; + if (kind === "websocket" && !transport.url && !hasBridge) { + throw new Error( + `LSP server ${id} (websocket) requires a url or a launcher bridge`, + ); + } + + const transportOptions: Record = + transport.options && typeof transport.options === "object" + ? { ...transport.options } + : {}; + + const sanitizedTransport: TransportDescriptor = { + kind, + command: transport.command, + args: Array.isArray(transport.args) + ? transport.args.map((arg) => String(arg)) + : undefined, + options: transportOptions, + url: transport.url, + protocols: undefined, + }; + + let launcher: LauncherConfig | undefined; + if (definition.launcher && typeof definition.launcher === "object") { + const rawLauncher = definition.launcher; + launcher = { + command: rawLauncher.command, + args: Array.isArray(rawLauncher.args) + ? rawLauncher.args.map((arg) => String(arg)) + : undefined, + startCommand: Array.isArray(rawLauncher.startCommand) + ? rawLauncher.startCommand.map((arg) => String(arg)) + : rawLauncher.startCommand, + checkCommand: rawLauncher.checkCommand, + install: + rawLauncher.install && typeof rawLauncher.install === "object" + ? { + command: rawLauncher.install.command ?? "", + } + : undefined, + bridge: sanitizeBridge(id, rawLauncher.bridge), + }; + } + + const sanitized: LspServerDefinition = { + id, + label: definition.label ?? id, + enabled: definition.enabled !== false, + languages: sanitizeLanguages(definition.languages), + transport: sanitizedTransport, + initializationOptions: clone(definition.initializationOptions), + clientConfig: clone(definition.clientConfig), + startupTimeout: + typeof definition.startupTimeout === "number" + ? definition.startupTimeout + : undefined, + capabilityOverrides: clone(definition.capabilityOverrides), + rootUri: + typeof definition.rootUri === "function" ? definition.rootUri : null, + resolveLanguageId: + typeof definition.resolveLanguageId === "function" + ? definition.resolveLanguageId + : null, + launcher, + useWorkspaceFolders: definition.useWorkspaceFolders === true, + }; + + if (!Object.keys(transportOptions).length) { + sanitized.transport.options = undefined; + } + + return sanitized; +} + +function resolveJsTsLanguageId( + languageId: string | undefined, + languageName: string | undefined, +): string | null { + const lang = toKey(languageId ?? languageName); + switch (lang) { + case "tsx": + case "typescriptreact": + return "typescriptreact"; + case "jsx": + case "javascriptreact": + return "javascriptreact"; + case "ts": + return "typescript"; + case "js": + return "javascript"; + default: + return lang || null; + } +} + +function notify(event: RegistryEventType, payload: LspServerDefinition): void { + listeners.forEach((fn) => { + try { + fn(event, payload); + } catch (error) { + console.error("LSP server registry listener failed", error); + } + }); +} + +export interface RegisterServerOptions { + replace?: boolean; +} + +export function registerServer( + definition: RawServerDefinition, + options: RegisterServerOptions = {}, +): LspServerDefinition { + const { replace = false } = options; + const normalized = sanitizeDefinition(definition); + const exists = registry.has(normalized.id); + if (exists && !replace) { + const existing = registry.get(normalized.id); + if (existing) return existing; + } + + registry.set(normalized.id, normalized); + notify("register", normalized); + return normalized; +} + +export function unregisterServer(id: string): boolean { + const key = toKey(id); + if (!key || !registry.has(key)) return false; + const existing = registry.get(key); + registry.delete(key); + if (existing) { + notify("unregister", existing); + } + return true; +} + +export type ServerUpdater = ( + current: LspServerDefinition, +) => Partial | null; + +export function updateServer( + id: string, + updater: ServerUpdater, +): LspServerDefinition | null { + const key = toKey(id); + if (!key || !registry.has(key)) return null; + const current = registry.get(key); + if (!current) return null; + const next = updater({ ...current }); + if (!next) return current; + const normalized = sanitizeDefinition({ + ...current, + ...next, + id: current.id, + }); + registry.set(key, normalized); + notify("update", normalized); + return normalized; +} + +export function getServer(id: string): LspServerDefinition | null { + return registry.get(toKey(id)) ?? null; +} + +export function listServers(): LspServerDefinition[] { + return Array.from(registry.values()); +} + +export interface GetServersOptions { + includeDisabled?: boolean; +} + +export function getServersForLanguage( + languageId: string, + options: GetServersOptions = {}, +): LspServerDefinition[] { + const { includeDisabled = false } = options; + const langKey = toKey(languageId); + if (!langKey) return []; + + return listServers().filter((server) => { + if (!includeDisabled && !server.enabled) return false; + return server.languages.includes(langKey); + }); +} + +export function onRegistryChange(listener: RegistryEventListener): () => void { + if (typeof listener !== "function") return () => {}; + listeners.add(listener); + return () => listeners.delete(listener); +} + +function registerBuiltinServers(): void { + const defaults: RawServerDefinition[] = [ + { + id: "typescript", + label: "TypeScript / JavaScript", + useWorkspaceFolders: true, + languages: [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "tsx", + "jsx", + ], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "typescript-language-server", + args: ["--stdio"], + }, + checkCommand: "which typescript-language-server", + install: { + command: + "apk add --no-cache nodejs npm && npm install -g typescript-language-server typescript", + }, + }, + enabled: true, + initializationOptions: { + provideFormatter: true, + hostInfo: "acode", + tsserver: { + maxTsServerMemory: 4096, + useSeparateSyntaxServer: true, + }, + preferences: { + includeInlayParameterNameHints: "all", + includeInlayParameterNameHintsWhenArgumentMatchesName: true, + includeInlayFunctionParameterTypeHints: true, + includeInlayVariableTypeHints: true, + includeInlayVariableTypeHintsWhenTypeMatchesName: false, + includeInlayPropertyDeclarationTypeHints: true, + includeInlayFunctionLikeReturnTypeHints: true, + includeInlayEnumMemberValueHints: true, + importModuleSpecifierPreference: "shortest", + importModuleSpecifierEnding: "auto", + includePackageJsonAutoImports: "auto", + provideRefactorNotApplicableReason: true, + allowIncompleteCompletions: true, + allowRenameOfImportPath: true, + generateReturnInDocTemplate: true, + organizeImportsIgnoreCase: "auto", + organizeImportsCollation: "ordinal", + organizeImportsCollationConfig: "default", + autoImportFileExcludePatterns: [], + preferTypeOnlyAutoImports: false, + }, + completions: { + completeFunctionCalls: true, + }, + diagnostics: { + reportStyleChecksAsWarnings: true, + }, + }, + resolveLanguageId: ({ languageId, languageName }) => + resolveJsTsLanguageId(languageId, languageName), + }, + { + id: "vtsls", + label: "TypeScript / JavaScript (vtsls)", + useWorkspaceFolders: true, + languages: [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "tsx", + "jsx", + ], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "vtsls", + args: ["--stdio"], + }, + checkCommand: "which vtsls", + install: { + command: + "apk add --no-cache nodejs npm && npm install -g @vtsls/language-server", + }, + }, + enabled: false, + initializationOptions: { + hostInfo: "acode", + typescript: { + enablePromptUseWorkspaceTsdk: true, + inlayHints: { + parameterNames: { + enabled: "all", + suppressWhenArgumentMatchesName: false, + }, + parameterTypes: { + enabled: true, + }, + variableTypes: { + enabled: true, + suppressWhenTypeMatchesName: false, + }, + propertyDeclarationTypes: { + enabled: true, + }, + functionLikeReturnTypes: { + enabled: true, + }, + enumMemberValues: { + enabled: true, + }, + }, + suggest: { + completeFunctionCalls: true, + includeCompletionsForModuleExports: true, + includeCompletionsWithInsertText: true, + includeAutomaticOptionalChainCompletions: true, + includeCompletionsWithSnippetText: true, + includeCompletionsWithClassMemberSnippets: true, + includeCompletionsWithObjectLiteralMethodSnippets: true, + autoImports: true, + classMemberSnippets: { + enabled: true, + }, + objectLiteralMethodSnippets: { + enabled: true, + }, + }, + preferences: { + importModuleSpecifier: "shortest", + importModuleSpecifierEnding: "auto", + includePackageJsonAutoImports: "auto", + preferTypeOnlyAutoImports: false, + quoteStyle: "auto", + jsxAttributeCompletionStyle: "auto", + }, + format: { + enable: true, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false, + semicolons: "ignore", + }, + updateImportsOnFileMove: { + enabled: "always", + }, + codeActionsOnSave: { + organizeImports: false, + addMissingImports: false, + }, + workspaceSymbols: { + scope: "allOpenProjects", + }, + }, + javascript: { + inlayHints: { + parameterNames: { + enabled: "all", + suppressWhenArgumentMatchesName: false, + }, + parameterTypes: { + enabled: true, + }, + variableTypes: { + enabled: true, + suppressWhenTypeMatchesName: false, + }, + propertyDeclarationTypes: { + enabled: true, + }, + functionLikeReturnTypes: { + enabled: true, + }, + enumMemberValues: { + enabled: true, + }, + }, + suggest: { + completeFunctionCalls: true, + includeCompletionsForModuleExports: true, + autoImports: true, + classMemberSnippets: { + enabled: true, + }, + }, + preferences: { + importModuleSpecifier: "shortest", + quoteStyle: "auto", + }, + format: { + enable: true, + }, + updateImportsOnFileMove: { + enabled: "always", + }, + }, + tsserver: { + maxTsServerMemory: 8092, + }, + vtsls: { + experimental: { + completion: { + enableServerSideFuzzyMatch: true, + entriesLimit: 5000, + }, + }, + autoUseWorkspaceTsdk: true, + }, + }, + resolveLanguageId: ({ languageId, languageName }) => + resolveJsTsLanguageId(languageId, languageName), + }, + { + id: "python", + label: "Python (pylsp)", + languages: ["python"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "pylsp", + }, + checkCommand: "which pylsp", + install: { + command: + "apk update && apk upgrade && apk add python3 py3-pip && PIP_BREAK_SYSTEM_PACKAGES=1 pip install 'python-lsp-server[all]'", + }, + }, + initializationOptions: { + pylsp: { + plugins: { + pyflakes: { enabled: true }, + pycodestyle: { enabled: true }, + mccabe: { enabled: true }, + }, + }, + }, + enabled: true, + }, + { + id: "eslint", + label: "ESLint", + languages: [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "tsx", + "jsx", + "vue", + "svelte", + "html", + "markdown", + "json", + "jsonc", + ], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "vscode-eslint-language-server", + args: ["--stdio"], + }, + checkCommand: "which vscode-eslint-language-server", + install: { + command: + "apk add --no-cache nodejs npm && npm install -g vscode-langservers-extracted", + }, + }, + enabled: false, + initializationOptions: { + validate: "on", + rulesCustomizations: [], + run: "onType", + nodePath: null, + workingDirectory: { + mode: "auto", + }, + problems: { + shortenToSingleLine: false, + }, + codeActionOnSave: { + enable: true, + rules: [], + mode: "all", + }, + codeAction: { + disableRuleComment: { + enable: true, + location: "separateLine", + commentStyle: "line", + }, + showDocumentation: { + enable: true, + }, + }, + experimental: { + useFlatConfig: false, + }, + format: { + enable: true, + }, + quiet: false, + onIgnoredFiles: "off", + useESLintClass: false, + }, + clientConfig: { + builtinExtensions: { + hover: false, + completion: false, + signature: false, + keymaps: false, + diagnostics: true, + }, + }, + resolveLanguageId: ({ languageId, languageName }) => + resolveJsTsLanguageId(languageId, languageName), + }, + { + id: "clangd", + label: "C / C++ (clangd)", + languages: ["c", "cpp"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "clangd", + }, + checkCommand: "which clangd", + install: { + command: "apk add --no-cache clang-extra-tools", + }, + }, + enabled: false, + }, + { + id: "html", + label: "HTML", + languages: ["html", "vue", "svelte"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "vscode-html-language-server", + args: ["--stdio"], + }, + checkCommand: "which vscode-html-language-server", + install: { + command: + "apk add --no-cache nodejs npm && npm install -g vscode-langservers-extracted", + }, + }, + enabled: true, + }, + { + id: "css", + label: "CSS", + languages: ["css", "scss", "less"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "vscode-css-language-server", + args: ["--stdio"], + }, + checkCommand: "which vscode-css-language-server", + install: { + command: + "apk add --no-cache nodejs npm && npm install -g vscode-langservers-extracted", + }, + }, + enabled: true, + }, + { + id: "json", + label: "JSON", + languages: ["json", "jsonc"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "vscode-json-language-server", + args: ["--stdio"], + }, + checkCommand: "which vscode-json-language-server", + install: { + command: + "apk add --no-cache nodejs npm && npm install -g vscode-langservers-extracted", + }, + }, + enabled: true, + }, + { + id: "gopls", + label: "Go (gopls)", + languages: ["go", "go.mod", "go.sum", "gotmpl"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "gopls", + args: ["serve"], + }, + checkCommand: "which gopls", + install: { + command: "apk add --no-cache go gopls", + }, + }, + initializationOptions: { + usePlaceholders: false, + completeUnimported: true, + deepCompletion: true, + completionBudget: "100ms", + matcher: "Fuzzy", + staticcheck: true, + gofumpt: true, + hints: { + assignVariableTypes: true, + compositeLiteralFields: true, + compositeLiteralTypes: true, + constantValues: true, + functionTypeParameters: true, + parameterNames: true, + rangeVariableTypes: true, + }, + diagnosticsDelay: "250ms", + diagnosticsTrigger: "Edit", + annotations: { + bounds: true, + escape: true, + inline: true, + nil: true, + }, + semanticTokens: true, + analyses: { + nilness: true, + unusedparams: true, + unusedvariable: true, + unusedwrite: true, + shadow: true, + fieldalignment: false, + stringintconv: true, + }, + importShortcut: "Both", + symbolMatcher: "FastFuzzy", + symbolStyle: "Dynamic", + symbolScope: "all", + local: "", + linksInHover: true, + hoverKind: "FullDocumentation", + verboseOutput: false, + }, + enabled: true, + }, + { + id: "rust-analyzer", + label: "Rust (rust-analyzer)", + useWorkspaceFolders: true, + languages: ["rust"], + transport: { + kind: "websocket", + }, + launcher: { + bridge: { + kind: "axs", + command: "rust-analyzer", + }, + checkCommand: "which rust-analyzer", + install: { + command: "apk add --no-cache rust cargo rust-analyzer", + }, + }, + initializationOptions: { + cargo: { + allFeatures: true, + buildScripts: { + enable: true, + }, + loadOutDirsFromCheck: true, + }, + procMacro: { + enable: true, + attributes: { + enable: true, + }, + }, + checkOnSave: { + enable: true, + command: "clippy", + extraArgs: ["--no-deps"], + }, + diagnostics: { + enable: true, + experimental: { + enable: true, + }, + }, + inlayHints: { + bindingModeHints: { + enable: false, + }, + chainingHints: { + enable: true, + }, + closingBraceHints: { + enable: true, + minLines: 25, + }, + closureReturnTypeHints: { + enable: "with_block", + }, + lifetimeElisionHints: { + enable: "skip_trivial", + useParameterNames: true, + }, + maxLength: 25, + parameterHints: { + enable: true, + }, + reborrowHints: { + enable: "mutable", + }, + typeHints: { + enable: true, + hideClosureInitialization: false, + hideNamedConstructor: false, + }, + }, + lens: { + enable: true, + debug: { + enable: true, + }, + implementations: { + enable: true, + }, + references: { + adt: { enable: false }, + enumVariant: { enable: false }, + method: { enable: false }, + trait: { enable: false }, + }, + run: { + enable: true, + }, + }, + completion: { + autoimport: { + enable: true, + }, + autoself: { + enable: true, + }, + callable: { + snippets: "fill_arguments", + }, + postfix: { + enable: true, + }, + privateEditable: { + enable: false, + }, + }, + semanticHighlighting: { + doc: { + comment: { + inject: { + enable: true, + }, + }, + }, + operator: { + enable: true, + specialization: { + enable: true, + }, + }, + punctuation: { + enable: false, + separate: { + macro: { + bang: true, + }, + }, + specialization: { + enable: true, + }, + }, + strings: { + enable: true, + }, + }, + hover: { + actions: { + debug: { + enable: true, + }, + enable: true, + gotoTypeDef: { + enable: true, + }, + implementations: { + enable: true, + }, + references: { + enable: true, + }, + run: { + enable: true, + }, + }, + documentation: { + enable: true, + }, + links: { + enable: true, + }, + }, + workspace: { + symbol: { + search: { + kind: "all_symbols", + scope: "workspace", + }, + }, + }, + rustfmt: { + extraArgs: [], + overrideCommand: null, + rangeFormatting: { + enable: false, + }, + }, + }, + enabled: true, + }, + ]; + + defaults.forEach((def) => { + try { + registerServer(def, { replace: false }); + } catch (error) { + console.error("Failed to register builtin LSP server", def.id, error); + } + }); +} + +registerBuiltinServers(); + +export default { + registerServer, + unregisterServer, + updateServer, + getServer, + getServersForLanguage, + listServers, + onRegistryChange, +}; diff --git a/src/cm/lsp/transport.ts b/src/cm/lsp/transport.ts new file mode 100644 index 000000000..d41f939c6 --- /dev/null +++ b/src/cm/lsp/transport.ts @@ -0,0 +1,397 @@ +/* + Language servers that expose stdio are proxied through a lightweight + WebSocket bridge so the CodeMirror client can continue to speak WebSocket. +*/ + +import type { Transport } from "@codemirror/lsp-client"; +import type { + LspServerDefinition, + TransportContext, + TransportHandle, + WebSocketTransportOptions, +} from "./types"; + +const DEFAULT_TIMEOUT = 5000; +const RECONNECT_BASE_DELAY = 500; +const RECONNECT_MAX_DELAY = 10000; +const RECONNECT_MAX_ATTEMPTS = 5; + +type MessageListener = (data: string) => void; + +interface TransportInterface extends Transport { + send(message: string): void; + subscribe(handler: MessageListener): void; + unsubscribe(handler: MessageListener): void; +} + +function createWebSocketTransport( + server: LspServerDefinition, + context: TransportContext, +): TransportHandle { + const transport = server.transport; + if (!transport) { + throw new Error( + `LSP server ${server.id} is missing transport configuration`, + ); + } + + let url = transport.url; + const options: WebSocketTransportOptions = transport.options ?? {}; + + // Use dynamic port from auto-port discovery if available + if (context.dynamicPort && context.dynamicPort > 0) { + url = `ws://127.0.0.1:${context.dynamicPort}/`; + console.info( + `[LSP:${server.id}] Using auto-discovered port ${context.dynamicPort}`, + ); + } + + // URL is only required when not using dynamic port + if (!url) { + throw new Error( + `WebSocket transport for ${server.id} has no URL (and no dynamic port available)`, + ); + } + + // Store validated URL in a const for TypeScript narrowing in nested functions + const wsUrl: string = url; + + const listeners = new Set(); + const binaryMode = !!options.binary; + const timeout = options.timeout ?? DEFAULT_TIMEOUT; + const enableReconnect = options.reconnect !== false; + const maxReconnectAttempts = + options.maxReconnectAttempts ?? RECONNECT_MAX_ATTEMPTS; + + let socket: WebSocket | null = null; + let disposed = false; + let reconnectAttempts = 0; + let reconnectTimer: ReturnType | null = null; + let connected = false; + + const encoder = binaryMode ? new TextEncoder() : null; + + function createSocket(): WebSocket { + try { + // pylsp's websocket endpoint does not require subprotocol negotiation. + // Avoid passing protocols to keep the handshake simple. + const ws = new WebSocket(wsUrl); + if (binaryMode) { + ws.binaryType = "arraybuffer"; + } + return ws; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error( + `Failed to construct WebSocket for ${server.id} (${wsUrl}): ${message}`, + ); + } + } + + function handleMessage(event: MessageEvent): void { + let data: string; + if (typeof event.data === "string") { + data = event.data; + } else if (event.data instanceof Blob) { + // Handle Blob synchronously by queuing - avoids async ordering issues + event.data + .text() + .then((text: string) => { + dispatchToListeners(text); + }) + .catch((err: Error) => { + console.error("Failed to read Blob message", err); + }); + return; + } else if (event.data instanceof ArrayBuffer) { + data = new TextDecoder().decode(event.data); + } else { + console.warn( + "Unknown WebSocket message type", + typeof event.data, + event.data, + ); + data = String(event.data); + } + dispatchToListeners(data); + } + + function dispatchToListeners(data: string): void { + // Debugging aid while stabilising websocket transport + if (context?.debugWebSocket) { + console.debug(`[LSP:${server.id}] <=`, data); + } + + // Temporary fix + // Intercept server requests that the CodeMirror LSP client doesn't handle + // The client only handles notifications, but some servers (e.g., TypeScript) + // send requests like window/workDoneProgress/create that need a response + try { + const msg = JSON.parse(data); + if ( + msg && + typeof msg.id !== "undefined" && + msg.method === "window/workDoneProgress/create" + ) { + // This is a request, respond with success + const response = JSON.stringify({ + jsonrpc: "2.0", + id: msg.id, + result: null, + }); + if (context?.debugWebSocket) { + console.debug(`[LSP:${server.id}] => (auto-response)`, response); + } + if (socket && socket.readyState === WebSocket.OPEN) { + if (binaryMode && encoder) { + socket.send(encoder.encode(response)); + } else { + socket.send(response); + } + } + // Don't pass this request to listeners since we handled it + console.info( + `[LSP:${server.id}] Auto-responded to window/workDoneProgress/create`, + ); + return; + } + } catch (_) { + // Not valid JSON or missing fields, pass through normally + } + + listeners.forEach((listener) => { + try { + listener(data); + } catch (error) { + console.error("LSP transport listener failed", error); + } + }); + } + + function handleClose(event: CloseEvent): void { + connected = false; + if (disposed) return; + + const wasClean = event.wasClean || event.code === 1000; + if (wasClean) { + console.info(`[LSP:${server.id}] WebSocket closed cleanly`); + return; + } + + console.warn( + `[LSP:${server.id}] WebSocket closed unexpectedly (code: ${event.code})`, + ); + + if (enableReconnect && reconnectAttempts < maxReconnectAttempts) { + scheduleReconnect(); + } else if (reconnectAttempts >= maxReconnectAttempts) { + console.error(`[LSP:${server.id}] Max reconnection attempts reached`); + } + } + + function handleError(event: Event): void { + if (disposed) return; + const errorEvent = event as ErrorEvent; + const reason = + errorEvent?.message || errorEvent?.type || "connection error"; + console.error(`[LSP:${server.id}] WebSocket error: ${reason}`); + } + + function scheduleReconnect(): void { + if (disposed || reconnectTimer) return; + + const delay = Math.min( + RECONNECT_BASE_DELAY * Math.pow(2, reconnectAttempts), + RECONNECT_MAX_DELAY, + ); + reconnectAttempts++; + + console.info( + `[LSP:${server.id}] Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${maxReconnectAttempts})`, + ); + + reconnectTimer = setTimeout(() => { + reconnectTimer = null; + if (disposed) return; + attemptReconnect(); + }, delay); + } + + function attemptReconnect(): void { + if (disposed) return; + + try { + socket = createSocket(); + setupSocketHandlers(socket); + + socket.onopen = () => { + connected = true; + reconnectAttempts = 0; + console.info(`[LSP:${server.id}] Reconnected successfully`); + if (socket) { + socket.onopen = null; + } + }; + } catch (error) { + console.error(`[LSP:${server.id}] Reconnection failed`, error); + if (reconnectAttempts < maxReconnectAttempts) { + scheduleReconnect(); + } + } + } + + function setupSocketHandlers(ws: WebSocket): void { + ws.onmessage = handleMessage; + ws.onclose = handleClose; + ws.onerror = handleError; + } + + // Initial socket creation + socket = createSocket(); + + const ready = new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + if (socket) { + socket.onopen = null; + socket.onerror = null; + } + try { + socket?.close(); + } catch (_) { + // Ignore close errors + } + reject(new Error(`Timed out opening WebSocket for ${server.id}`)); + }, timeout); + + if (socket) { + socket.onopen = () => { + clearTimeout(timeoutId); + connected = true; + if (socket) { + setupSocketHandlers(socket); + } + resolve(); + }; + + socket.onerror = (event: Event) => { + clearTimeout(timeoutId); + if (socket) { + socket.onopen = null; + socket.onerror = null; + } + const errorEvent = event as ErrorEvent; + const reason = + errorEvent?.message || errorEvent?.type || "connection error"; + reject(new Error(`WebSocket error for ${server.id}: ${reason}`)); + }; + } + }); + + const transportInterface: TransportInterface = { + send(message: string): void { + if (!connected || !socket || socket.readyState !== WebSocket.OPEN) { + throw new Error("WebSocket transport is not open"); + } + if (binaryMode && encoder) { + socket.send(encoder.encode(message)); + } else { + socket.send(message); + } + }, + subscribe(handler: MessageListener): void { + listeners.add(handler); + }, + unsubscribe(handler: MessageListener): void { + listeners.delete(handler); + }, + }; + + const dispose = (): void => { + disposed = true; + connected = false; + + if (reconnectTimer) { + clearTimeout(reconnectTimer); + reconnectTimer = null; + } + + listeners.clear(); + + if (socket) { + if ( + socket.readyState === WebSocket.CLOSED || + socket.readyState === WebSocket.CLOSING + ) { + return; + } + try { + socket.close(1000, "Client disposed"); + } catch (_) { + // Ignore close errors + } + } + }; + + return { transport: transportInterface, dispose, ready }; +} + +function createStdioTransport( + server: LspServerDefinition, + context: TransportContext, +): TransportHandle { + if (!server.transport) { + throw new Error( + `LSP server ${server.id} is missing transport configuration`, + ); + } + if (!server.transport.url) { + throw new Error( + `STDIO transport for ${server.id} is missing a websocket bridge url`, + ); + } + if (!server.transport.options?.binary) { + console.info( + `LSP server ${server.id} is using stdio bridge without binary mode. Falling back to text frames.`, + ); + } + return createWebSocketTransport(server, context); +} + +export function createTransport( + server: LspServerDefinition, + context: TransportContext = {}, +): TransportHandle { + if (!server) { + throw new Error("createTransport requires a server configuration"); + } + if (!server.transport) { + throw new Error( + `LSP server ${server.id || "unknown"} is missing transport configuration`, + ); + } + + const kind = server.transport.kind; + if (!kind) { + throw new Error( + `LSP server ${server.id} transport is missing 'kind' property`, + ); + } + + switch (kind) { + case "websocket": + return createWebSocketTransport(server, context); + case "stdio": + return createStdioTransport(server, context); + case "external": + if (typeof server.transport.create === "function") { + return server.transport.create(server, context); + } + throw new Error( + `LSP server ${server.id} declares an external transport without a create() factory`, + ); + default: + throw new Error(`Unsupported transport kind: ${kind}`); + } +} + +export default { createTransport }; diff --git a/src/cm/lsp/types.ts b/src/cm/lsp/types.ts new file mode 100644 index 000000000..9eae2072c --- /dev/null +++ b/src/cm/lsp/types.ts @@ -0,0 +1,430 @@ +import type { + LSPClient, + LSPClientConfig, + LSPClientExtension, + Transport, + Workspace, + WorkspaceFile, +} from "@codemirror/lsp-client"; +import type { ChangeSet, Extension, MapMode, Text } from "@codemirror/state"; +import type { EditorView } from "@codemirror/view"; + +import type { + Diagnostic as LSPDiagnostic, + FormattingOptions as LSPFormattingOptions, + Position, + Range, + TextEdit, +} from "vscode-languageserver-types"; + +export type { + LSPClient, + LSPClientConfig, + LSPClientExtension, + Transport, + Workspace, + WorkspaceFile, + TextEdit, + LSPFormattingOptions, + LSPDiagnostic, + Range, + Position, +}; + +export interface WorkspaceFileUpdate { + file: WorkspaceFile; + prevDoc: Text; + changes: ChangeSet; +} + +// ============================================================================ +// Transport Types +// ============================================================================ + +export type TransportKind = "websocket" | "stdio" | "external"; + +export interface WebSocketTransportOptions { + binary?: boolean; + timeout?: number; + reconnect?: boolean; + maxReconnectAttempts?: number; +} + +export interface TransportDescriptor { + kind: TransportKind; + url?: string; + command?: string; + args?: string[]; + options?: WebSocketTransportOptions; + protocols?: string[]; + create?: ( + server: LspServerDefinition, + context: TransportContext, + ) => TransportHandle; +} + +export interface TransportHandle { + transport: Transport; + dispose: () => Promise | void; + ready: Promise; +} + +export interface TransportContext { + uri?: string; + file?: AcodeFile; + view?: EditorView; + languageId?: string; + rootUri?: string | null; + originalRootUri?: string; + debugWebSocket?: boolean; + /** Dynamically discovered port from auto-port discovery */ + dynamicPort?: number; +} + +// ============================================================================ +// Server Registry Types +// ============================================================================ + +export interface BridgeConfig { + kind: "axs"; + /** Optional port - if not provided, auto-port discovery will be used */ + port?: number; + command: string; + args?: string[]; + /** Session ID for port file naming (defaults to command name) */ + session?: string; +} + +export interface LauncherInstallConfig { + command: string; +} + +export interface LauncherConfig { + command?: string; + args?: string[]; + startCommand?: string | string[]; + checkCommand?: string; + install?: LauncherInstallConfig; + bridge?: BridgeConfig; +} + +export interface BuiltinExtensionsConfig { + hover?: boolean; + completion?: boolean; + signature?: boolean; + keymaps?: boolean; + diagnostics?: boolean; + inlayHints?: boolean; + documentHighlights?: boolean; +} + +export interface AcodeClientConfig { + useDefaultExtensions?: boolean; + builtinExtensions?: BuiltinExtensionsConfig; + extensions?: (Extension | LSPClientExtension)[]; + notificationHandlers?: Record< + string, + (client: LSPClient, params: unknown) => boolean + >; + workspace?: (client: LSPClient) => Workspace; + rootUri?: string; + timeout?: number; +} + +export interface LanguageResolverContext { + languageId: string; + languageName?: string; + uri?: string; + file?: AcodeFile; +} + +export interface LspServerDefinition { + id: string; + label: string; + enabled: boolean; + languages: string[]; + transport: TransportDescriptor; + initializationOptions?: Record; + clientConfig?: AcodeClientConfig; + startupTimeout?: number; + capabilityOverrides?: Record; + rootUri?: ((uri: string, context: RootUriContext) => string | null) | null; + resolveLanguageId?: + | ((context: LanguageResolverContext) => string | null) + | null; + launcher?: LauncherConfig; + /** + * When true, uses a single server instance with workspace folders + * instead of starting separate servers per project root. + * Heavy LSP servers like TypeScript and rust-analyzer should use this. + */ + useWorkspaceFolders?: boolean; +} + +export interface RootUriContext { + uri?: string; + file?: AcodeFile; + view?: EditorView; + languageId?: string; + rootUri?: string; +} + +export type RegistryEventType = "register" | "unregister" | "update"; + +export type RegistryEventListener = ( + event: RegistryEventType, + server: LspServerDefinition, +) => void; + +// ============================================================================ +// Client Manager Types +// ============================================================================ + +export interface FileMetadata { + uri: string; + languageId?: string; + languageName?: string; + view?: EditorView; + file?: AcodeFile; + rootUri?: string; +} + +export interface FormattingOptions { + tabSize?: number; + insertSpaces?: boolean; + [key: string]: unknown; +} + +export interface ClientManagerOptions { + diagnosticsUiExtension?: Extension | Extension[]; + clientExtensions?: Extension | Extension[]; + resolveRoot?: (context: RootUriContext) => Promise; + displayFile?: (uri: string) => Promise; + openFile?: (uri: string) => Promise; + resolveLanguageId?: (uri: string) => string | null; + onClientIdle?: (info: ClientIdleInfo) => void; +} + +export interface ClientIdleInfo { + server: LspServerDefinition; + client: LSPClient; + rootUri: string | null; +} + +export interface ClientState { + server: LspServerDefinition; + client: LSPClient; + transport: TransportHandle; + rootUri: string | null; + attach: (uri: string, view: EditorView) => void; + detach: (uri: string, view?: EditorView) => void; + dispose: () => Promise; +} + +export interface NormalizedRootUri { + normalizedRootUri: string | null; + originalRootUri: string | null; +} + +// ============================================================================ +// Server Launcher Types +// ============================================================================ + +export interface ManagedServerEntry { + uuid: string; + command: string; + startedAt: number; + /** Port number for the axs proxy (for stats endpoint) */ + port?: number; +} + +export type InstallStatus = "present" | "declined" | "failed"; + +/** + * Port information from auto-port discovery + */ +export interface PortInfo { + /** The discovered port number */ + port: number; + /** Path to the port file */ + filePath: string; + /** Session ID used for the port file */ + session: string; +} + +export interface WaitOptions { + attempts?: number; + delay?: number; + probeTimeout?: number; +} + +/** + * Result from ensureServerRunning + */ +export interface EnsureServerResult { + uuid: string | null; + /** Port discovered from port file (for auto-port discovery) */ + discoveredPort?: number; +} + +/** + * Stats returned from the axs proxy /status endpoint + */ +export interface LspServerStats { + program: string; + processes: Array<{ + pid: number; + uptime_secs: number; + memory_bytes: number; + }>; +} + +/** + * Formatted stats for UI display + */ +export interface LspServerStatsFormatted { + memoryBytes: number; + memoryFormatted: string; + uptimeSeconds: number; + uptimeFormatted: string; + pid: number | null; + processCount: number; +} + +// ============================================================================ +// Workspace Types +// ============================================================================ + +export interface WorkspaceOptions { + displayFile?: (uri: string) => Promise; + openFile?: (uri: string) => Promise; + resolveLanguageId?: (uri: string) => string | null; +} + +// ============================================================================ +// Diagnostics Types +// ============================================================================ + +export interface LspDiagnostic { + from: number; + to: number; + severity: "error" | "warning" | "info" | "hint"; + message: string; + source?: string; + /** Related diagnostic information (e.g., location of declaration for 'unused' errors) */ + relatedInformation?: DiagnosticRelatedInformation[]; +} + +/** Related information for a diagnostic (mapped to editor positions) */ +export interface DiagnosticRelatedInformation { + /** Document URI */ + uri: string; + /** Start position (offset in document) */ + from: number; + /** End position (offset in document) */ + to: number; + /** Message describing the relationship */ + message: string; +} + +export interface PublishDiagnosticsParams { + uri: string; + version?: number; + diagnostics: RawDiagnostic[]; +} + +export interface RawDiagnostic { + range: Range; + severity?: number; + code?: number | string; + source?: string; + message: string; + /** Related diagnostic locations from LSP (raw positions) */ + relatedInformation?: RawDiagnosticRelatedInformation[]; +} + +/** Raw related information from LSP (before position mapping) */ +export interface RawDiagnosticRelatedInformation { + location: { + uri: string; + range: Range; + }; + message: string; +} + +// ============================================================================ +// Formatter Types +// ============================================================================ + +export interface AcodeApi { + registerFormatter: ( + id: string, + extensions: string[], + formatter: () => Promise, + label: string, + ) => void; +} + +/** + * Uri utility interface + */ +export interface ParsedUri { + docId?: string; + rootUri?: string; + isFileUri?: boolean; +} + +/** + * Interface representing the LSPPlugin instance API. + */ +export interface LSPPluginAPI { + /** The document URI this plugin is attached to */ + uri: string; + /** The LSP client instance */ + client: LSPClient & { sync: () => void; connected?: boolean }; + /** Convert a document offset to an LSP Position */ + toPosition: (offset: number) => { line: number; character: number }; + /** Convert an LSP Position to a document offset */ + fromPosition: ( + pos: { line: number; character: number }, + doc?: unknown, + ) => number; + /** The currently synced document state */ + syncedDoc: { length: number }; + /** Pending changes that haven't been synced yet */ + unsyncedChanges: { + mapPos: (pos: number, assoc?: number, mode?: MapMode) => number | null; + empty: boolean; + }; + /** Clear pending changes */ + clear: () => void; +} + +/** + * Interface for workspace file with view access + */ +export interface WorkspaceFileWithView { + version: number; + getView: () => EditorView | null; +} + +/** + * Interface for workspace with file access + */ +export interface WorkspaceWithFileAccess { + getFile: (uri: string) => WorkspaceFileWithView | null; +} + +/** + * LSPClient with workspace access (for type casting in notification handlers) + */ +export interface LSPClientWithWorkspace { + workspace: WorkspaceWithFileAccess; +} + +// Extend the LSPClient with Acode-specific properties +declare module "@codemirror/lsp-client" { + interface LSPClient { + __acodeLoggedInfo?: boolean; + } +} diff --git a/src/cm/lsp/workspace.ts b/src/cm/lsp/workspace.ts new file mode 100644 index 000000000..d6218843b --- /dev/null +++ b/src/cm/lsp/workspace.ts @@ -0,0 +1,284 @@ +import type { WorkspaceFile } from "@codemirror/lsp-client"; +import { LSPPlugin, Workspace } from "@codemirror/lsp-client"; +import type { Text, TransactionSpec } from "@codemirror/state"; +import type { EditorView } from "@codemirror/view"; +import { getModeForPath } from "cm/modelist"; +import type { WorkspaceFileUpdate, WorkspaceOptions } from "./types"; + +class AcodeWorkspaceFile implements WorkspaceFile { + uri: string; + languageId: string; + version: number; + doc: Text; + views: Set; + + constructor( + uri: string, + languageId: string, + version: number, + doc: Text, + view?: EditorView, + ) { + this.uri = uri; + this.languageId = languageId; + this.version = version; + this.doc = doc; + this.views = new Set(); + if (view) this.views.add(view); + } + + getView(preferred?: EditorView): EditorView | null { + if (preferred && this.views.has(preferred)) return preferred; + const iterator = this.views.values(); + const next = iterator.next(); + return next.done ? null : next.value; + } +} + +export default class AcodeWorkspace extends Workspace { + files: AcodeWorkspaceFile[]; + options: WorkspaceOptions; + + #fileMap: Map; + #versions: Record; + #workspaceFolders: Set; + + constructor( + client: ConstructorParameters[0], + options: WorkspaceOptions = {}, + ) { + super(client); + this.files = []; + this.#fileMap = new Map(); + this.#versions = Object.create(null) as Record; + this.#workspaceFolders = new Set(); + this.options = options; + } + + #getOrCreateFile( + uri: string, + languageId: string, + view: EditorView, + ): AcodeWorkspaceFile { + let file = this.#fileMap.get(uri); + if (!file) { + const doc = view.state?.doc; + if (!doc) { + throw new Error( + `Cannot create workspace file without document: ${uri}`, + ); + } + file = new AcodeWorkspaceFile( + uri, + languageId, + this.#nextFileVersion(uri), + doc, + view, + ); + this.#fileMap.set(uri, file); + this.files.push(file); + this.client.didOpen(file); + } + file.views.add(view); + return file; + } + + #getFileEntry(uri: string): AcodeWorkspaceFile | null { + return this.#fileMap.get(uri) ?? null; + } + + #removeFileEntry(file: AcodeWorkspaceFile): void { + this.#fileMap.delete(file.uri); + this.files = this.files.filter((candidate) => candidate !== file); + } + + #nextFileVersion(uri: string): number { + const current = this.#versions[uri] ?? -1; + const next = current + 1; + this.#versions[uri] = next; + return next; + } + + #resolveLanguageIdForUri(uri: string): string { + if (typeof this.options.resolveLanguageId === "function") { + const resolved = this.options.resolveLanguageId(uri); + if (resolved) return resolved; + } + try { + const mode = getModeForPath(uri); + if (mode?.name) { + return String(mode.name).toLowerCase(); + } + } catch (_) {} + return "plaintext"; + } + + syncFiles(): readonly WorkspaceFileUpdate[] { + const updates: WorkspaceFileUpdate[] = []; + for (const file of this.files) { + const view = file.getView(); + if (!view) continue; + const plugin = LSPPlugin.get(view); + if (!plugin) continue; + const { unsyncedChanges } = plugin; + if (unsyncedChanges.empty) continue; + + updates.push({ file, prevDoc: file.doc, changes: unsyncedChanges }); + file.doc = view.state.doc; + file.version = this.#nextFileVersion(file.uri); + plugin.clear(); + } + return updates; + } + + openFile(uri: string, languageId: string, view: EditorView): void { + if (!view) return; + this.#getOrCreateFile(uri, languageId, view); + } + + closeFile(uri: string, view?: EditorView): void { + const file = this.#getFileEntry(uri); + if (!file) return; + + if (view && file.views.has(view)) { + file.views.delete(view); + } + + if (!file.views.size) { + this.client.didClose(uri); + this.#removeFileEntry(file); + } + } + + getFile(uri: string): AcodeWorkspaceFile | null { + return this.#getFileEntry(uri); + } + + requestFile(uri: string): Promise { + return Promise.resolve(this.#getFileEntry(uri)); + } + + connected(): void { + for (const file of this.files) { + this.client.didOpen(file); + } + } + + updateFile(uri: string, update: TransactionSpec): void { + const file = this.#getFileEntry(uri); + + if (file) { + const view = file.getView(); + if (view) { + view.dispatch(update); + return; + } + } + + // File is not open - try to open it and apply the update + this.#applyUpdateToClosedFile(uri, update).catch((error) => { + console.warn(`[LSP:Workspace] Failed to apply update: ${uri}`, error); + }); + } + + async #applyUpdateToClosedFile( + uri: string, + update: TransactionSpec, + ): Promise { + if (typeof this.options.displayFile !== "function") return; + + try { + const view = await this.options.displayFile(uri); + if (!view?.state?.doc) return; + const languageId = this.#resolveLanguageIdForUri(uri); + const file = this.#getOrCreateFile(uri, languageId, view); + const fileView = file.getView(); + if (fileView) { + fileView.dispatch(update); + } + } catch (error) { + console.error(`[LSP:Workspace] Failed to apply update: ${uri}`, error); + } + } + + async displayFile(uri: string): Promise { + if (typeof this.options.displayFile === "function") { + try { + return await this.options.displayFile(uri); + } catch (error) { + console.error("[LSP:Workspace] Failed to display file", error); + } + } + return null; + } + + // ======================================================================== + // Workspace Folders Support + // ======================================================================== + + #getFolderName(uri: string): string { + const parts = uri.replace(/\/$/, "").split("/"); + return parts[parts.length - 1] || uri; + } + + #sendNotification(method: string, params: unknown): void { + // Access the client's transport to send raw JSON-RPC notification + const client = this.client as unknown as { + connected: boolean; + transport?: { send: (message: string) => void }; + }; + + if (!client.connected || !client.transport) { + console.warn(`[LSP:Workspace] Cannot send notification: not connected`); + return; + } + + const message = JSON.stringify({ + jsonrpc: "2.0", + method, + params, + }); + + client.transport.send(message); + } + + hasWorkspaceFolder(uri: string): boolean { + return this.#workspaceFolders.has(uri); + } + + getWorkspaceFolders(): string[] { + return Array.from(this.#workspaceFolders); + } + + addWorkspaceFolder(uri: string): boolean { + if (this.#workspaceFolders.has(uri)) { + return false; + } + + this.#workspaceFolders.add(uri); + this.#sendNotification("workspace/didChangeWorkspaceFolders", { + event: { + added: [{ uri, name: this.#getFolderName(uri) }], + removed: [], + }, + }); + console.info(`[LSP:Workspace] Added workspace folder: ${uri}`); + return true; + } + + removeWorkspaceFolder(uri: string): boolean { + if (!this.#workspaceFolders.has(uri)) { + return false; + } + + this.#workspaceFolders.delete(uri); + this.#sendNotification("workspace/didChangeWorkspaceFolders", { + event: { + added: [], + removed: [{ uri, name: this.#getFolderName(uri) }], + }, + }); + console.info(`[LSP:Workspace] Removed workspace folder: ${uri}`); + return true; + } +} diff --git a/src/cm/modelist.ts b/src/cm/modelist.ts new file mode 100644 index 000000000..fe9be60ad --- /dev/null +++ b/src/cm/modelist.ts @@ -0,0 +1,165 @@ +import type { Extension } from "@codemirror/state"; + +export type LanguageExtensionProvider = () => Extension | Promise; + +export interface ModesByName { + [name: string]: Mode; +} + +const modesByName: ModesByName = {}; +const modes: Mode[] = []; + +/** + * Initialize CodeMirror mode list functionality + */ +export function initModes(): void { + // CodeMirror modes don't need the same ace.define wrapper + // but we maintain the same API structure for compatibility +} + +/** + * Add language mode to CodeMirror editor + */ +export function addMode( + name: string, + extensions: string | string[], + caption?: string, + languageExtension: LanguageExtensionProvider | null = null, +): void { + const filename = name.toLowerCase(); + const mode = new Mode(filename, caption, extensions, languageExtension); + modesByName[filename] = mode; + modes.push(mode); +} + +/** + * Remove language mode from CodeMirror editor + */ +export function removeMode(name: string): void { + const filename = name.toLowerCase(); + delete modesByName[filename]; + const modeIndex = modes.findIndex((mode) => mode.name === filename); + if (modeIndex >= 0) { + modes.splice(modeIndex, 1); + } +} + +/** + * Get mode for file path + */ +export function getModeForPath(path: string): Mode { + let mode = modesByName.text; + const fileName = path.split(/[/\\]/).pop() || ""; + + // Sort modes by specificity (descending) to check most specific first + const sortedModes = [...modes].sort((a, b) => { + return getModeSpecificityScore(b) - getModeSpecificityScore(a); + }); + + for (const iMode of sortedModes) { + if (iMode.supportsFile?.(fileName)) { + mode = iMode; + break; + } + } + return mode; +} + +/** + * Calculates a specificity score for a mode. + * Higher score means more specific. + * - Anchored patterns (e.g., "^Dockerfile") get a base score of 1000. + * - Non-anchored patterns (extensions) are scored by length. + */ +function getModeSpecificityScore(modeInstance: Mode): number { + const extensionsStr = modeInstance.extensions; + if (!extensionsStr) return 0; + + const patterns = extensionsStr.split("|"); + let maxScore = 0; + + for (const pattern of patterns) { + let currentScore = 0; + if (pattern.startsWith("^")) { + // Exact filename match or anchored pattern + currentScore = 1000 + (pattern.length - 1); // Subtract 1 for '^' + } else { + // Extension match + currentScore = pattern.length; + } + if (currentScore > maxScore) { + maxScore = currentScore; + } + } + return maxScore; +} + +/** + * Get all modes by name + */ +export function getModesByName(): ModesByName { + return modesByName; +} + +/** + * Get all modes array + */ +export function getModes(): Mode[] { + return modes; +} + +export class Mode { + extensions: string; + caption: string; + name: string; + mode: string; + extRe: RegExp; + languageExtension: LanguageExtensionProvider | null; + + constructor( + name: string, + caption: string | undefined, + extensions: string | string[], + languageExtension: LanguageExtensionProvider | null = null, + ) { + if (Array.isArray(extensions)) { + extensions = extensions.join("|"); + } + + this.name = name; + this.mode = name; // CodeMirror uses different mode naming + this.extensions = extensions; + this.caption = caption || this.name.replace(/_/g, " "); + this.languageExtension = languageExtension; + let re: string; + + if (/\^/.test(extensions)) { + re = + extensions.replace(/\|(\^)?/g, function (_a: string, b: string) { + return "$|" + (b ? "^" : "^.*\\."); + }) + "$"; + } else { + re = "^.*\\.(" + extensions + ")$"; + } + + this.extRe = new RegExp(re, "i"); + } + + supportsFile(filename: string): boolean { + return this.extRe.test(filename); + } + + /** + * Get the CodeMirror language extension + */ + getExtension(): LanguageExtensionProvider | null { + return this.languageExtension; + } + + /** + * Check if the language extension is available (loaded) + */ + isAvailable(): boolean { + return this.languageExtension !== null; + } +} diff --git a/src/cm/rainbowBrackets.ts b/src/cm/rainbowBrackets.ts new file mode 100644 index 000000000..b1929c9c9 --- /dev/null +++ b/src/cm/rainbowBrackets.ts @@ -0,0 +1,176 @@ +import { syntaxTree } from "@codemirror/language"; +import type { DecorationSet, ViewUpdate } from "@codemirror/view"; +import { Decoration, EditorView, ViewPlugin } from "@codemirror/view"; +import type { SyntaxNode } from "@lezer/common"; + +const COLORS = ["gold", "orchid", "lightblue"]; + +// Token types that should be skipped (brackets inside these are not colored) +const SKIP_CONTEXTS = new Set([ + "String", + "TemplateString", + "Comment", + "LineComment", + "BlockComment", + "RegExp", +]); + +interface BracketInfo { + from: number; + to: number; + depth: number; + char: string; +} + +const rainbowBracketsPlugin = ViewPlugin.fromClass( + class { + decorations: DecorationSet; + + constructor(view: EditorView) { + this.decorations = this.buildDecorations(view); + } + + update(update: ViewUpdate) { + if (update.docChanged || update.viewportChanged) { + this.decorations = this.buildDecorations(update.view); + } + } + + buildDecorations(view: EditorView): DecorationSet { + const decorations: { from: number; to: number; color: string }[] = []; + const tree = syntaxTree(view.state); + + // Process only visible ranges for performance + for (const { from, to } of view.visibleRanges) { + this.processRange(view, tree, from, to, decorations); + } + + // Sort by position (required for Decoration.set) + decorations.sort((a, b) => a.from - b.from); + + // Build decoration marks + const marks = decorations.map((d) => + Decoration.mark({ class: `cm-bracket-${d.color}` }).range(d.from, d.to), + ); + + return Decoration.set(marks); + } + + processRange( + view: EditorView, + tree: ReturnType, + from: number, + to: number, + decorations: { from: number; to: number; color: string }[], + ): void { + const { doc } = view.state; + const openBrackets: BracketInfo[] = []; + + // Iterate through the document in the visible range + for (let pos = from; pos < to; pos++) { + const char = doc.sliceString(pos, pos + 1); + + // Check if this is a bracket character + if (!this.isBracketChar(char)) continue; + + // Use syntax tree to check if this bracket should be colored + if (this.isInSkipContext(tree, pos)) continue; + + if (char === "(" || char === "[" || char === "{") { + // Opening bracket - push to stack with current depth + openBrackets.push({ + from: pos, + to: pos + 1, + depth: openBrackets.length, + char, + }); + } else if (char === ")" || char === "]" || char === "}") { + // Closing bracket - find matching open bracket + const matchingOpen = this.getMatchingOpenBracket(char); + let matchFound = false; + + // Search backwards for matching open bracket + for (let i = openBrackets.length - 1; i >= 0; i--) { + if (openBrackets[i].char === matchingOpen) { + const open = openBrackets[i]; + const depth = open.depth; + const color = COLORS[depth % COLORS.length]; + + // Add decorations for both brackets + decorations.push( + { from: open.from, to: open.to, color }, + { from: pos, to: pos + 1, color }, + ); + + // Remove matched bracket and all unmatched brackets after it + openBrackets.splice(i); + matchFound = true; + break; + } + } + + // If no match found, this is an unmatched closing bracket + if (!matchFound) { + // Unmatched closing bracket + } + } + } + } + + isBracketChar(char: string): boolean { + return ( + char === "(" || + char === ")" || + char === "[" || + char === "]" || + char === "{" || + char === "}" + ); + } + + isInSkipContext(tree: ReturnType, pos: number): boolean { + let node: SyntaxNode | null = tree.resolveInner(pos, 1); + + // Walk up the tree to check if we're inside a skip context + while (node) { + if (SKIP_CONTEXTS.has(node.name)) { + return true; + } + node = node.parent; + } + + return false; + } + + getMatchingOpenBracket(closing: string): string | null { + switch (closing) { + case ")": + return "("; + case "]": + return "["; + case "}": + return "{"; + default: + return null; + } + } + }, + { + decorations: (v) => v.decorations, + }, +); + +const theme = EditorView.baseTheme({ + ".cm-bracket-gold": { color: "#FFD700 !important" }, + ".cm-bracket-gold > span": { color: "#FFD700 !important" }, + ".cm-bracket-orchid": { color: "#DA70D6 !important" }, + ".cm-bracket-orchid > span": { color: "#DA70D6 !important" }, + ".cm-bracket-lightblue": { color: "#179FFF !important" }, + ".cm-bracket-lightblue > span": { color: "#179FFF !important" }, +}); + +export function rainbowBrackets() { + return [rainbowBracketsPlugin, theme]; +} + +export default rainbowBrackets; diff --git a/src/cm/supportedModes.ts b/src/cm/supportedModes.ts new file mode 100644 index 000000000..cb0941edd --- /dev/null +++ b/src/cm/supportedModes.ts @@ -0,0 +1,58 @@ +import { languages } from "@codemirror/language-data"; +import type { Extension } from "@codemirror/state"; +import { addMode } from "./modelist"; + +interface LanguageDescription { + name?: string; + extensions?: readonly string[]; + filenames?: readonly string[]; + filename?: string; + load?: () => Promise; +} + +// 1) Always register a plain text fallback +addMode("Text", "txt|text|log|plain", "Plain Text", () => []); + +// 2) Register all languages provided by @codemirror/language-data +// We convert extensions like [".js", ".mjs"] into a modelist pattern: "js|mjs" +// and include anchored filename patterns like "^Dockerfile" when present. +for (const lang of languages as readonly LanguageDescription[]) { + try { + const name = String(lang?.name || "").trim(); + if (!name) continue; + + const parts: string[] = []; + // File extensions + if (Array.isArray(lang.extensions)) { + for (const e of lang.extensions) { + if (typeof e !== "string") continue; + const cleaned = e.replace(/^\./, "").trim(); + if (cleaned) parts.push(cleaned); + } + } + // Exact filenames (dockerfile, makefile, etc.) + const filenames = Array.isArray(lang.filenames) + ? lang.filenames + : lang.filename + ? [lang.filename] + : []; + for (const fn of filenames) { + if (typeof fn !== "string") continue; + const cleaned = fn.trim(); + if (cleaned) parts.push(`^${cleaned}`); + } + + // Skip if we have no way to match the language + if (parts.length === 0) continue; + + const pattern = parts.join("|"); + + // Wrap language-data loader as our modelist language provider + // lang.load() returns a Promise; we let the editor handle async loading + const loader = typeof lang.load === "function" ? () => lang.load!() : null; + + addMode(name, pattern, name, loader); + } catch (_) { + // Ignore faulty entries to avoid breaking the whole registration + } +} diff --git a/src/cm/themes/aura.js b/src/cm/themes/aura.js new file mode 100644 index 000000000..fdbe82456 --- /dev/null +++ b/src/cm/themes/aura.js @@ -0,0 +1,150 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +// Aura theme configuration and extensions +export const config = { + name: "aura", + dark: true, + background: "#21202e", + foreground: "#edecee", + selection: "#3d375e7f", + cursor: "#a277ff", + dropdownBackground: "#21202e", + dropdownBorder: "#3b334b", + activeLine: "#4d4b6622", + lineNumber: "#a394f033", + lineNumberActive: "#cdccce", + matchingBracket: "#a394f033", + keyword: "#a277ff", + storage: "#a277ff", + variable: "#edecee", + parameter: "#edecee", + function: "#ffca85", + string: "#61ffca", + constant: "#61ffca", + type: "#82e2ff", + class: "#82e2ff", + number: "#61ffca", + comment: "#6d6d6d", + heading: "#a277ff", + invalid: "#ff6767", + regexp: "#61ffca", +}; + +export const auraTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { + backgroundColor: config.selection, + }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const auraHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function aura() { + return [auraTheme, syntaxHighlighting(auraHighlightStyle)]; +} + +export default aura; diff --git a/src/cm/themes/dracula.js b/src/cm/themes/dracula.js new file mode 100644 index 000000000..3da64920d --- /dev/null +++ b/src/cm/themes/dracula.js @@ -0,0 +1,147 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "dracula", + dark: true, + background: "#282A36", + foreground: "#F8F8F2", + selection: "#44475A", + cursor: "#F8F8F2", + dropdownBackground: "#282A36", + dropdownBorder: "#191A21", + activeLine: "#53576c22", + lineNumber: "#6272A4", + lineNumberActive: "#F8F8F2", + matchingBracket: "#44475A", + keyword: "#FF79C6", + storage: "#FF79C6", + variable: "#F8F8F2", + parameter: "#F8F8F2", + function: "#50FA7B", + string: "#F1FA8C", + constant: "#BD93F9", + type: "#8BE9FD", + class: "#8BE9FD", + number: "#BD93F9", + comment: "#6272A4", + heading: "#BD93F9", + invalid: "#FF5555", + regexp: "#F1FA8C", +}; + +export const draculaTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const draculaHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function dracula() { + return [draculaTheme, syntaxHighlighting(draculaHighlightStyle)]; +} + +export default dracula; diff --git a/src/cm/themes/githubDark.js b/src/cm/themes/githubDark.js new file mode 100644 index 000000000..b08bbfb66 --- /dev/null +++ b/src/cm/themes/githubDark.js @@ -0,0 +1,147 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "githubDark", + dark: true, + background: "#24292e", + foreground: "#d1d5da", + selection: "#3392FF44", + cursor: "#c8e1ff", + dropdownBackground: "#24292e", + dropdownBorder: "#1b1f23", + activeLine: "#4d566022", + lineNumber: "#444d56", + lineNumberActive: "#e1e4e8", + matchingBracket: "#17E5E650", + keyword: "#f97583", + storage: "#f97583", + variable: "#ffab70", + parameter: "#e1e4e8", + function: "#79b8ff", + string: "#9ecbff", + constant: "#79b8ff", + type: "#79b8ff", + class: "#b392f0", + number: "#79b8ff", + comment: "#6a737d", + heading: "#79b8ff", + invalid: "#f97583", + regexp: "#9ecbff", +}; + +export const githubDarkTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const githubDarkHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function githubDark() { + return [githubDarkTheme, syntaxHighlighting(githubDarkHighlightStyle)]; +} + +export default githubDark; diff --git a/src/cm/themes/githubLight.js b/src/cm/themes/githubLight.js new file mode 100644 index 000000000..92dcc83a5 --- /dev/null +++ b/src/cm/themes/githubLight.js @@ -0,0 +1,147 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "githubLight", + dark: false, + background: "#fff", + foreground: "#444d56", + selection: "#0366d625", + cursor: "#044289", + dropdownBackground: "#fff", + dropdownBorder: "#e1e4e8", + activeLine: "#c6c6c622", + lineNumber: "#1b1f234d", + lineNumberActive: "#24292e", + matchingBracket: "#34d05840", + keyword: "#d73a49", + storage: "#d73a49", + variable: "#e36209", + parameter: "#24292e", + function: "#005cc5", + string: "#032f62", + constant: "#005cc5", + type: "#005cc5", + class: "#6f42c1", + number: "#005cc5", + comment: "#6a737d", + heading: "#005cc5", + invalid: "#cb2431", + regexp: "#032f62", +}; + +export const githubLightTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const githubLightHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function githubLight() { + return [githubLightTheme, syntaxHighlighting(githubLightHighlightStyle)]; +} + +export default githubLight; diff --git a/src/cm/themes/index.js b/src/cm/themes/index.js new file mode 100644 index 000000000..a10145e3e --- /dev/null +++ b/src/cm/themes/index.js @@ -0,0 +1,232 @@ +import { EditorState } from "@codemirror/state"; +import { oneDark } from "@codemirror/theme-one-dark"; +import aura, { config as auraConfig } from "./aura"; +import dracula, { config as draculaConfig } from "./dracula"; +import githubDark, { config as githubDarkConfig } from "./githubDark"; +import githubLight, { config as githubLightConfig } from "./githubLight"; +import monokai, { config as monokaiConfig } from "./monokai"; +import noctisLilac, { config as noctisLilacConfig } from "./noctisLilac"; +import solarizedDark, { config as solarizedDarkConfig } from "./solarizedDark"; +import solarizedLight, { + config as solarizedLightConfig, +} from "./solarizedLight"; +import tokyoNight, { config as tokyoNightConfig } from "./tokyoNight"; +import tokyoNightDay, { config as tokyoNightDayConfig } from "./tokyoNightDay"; +import vscodeDark, { config as vscodeDarkConfig } from "./vscodeDark"; + +const oneDarkConfig = { + name: "one_dark", + dark: true, + background: "#282c34", + foreground: "#abb2bf", + keyword: "#c678dd", + string: "#98c379", + number: "#d19a66", + comment: "#5c6370", + function: "#61afef", + variable: "#e06c75", + type: "#e5c07b", + class: "#e5c07b", + constant: "#d19a66", + operator: "#56b6c2", + invalid: "#ff6b6b", +}; + +const themes = new Map(); +const warnedInvalidThemes = new Set(); + +function normalizeExtensions(value, target = []) { + if (Array.isArray(value)) { + value.forEach((item) => normalizeExtensions(item, target)); + return target; + } + + if (value !== null && value !== undefined) { + target.push(value); + } + + return target; +} + +function toExtensionGetter(getExtension) { + if (typeof getExtension === "function") { + return () => normalizeExtensions(getExtension()); + } + + return () => normalizeExtensions(getExtension); +} + +function logInvalidThemeOnce(themeId, error, reason = "") { + if (warnedInvalidThemes.has(themeId)) return; + warnedInvalidThemes.add(themeId); + const message = reason + ? `[editorThemes] Theme '${themeId}' is invalid: ${reason}` + : `[editorThemes] Theme '${themeId}' is invalid.`; + console.error(message, error); +} + +function validateThemeExtensions(themeId, extensions) { + if (!extensions.length) { + logInvalidThemeOnce(themeId, null, "no extensions were returned"); + return false; + } + + try { + // Validate against Acode's own CodeMirror instance. + EditorState.create({ doc: "", extensions }); + return true; + } catch (error) { + logInvalidThemeOnce(themeId, error); + return false; + } +} + +function resolveThemeEntryExtensions(theme, fallbackExtensions) { + const fallback = fallbackExtensions.length + ? [...fallbackExtensions] + : [oneDark]; + + if (!theme) return fallback; + + try { + const resolved = normalizeExtensions(theme.getExtension?.()); + if (!validateThemeExtensions(theme.id, resolved)) { + return fallback; + } + return resolved; + } catch (error) { + logInvalidThemeOnce(theme.id, error); + return fallback; + } +} + +export function addTheme(id, caption, isDark, getExtension, config = null) { + const key = String(id || "") + .trim() + .toLowerCase(); + if (!key || themes.has(key)) return false; + + const theme = { + id: key, + caption: caption || id, + isDark: !!isDark, + getExtension: toExtensionGetter(getExtension), + config: config || null, + }; + + if (!validateThemeExtensions(key, theme.getExtension())) { + return false; + } + + themes.set(key, theme); + return true; +} + +export function getThemes() { + return Array.from(themes.values()); +} + +export function getThemeById(id) { + if (!id) return null; + return themes.get(String(id).toLowerCase()) || null; +} + +export function getThemeConfig(id) { + if (!id) return oneDarkConfig; + const theme = themes.get(String(id).toLowerCase()); + return theme?.config || oneDarkConfig; +} + +export function getThemeExtensions(id, fallback = [oneDark]) { + const fallbackExtensions = normalizeExtensions(fallback); + const theme = + getThemeById(id) || getThemeById(String(id || "").replace(/-/g, "_")); + return resolveThemeEntryExtensions(theme, fallbackExtensions); +} + +export function removeTheme(id) { + if (!id) return; + themes.delete(String(id).toLowerCase()); +} + +addTheme("one_dark", "One Dark", true, () => [oneDark], oneDarkConfig); +addTheme(auraConfig.name, "Aura", !!auraConfig.dark, () => aura(), auraConfig); +addTheme( + noctisLilacConfig.name, + noctisLilacConfig.caption || "Noctis Lilac", + !!noctisLilacConfig.dark, + () => noctisLilac(), + noctisLilacConfig, +); +addTheme( + draculaConfig.name, + "Dracula", + !!draculaConfig.dark, + () => dracula(), + draculaConfig, +); +addTheme( + githubDarkConfig.name, + "GitHub Dark", + !!githubDarkConfig.dark, + () => githubDark(), + githubDarkConfig, +); +addTheme( + githubLightConfig.name, + "GitHub Light", + !!githubLightConfig.dark, + () => githubLight(), + githubLightConfig, +); +addTheme( + solarizedDarkConfig.name, + "Solarized Dark", + !!solarizedDarkConfig.dark, + () => solarizedDark(), + solarizedDarkConfig, +); +addTheme( + solarizedLightConfig.name, + "Solarized Light", + !!solarizedLightConfig.dark, + () => solarizedLight(), + solarizedLightConfig, +); +addTheme( + tokyoNightDayConfig.name, + "Tokyo Night Day", + !!tokyoNightDayConfig.dark, + () => tokyoNightDay(), + tokyoNightDayConfig, +); +addTheme( + tokyoNightConfig.name, + "Tokyo Night", + !!tokyoNightConfig.dark, + () => tokyoNight(), + tokyoNightConfig, +); +addTheme( + monokaiConfig.name, + "Monokai", + !!monokaiConfig.dark, + () => monokai(), + monokaiConfig, +); +addTheme( + vscodeDarkConfig.name, + "VS Code Dark", + !!vscodeDarkConfig.dark, + () => vscodeDark(), + vscodeDarkConfig, +); + +export default { + getThemes, + getThemeById, + getThemeConfig, + getThemeExtensions, + addTheme, + removeTheme, +}; diff --git a/src/cm/themes/monokai.js b/src/cm/themes/monokai.js new file mode 100644 index 000000000..e43e2969d --- /dev/null +++ b/src/cm/themes/monokai.js @@ -0,0 +1,155 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "monokai", + dark: true, + background: "#272822", + foreground: "#f8f8f2", + selection: "#4a4a76", + cursor: "#f8f8f0", + dropdownBackground: "#414339", + dropdownBorder: "#3e3d32", + activeLine: "#3e3d3257", + lineNumber: "#f8f8f270", + lineNumberActive: "#f8f8f2", + matchingBracket: "#3e3d32", + keyword: "#F92672", + storage: "#F92672", + variable: "#FD971F", + parameter: "#FD971F", + function: "#66D9EF", + string: "#E6DB74", + constant: "#AE81FF", + type: "#66D9EF", + class: "#A6E22E", + number: "#AE81FF", + comment: "#88846f", + heading: "#A6E22E", + invalid: "#F44747", + regexp: "#E6DB74", + tag: "#F92672", +}; + +export const monokaiTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { + backgroundColor: config.selection, + }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { + borderBottom: `1px solid ${config.dropdownBorder}`, + }, + ".cm-panels.cm-panels-bottom": { + borderTop: `1px solid ${config.dropdownBorder}`, + }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const monokaiHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.tagName, color: config.tag }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function monokai() { + return [monokaiTheme, syntaxHighlighting(monokaiHighlightStyle)]; +} + +export default monokai; diff --git a/src/cm/themes/noctisLilac.js b/src/cm/themes/noctisLilac.js new file mode 100644 index 000000000..c8665b661 --- /dev/null +++ b/src/cm/themes/noctisLilac.js @@ -0,0 +1,138 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "noctisLilac", + dark: false, + background: "#f2f1f8", + foreground: "#0c006b", + selection: "#d5d1f2", + cursor: "#5c49e9", + dropdownBackground: "#f2f1f8", + dropdownBorder: "#e1def3", + activeLine: "#e1def3", + lineNumber: "#0c006b70", + lineNumberActive: "#0c006b", + matchingBracket: "#d5d1f2", + keyword: "#ff5792", + storage: "#ff5792", + variable: "#0c006b", + parameter: "#0c006b", + function: "#0095a8", + string: "#00b368", + constant: "#5842ff", + type: "#b3694d", + class: "#0094f0", + number: "#5842ff", + comment: "#9995b7", + heading: "#0094f0", + invalid: "#ff5792", + regexp: "#00b368", +}; + +export const noctisLilacTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { + backgroundColor: config.selection, + }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const noctisLilacHighlightStyle = HighlightStyle.define([ + { tag: t.comment, color: config.comment }, + { tag: t.keyword, color: config.keyword, fontWeight: "bold" }, + { tag: [t.definitionKeyword, t.modifier], color: config.keyword }, + { + tag: [t.className, t.tagName, t.definition(t.typeName)], + color: config.class, + }, + { tag: [t.number, t.bool, t.null, t.special(t.brace)], color: config.number }, + { + tag: [t.definition(t.propertyName), t.function(t.variableName)], + color: config.function, + }, + { tag: t.typeName, color: config.type }, + { tag: [t.propertyName, t.variableName], color: "#fa8900" }, + { tag: t.operator, color: config.keyword }, + { tag: t.self, color: "#e64100" }, + { tag: [t.string, t.regexp], color: config.string }, + { tag: [t.paren, t.bracket], color: "#0431fa" }, + { tag: t.labelName, color: "#00bdd6" }, + { tag: t.attributeName, color: "#e64100" }, + { tag: t.angleBracket, color: config.comment }, +]); + +export function noctisLilac() { + return [noctisLilacTheme, syntaxHighlighting(noctisLilacHighlightStyle)]; +} + +export default noctisLilac; diff --git a/src/cm/themes/solarizedDark.js b/src/cm/themes/solarizedDark.js new file mode 100644 index 000000000..aab15ece3 --- /dev/null +++ b/src/cm/themes/solarizedDark.js @@ -0,0 +1,147 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "solarizedDark", + dark: true, + background: "#002B36", + foreground: "#93A1A1", + selection: "#274642", + cursor: "#D30102", + dropdownBackground: "#002B36", + dropdownBorder: "#2AA19899", + activeLine: "#005b7022", + lineNumber: "#93A1A1", + lineNumberActive: "#949494", + matchingBracket: "#073642", + keyword: "#859900", + storage: "#93A1A1", + variable: "#268BD2", + parameter: "#268BD2", + function: "#268BD2", + string: "#2AA198", + constant: "#CB4B16", + type: "#CB4B16", + class: "#CB4B16", + number: "#D33682", + comment: "#586E75", + heading: "#268BD2", + invalid: "#DC322F", + regexp: "#DC322F", +}; + +export const solarizedDarkTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const solarizedDarkHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function solarizedDark() { + return [solarizedDarkTheme, syntaxHighlighting(solarizedDarkHighlightStyle)]; +} + +export default solarizedDark; diff --git a/src/cm/themes/solarizedLight.js b/src/cm/themes/solarizedLight.js new file mode 100644 index 000000000..022899460 --- /dev/null +++ b/src/cm/themes/solarizedLight.js @@ -0,0 +1,150 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "solarizedLight", + dark: false, + background: "#FDF6E3", + foreground: "#586E75", + selection: "#EEE8D5", + cursor: "#657B83", + dropdownBackground: "#FDF6E3", + dropdownBorder: "#D3AF86", + activeLine: "#d5bd5c22", + lineNumber: "#586E75", + lineNumberActive: "#567983", + matchingBracket: "#EEE8D5", + keyword: "#859900", + storage: "#586E75", + variable: "#268BD2", + parameter: "#268BD2", + function: "#268BD2", + string: "#2AA198", + constant: "#CB4B16", + type: "#CB4B16", + class: "#CB4B16", + number: "#D33682", + comment: "#93A1A1", + heading: "#268BD2", + invalid: "#DC322F", + regexp: "#DC322F", +}; + +export const solarizedLightTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const solarizedLightHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function solarizedLight() { + return [ + solarizedLightTheme, + syntaxHighlighting(solarizedLightHighlightStyle), + ]; +} + +export default solarizedLight; diff --git a/src/cm/themes/tokyoNight.js b/src/cm/themes/tokyoNight.js new file mode 100644 index 000000000..33af93847 --- /dev/null +++ b/src/cm/themes/tokyoNight.js @@ -0,0 +1,147 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "tokyoNight", + dark: true, + background: "#1a1b26", + foreground: "#787c99", + selection: "#515c7e40", + cursor: "#c0caf5", + dropdownBackground: "#1a1b26", + dropdownBorder: "#787c99", + activeLine: "#43455c22", + lineNumber: "#363b54", + lineNumberActive: "#737aa2", + matchingBracket: "#16161e", + keyword: "#bb9af7", + storage: "#bb9af7", + variable: "#c0caf5", + parameter: "#c0caf5", + function: "#7aa2f7", + string: "#9ece6a", + constant: "#bb9af7", + type: "#0db9d7", + class: "#c0caf5", + number: "#ff9e64", + comment: "#444b6a", + heading: "#89ddff", + invalid: "#ff5370", + regexp: "#b4f9f8", +}; + +export const tokyoNightTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const tokyoNightHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function tokyoNight() { + return [tokyoNightTheme, syntaxHighlighting(tokyoNightHighlightStyle)]; +} + +export default tokyoNight; diff --git a/src/cm/themes/tokyoNightDay.js b/src/cm/themes/tokyoNightDay.js new file mode 100644 index 000000000..e9f948ffe --- /dev/null +++ b/src/cm/themes/tokyoNightDay.js @@ -0,0 +1,147 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView, lineNumbers } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "tokyoNightDay", + dark: false, + background: "#e1e2e7", + foreground: "#6a6f8e", + selection: "#8591b840", + cursor: "#3760bf", + dropdownBackground: "#e1e2e7", + dropdownBorder: "#6a6f8e", + activeLine: "#a7aaba22", + lineNumber: "#b3b6cd", + lineNumberActive: "#68709a", + matchingBracket: "#e9e9ec", + keyword: "#9854f1", + storage: "#9854f1", + variable: "#3760bf", + parameter: "#3760bf", + function: "#2e7de9", + string: "#587539", + constant: "#9854f1", + type: "#07879d", + class: "#3760bf", + number: "#b15c00", + comment: "#9da3c2", + heading: "#006a83", + invalid: "#ff3e64", + regexp: "#2e5857", +}; + +export const tokyoNightDayTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { backgroundColor: config.selection }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { borderBottom: "2px solid black" }, + ".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selection, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selection }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.foreground, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selection, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const tokyoNightDayHighlightStyle = HighlightStyle.define([ + { tag: t.keyword, color: config.keyword }, + { + tag: [t.name, t.deleted, t.character, t.macroName], + color: config.variable, + }, + { tag: [t.propertyName], color: config.function }, + { + tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], + color: config.string, + }, + { tag: [t.function(t.variableName), t.labelName], color: config.function }, + { + tag: [t.color, t.constant(t.name), t.standard(t.name)], + color: config.constant, + }, + { tag: [t.definition(t.name), t.separator], color: config.variable }, + { tag: [t.className], color: config.class }, + { + tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], + color: config.number, + }, + { tag: [t.typeName], color: config.type, fontStyle: config.type }, + { tag: [t.operator, t.operatorKeyword], color: config.keyword }, + { tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.link, textDecoration: "underline" }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable }, + { tag: t.invalid, color: config.invalid }, + { tag: t.strikethrough, textDecoration: "line-through" }, +]); + +export function tokyoNightDay() { + return [tokyoNightDayTheme, syntaxHighlighting(tokyoNightDayHighlightStyle)]; +} + +export default tokyoNightDay; diff --git a/src/cm/themes/vscodeDark.js b/src/cm/themes/vscodeDark.js new file mode 100644 index 000000000..21e634b11 --- /dev/null +++ b/src/cm/themes/vscodeDark.js @@ -0,0 +1,189 @@ +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; +import { tags as t } from "@lezer/highlight"; + +export const config = { + name: "vscodeDark", + dark: true, + background: "#1e1e1e", + foreground: "#9cdcfe", + selection: "#6199ff2f", + selectionMatch: "#72a1ff59", + cursor: "#c6c6c6", + dropdownBackground: "#1e1e1e", + dropdownBorder: "#3c3c3c", + activeLine: "#ffffff0f", + lineNumber: "#838383", + lineNumberActive: "#ffffff", + matchingBracket: "#515c6a", + keyword: "#569cd6", + variable: "#9cdcfe", + parameter: "#9cdcfe", + function: "#dcdcaa", + string: "#ce9178", + constant: "#569cd6", + type: "#4ec9b0", + class: "#4ec9b0", + number: "#b5cea8", + comment: "#6a9955", + heading: "#9cdcfe", + invalid: "#ff0000", + regexp: "#d16969", + tag: "#4ec9b0", + operator: "#d4d4d4", + angleBracket: "#808080", +}; + +export const vscodeDarkTheme = EditorView.theme( + { + "&": { + color: config.foreground, + backgroundColor: config.background, + }, + + ".cm-content": { caretColor: config.cursor }, + + ".cm-cursor, .cm-dropCursor": { borderLeftColor: config.cursor }, + "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": + { + backgroundColor: config.selection, + }, + + ".cm-panels": { + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-panels.cm-panels-top": { + borderBottom: `1px solid ${config.dropdownBorder}`, + }, + ".cm-panels.cm-panels-bottom": { + borderTop: `1px solid ${config.dropdownBorder}`, + }, + + ".cm-searchMatch": { + backgroundColor: config.dropdownBackground, + outline: `1px solid ${config.dropdownBorder}`, + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: config.selectionMatch, + }, + + ".cm-activeLine": { backgroundColor: config.activeLine }, + ".cm-selectionMatch": { backgroundColor: config.selectionMatch }, + + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: config.matchingBracket, + outline: "none", + }, + + ".cm-gutters": { + backgroundColor: config.background, + color: config.lineNumber, + border: "none", + }, + ".cm-activeLineGutter": { backgroundColor: config.background }, + + ".cm-lineNumbers .cm-gutterElement": { color: config.lineNumber }, + ".cm-lineNumbers .cm-activeLineGutter": { color: config.lineNumberActive }, + + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: config.foreground, + }, + ".cm-tooltip": { + border: `1px solid ${config.dropdownBorder}`, + backgroundColor: config.dropdownBackground, + color: config.foreground, + }, + ".cm-tooltip .cm-tooltip-arrow:before": { + borderTopColor: "transparent", + borderBottomColor: "transparent", + }, + ".cm-tooltip .cm-tooltip-arrow:after": { + borderTopColor: config.foreground, + borderBottomColor: config.foreground, + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + background: config.selectionMatch, + color: config.foreground, + }, + }, + }, + { dark: config.dark }, +); + +export const vscodeDarkHighlightStyle = HighlightStyle.define([ + { + tag: [ + t.keyword, + t.operatorKeyword, + t.modifier, + t.color, + t.constant(t.name), + t.standard(t.name), + t.standard(t.tagName), + t.special(t.brace), + t.atom, + t.bool, + t.special(t.variableName), + ], + color: config.keyword, + }, + { tag: [t.controlKeyword, t.moduleKeyword], color: "#c586c0" }, + { + tag: [ + t.name, + t.deleted, + t.character, + t.macroName, + t.propertyName, + t.variableName, + t.labelName, + t.definition(t.name), + ], + color: config.variable, + }, + { tag: t.heading, fontWeight: "bold", color: config.heading }, + { + tag: [ + t.typeName, + t.className, + t.tagName, + t.number, + t.changed, + t.annotation, + t.self, + t.namespace, + ], + color: config.type, + }, + { + tag: [t.function(t.variableName), t.function(t.propertyName)], + color: config.function, + }, + { tag: [t.number], color: config.number }, + { + tag: [t.operator, t.punctuation, t.separator, t.url, t.escape, t.regexp], + color: config.operator, + }, + { tag: [t.regexp], color: config.regexp }, + { + tag: [t.special(t.string), t.processingInstruction, t.string, t.inserted], + color: config.string, + }, + { tag: [t.angleBracket], color: config.angleBracket }, + { tag: t.strong, fontWeight: "bold" }, + { tag: t.emphasis, fontStyle: "italic" }, + { tag: t.strikethrough, textDecoration: "line-through" }, + { tag: [t.meta, t.comment], color: config.comment }, + { tag: t.link, color: config.comment, textDecoration: "underline" }, + { tag: t.invalid, color: config.invalid }, +]); + +export function vscodeDark() { + return [vscodeDarkTheme, syntaxHighlighting(vscodeDarkHighlightStyle)]; +} + +export default vscodeDark; diff --git a/src/cm/touchSelectionMenu.js b/src/cm/touchSelectionMenu.js new file mode 100644 index 000000000..2cdc216f5 --- /dev/null +++ b/src/cm/touchSelectionMenu.js @@ -0,0 +1,1174 @@ +import { EditorSelection } from "@codemirror/state"; +import constants from "lib/constants"; +import selectionMenu from "lib/selectionMenu"; +import appSettings from "lib/settings"; +import { getColorRange } from "utils/color/regex"; + +const TAP_MAX_DELAY = 500; +const TAP_MAX_DISTANCE = 20; +const LONG_PRESS_DELAY = 450; +const EDGE_SCROLL_GAP = 40; +const EDGE_SCROLL_STEP = 16; +const MENU_MARGIN = 10; +const DRAG_FINGER_OFFSET_FACTOR = 1.8; +const HANDLE_HIT_SLOP = 8; +const CURSOR_HANDLE_HIT_SLOP = 2; +const CURSOR_HANDLE_GUARD_MS = 320; +const TAP_MAX_COLUMN_DELTA = 2; +const TAP_MAX_POS_DELTA = 2; + +/** + * Classify taps into single/double/triple tap buckets. + * @param {{x:number,y:number,time:number,count:number}|null} previousTap + * @param {{x:number,y:number,time:number}} tap + * @returns {{x:number,y:number,time:number,count:number}} + */ +export function classifyTap(previousTap, tap) { + if (!previousTap) { + return { ...tap, count: 1 }; + } + + const dt = tap.time - previousTap.time; + const dx = tap.x - previousTap.x; + const dy = tap.y - previousTap.y; + const distance = Math.hypot(dx, dy); + const sameTextZone = + tap.line != null && + previousTap.line != null && + tap.line === previousTap.line && + Math.abs((tap.column ?? 0) - (previousTap.column ?? 0)) <= + TAP_MAX_COLUMN_DELTA; + const nearSamePos = + tap.pos != null && + previousTap.pos != null && + Math.abs(tap.pos - previousTap.pos) <= TAP_MAX_POS_DELTA; + + if ( + dt <= TAP_MAX_DELAY && + (distance <= TAP_MAX_DISTANCE || sameTextZone || nearSamePos) + ) { + return { + ...tap, + count: Math.min(previousTap.count + 1, 3), + }; + } + + return { ...tap, count: 1 }; +} + +/** + * Clamp menu coordinates so it stays within the container bounds. + * @param {{left:number, top:number, width:number, height:number}} menuRect + * @param {{left:number, top:number, width:number, height:number}} containerRect + * @returns {{left:number, top:number}} + */ +export function clampMenuPosition(menuRect, containerRect) { + const maxLeft = Math.max( + containerRect.left + MENU_MARGIN, + containerRect.left + containerRect.width - menuRect.width - MENU_MARGIN, + ); + const maxTop = Math.max( + containerRect.top + MENU_MARGIN, + containerRect.top + containerRect.height - menuRect.height - MENU_MARGIN, + ); + + return { + left: clamp(menuRect.left, containerRect.left + MENU_MARGIN, maxLeft), + top: clamp(menuRect.top, containerRect.top + MENU_MARGIN, maxTop), + }; +} + +/** + * Filter menu items using Ace-compatible rules. + * @param {ReturnType} items + * @param {{readOnly:boolean,hasSelection:boolean}} options + */ +export function filterSelectionMenuItems(items, options) { + const { readOnly, hasSelection } = options; + return items.filter((item) => { + if (readOnly && !item.readOnly) return false; + if (hasSelection && !["selected", "all"].includes(item.mode)) return false; + if (!hasSelection && item.mode === "selected") return false; + return true; + }); +} + +function clamp(value, min, max) { + return Math.max(min, Math.min(max, value)); +} + +function getElementRect($el) { + if (!$el?.isConnected) return null; + return $el.getBoundingClientRect(); +} + +export default function createTouchSelectionMenu(view, options = {}) { + return new TouchSelectionMenuController(view, options); +} + +class TouchSelectionMenuController { + #view; + #container; + #getActiveFile; + #tap = null; + #touchSession = null; + #dragState = null; + #longPressTimer = null; + #cursorHideTimer = null; + #scrollTimeout = null; + #autoScrollRaf = 0; + #stateSyncRaf = 0; + #isScrolling = false; + #selectionActive = false; + #menuActive = false; + #enabled = true; + #handlingMenuAction = false; + #pendingPointerTriggered = false; + #pendingSelectionChanged = false; + #cursorHandleGuardUntil = 0; + #pointer = { x: 0, y: 0 }; + #mouseSelecting = false; + + constructor(view, options = {}) { + this.#view = view; + this.#container = + options.container || view.dom.closest(".editor-container") || view.dom; + this.#getActiveFile = options.getActiveFile || (() => null); + + this.config = { + teardropSize: appSettings.value.teardropSize, + teardropTimeout: appSettings.value.teardropTimeout, + touchMoveThreshold: appSettings.value.touchMoveThreshold, + }; + + this.$start = this.#createHandle("start"); + this.$end = this.#createHandle("end"); + this.$cursor = this.#createHandle("single"); + this.$menu = document.createElement("menu"); + this.$menu.className = "cursor-menu"; + this.$start.addEventListener("touchstart", this.#onStartHandleTouchStart, { + passive: false, + }); + this.$end.addEventListener("touchstart", this.#onEndHandleTouchStart, { + passive: false, + }); + this.$cursor.addEventListener( + "touchstart", + this.#onCursorHandleTouchStart, + { + passive: false, + }, + ); + + this.#bindEvents(); + this.#syncHandleSize(); + } + + #createHandle(type) { + const $handle = document.createElement("span"); + $handle.className = `cursor ${type}`; + $handle.dataset.size = String(this.config.teardropSize); + return $handle; + } + + #bindEvents() { + const root = this.#view.dom; + root.addEventListener("touchstart", this.#onTouchStart, { + passive: false, + capture: true, + }); + root.addEventListener("mousedown", this.#onMouseDown, true); + root.addEventListener("contextmenu", this.#onContextMenu, true); + document.addEventListener("mouseup", this.#onMouseUp, true); + document.addEventListener("mousedown", this.#onGlobalPointerDown, true); + document.addEventListener("touchstart", this.#onGlobalPointerDown, true); + + appSettings.on("update:teardropSize", this.#onTeardropSizeUpdate); + appSettings.on("update:teardropTimeout", this.#onTeardropTimeoutUpdate); + appSettings.on( + "update:touchMoveThreshold", + this.#onTouchMoveThresholdUpdate, + ); + } + + destroy() { + const root = this.#view.dom; + root.removeEventListener("touchstart", this.#onTouchStart, true); + root.removeEventListener("mousedown", this.#onMouseDown, true); + root.removeEventListener("contextmenu", this.#onContextMenu, true); + document.removeEventListener("mouseup", this.#onMouseUp, true); + document.removeEventListener("mousedown", this.#onGlobalPointerDown, true); + document.removeEventListener("touchstart", this.#onGlobalPointerDown, true); + this.#removeTouchListeners(); + this.#stopAutoScroll(); + this.#clearScrollTimeout(); + cancelAnimationFrame(this.#stateSyncRaf); + this.#stateSyncRaf = 0; + this.#pendingPointerTriggered = false; + this.#pendingSelectionChanged = false; + this.#clearLongPress(); + this.#clearCursorHideTimer(); + this.#clearSelectionUi(); + this.#hideMenu(true); + this.$start.removeEventListener( + "touchstart", + this.#onStartHandleTouchStart, + ); + this.$end.removeEventListener("touchstart", this.#onEndHandleTouchStart); + this.$cursor.removeEventListener( + "touchstart", + this.#onCursorHandleTouchStart, + ); + appSettings.off("update:teardropSize", this.#onTeardropSizeUpdate); + appSettings.off("update:teardropTimeout", this.#onTeardropTimeoutUpdate); + appSettings.off( + "update:touchMoveThreshold", + this.#onTouchMoveThresholdUpdate, + ); + } + + setEnabled(enabled) { + this.#enabled = !!enabled; + if (!this.#enabled) { + this.#touchSession = null; + this.#dragState = null; + this.#removeTouchListeners(); + this.#stopAutoScroll(); + this.#clearScrollTimeout(); + cancelAnimationFrame(this.#stateSyncRaf); + this.#stateSyncRaf = 0; + this.#pendingPointerTriggered = false; + this.#pendingSelectionChanged = false; + this.#clearLongPress(); + this.#clearCursorHideTimer(); + this.#clearSelectionUi(); + this.#hideMenu(true); + } + } + + setSelection(value) { + this.#selectionActive = !!value; + if (!this.#enabled) return; + if (value && !this.#hasSelection()) { + this.#selectWordAtCursor(); + } + this.onStateChanged({ selectionChanged: true, pointerTriggered: !!value }); + } + + setMenu(value) { + this.#menuActive = !!value; + if (!this.#enabled) return; + if (!value) { + this.#hideMenu(); + return; + } + const triggerType = this.#hasSelection() ? "end" : "cursor"; + if (triggerType === "end") { + this.#selectionActive = true; + this.#showSelectionHandles(); + } else { + this.#showCursorHandle(); + } + this.#showMenuDeferred(triggerType); + } + + onScroll() { + if (!this.#enabled) return; + if (this.#dragState) return; + this.#clearScrollTimeout(); + this.#isScrolling = true; + cancelAnimationFrame(this.#stateSyncRaf); + this.#stateSyncRaf = 0; + this.#clearSelectionUi(); + this.#hideMenu(false, false); + this.#scrollTimeout = setTimeout(() => { + this.#onScrollEnd(); + }, 100); + } + + #onScrollEnd() { + this.#scrollTimeout = null; + if (!this.#enabled) return; + if (!this.#isScrolling) return; + this.#isScrolling = false; + if (this.#dragState) return; + + if (this.#selectionActive && this.#hasSelection()) { + this.#showSelectionHandles(); + } else { + this.#showCursorHandle(); + } + + if (this.#menuActive) { + const triggerType = + this.#selectionActive && this.#hasSelection() ? "end" : "cursor"; + this.#showMenuDeferred(triggerType); + } + + if (this.#pendingPointerTriggered || this.#pendingSelectionChanged) { + this.onStateChanged(); + } + } + + onStateChanged(meta = {}) { + if (!this.#enabled) return; + if (this.#handlingMenuAction) return; + if (meta.pointerTriggered) this.#pendingPointerTriggered = true; + if (meta.selectionChanged) this.#pendingSelectionChanged = true; + if (this.#isScrolling) return; + cancelAnimationFrame(this.#stateSyncRaf); + this.#stateSyncRaf = requestAnimationFrame(() => { + this.#stateSyncRaf = 0; + this.#applyStateChange(); + }); + } + + onSessionChanged() { + if (!this.#enabled) return; + this.#clearSelectionUi(); + this.#hideMenu(true); + this.#selectionActive = this.#hasSelection(); + this.onStateChanged({ + selectionChanged: true, + pointerTriggered: this.#selectionActive, + }); + } + + #onTeardropSizeUpdate = (value) => { + this.config.teardropSize = value; + this.#syncHandleSize(); + if (!this.#enabled) return; + this.onStateChanged({ selectionChanged: true }); + }; + + #onTeardropTimeoutUpdate = (value) => { + this.config.teardropTimeout = value; + }; + + #onTouchMoveThresholdUpdate = (value) => { + this.config.touchMoveThreshold = value; + }; + + #onGlobalPointerDown = (event) => { + if (!this.#menuActive || !this.$menu.isConnected) return; + const target = event.target; + if ( + this.$menu.contains(target) || + this.$start.contains(target) || + this.$end.contains(target) || + this.$cursor.contains(target) + ) { + return; + } + if (this.#isIgnoredPointerTarget(target)) { + return; + } + if ( + event.type === "touchstart" && + target instanceof Node && + this.#view.dom.contains(target) + ) { + this.#hideMenu(false, false); + return; + } + this.#hideMenu(); + }; + + #onContextMenu = (event) => { + if (!this.#enabled) return; + if (this.#isIgnoredPointerTarget(event.target)) return; + event.preventDefault(); + event.stopPropagation(); + + const { clientX, clientY } = event; + const moved = this.#moveCursorToCoords(clientX, clientY); + if (moved == null) return; + + if (!this.#hasSelection()) { + this.#selectWordAtCursor(); + } + + this.#selectionActive = this.#hasSelection(); + if (this.#selectionActive) { + this.#showSelectionHandles(); + this.#showMenuDeferred("end"); + return; + } + this.#showCursorHandle(); + this.#showMenuDeferred("cursor"); + }; + + #onMouseDown = (event) => { + if (!this.#enabled) return; + if (event.button !== 0) return; + if (this.#isIgnoredPointerTarget(event.target)) return; + this.#mouseSelecting = true; + }; + + #onMouseUp = (event) => { + if (!this.#enabled) return; + if (event.button !== 0) return; + if (!this.#mouseSelecting) return; + this.#mouseSelecting = false; + requestAnimationFrame(() => { + if (!this.#enabled || !this.#hasSelection()) return; + this.#selectionActive = true; + this.onStateChanged({ + pointerTriggered: true, + selectionChanged: true, + }); + }); + }; + + #onTouchStart = (event) => { + if (!this.#enabled || event.touches.length !== 1) return; + if (this.#isIgnoredPointerTarget(event.target)) { + this.#touchSession = null; + this.#clearLongPress(); + return; + } + const touch = event.touches[0]; + const { clientX, clientY } = touch; + const now = performance.now(); + this.#pointer.x = clientX; + this.#pointer.y = clientY; + + if (this.#isInHandle(this.$start, clientX, clientY)) { + event.preventDefault(); + this.#startDrag("start", clientX, clientY); + return; + } + + if (this.#isInHandle(this.$end, clientX, clientY)) { + event.preventDefault(); + this.#startDrag("end", clientX, clientY); + return; + } + + if ( + now >= this.#cursorHandleGuardUntil && + this.#isInHandle(this.$cursor, clientX, clientY, CURSOR_HANDLE_HIT_SLOP) + ) { + event.preventDefault(); + this.#startDrag("cursor", clientX, clientY); + return; + } + + if (this.#isEdgeGestureStart(clientX)) { + event.stopPropagation(); + event.stopImmediatePropagation?.(); + return; + } + + this.#touchSession = { + startX: clientX, + startY: clientY, + moved: false, + longPressFired: false, + }; + + this.#addTouchListeners(); + this.#clearLongPress(); + this.#longPressTimer = setTimeout(() => { + if (!this.#touchSession || this.#touchSession.moved) return; + this.#touchSession.longPressFired = true; + this.#moveCursorToCoords(clientX, clientY); + this.#selectWordAtCursor(); + this.#selectionActive = true; + this.#showSelectionHandles(); + this.#showMenuDeferred("end"); + this.#vibrate(); + }, LONG_PRESS_DELAY); + }; + + #onStartHandleTouchStart = (event) => { + if (!this.#enabled || event.touches.length !== 1) return; + const touch = event.touches[0]; + event.preventDefault(); + event.stopPropagation(); + this.#startDrag("start", touch.clientX, touch.clientY); + }; + + #onEndHandleTouchStart = (event) => { + if (!this.#enabled || event.touches.length !== 1) return; + const touch = event.touches[0]; + event.preventDefault(); + event.stopPropagation(); + this.#startDrag("end", touch.clientX, touch.clientY); + }; + + #onCursorHandleTouchStart = (event) => { + if (!this.#enabled || event.touches.length !== 1) return; + const touch = event.touches[0]; + event.preventDefault(); + event.stopPropagation(); + this.#startDrag("cursor", touch.clientX, touch.clientY); + }; + + #onTouchMove = (event) => { + if (event.touches.length !== 1) return; + const touch = event.touches[0]; + const { clientX, clientY } = touch; + this.#pointer.x = clientX; + this.#pointer.y = clientY; + + if (this.#dragState) { + event.preventDefault(); + this.#dragTo(clientX, clientY); + return; + } + + if (!this.#touchSession) return; + const dx = Math.abs(clientX - this.#touchSession.startX); + const dy = Math.abs(clientY - this.#touchSession.startY); + if ( + dx >= this.config.touchMoveThreshold || + dy >= this.config.touchMoveThreshold + ) { + this.#clearLongPress(); + } + if (dx >= TAP_MAX_DISTANCE || dy >= TAP_MAX_DISTANCE) { + this.#touchSession.moved = true; + } + }; + + #onTouchEnd = (event) => { + if (this.#dragState) { + event.preventDefault(); + this.#finishDrag(); + return; + } + + const session = this.#touchSession; + this.#touchSession = null; + this.#removeTouchListeners(); + this.#clearLongPress(); + if (!session) return; + if (session.longPressFired || session.moved) return; + + const changedTouch = event.changedTouches?.[0]; + if (!changedTouch) return; + const { clientX, clientY } = changedTouch; + const tapMeta = this.#getTapMeta(clientX, clientY); + const previousTap = this.#tap; + + let tap = classifyTap(previousTap, { + x: clientX, + y: clientY, + time: performance.now(), + pos: tapMeta.pos, + line: tapMeta.line, + column: tapMeta.column, + }); + if ( + tap.count > 1 && + previousTap?.line != null && + tapMeta.line != null && + (tapMeta.line !== previousTap.line || + Math.abs(tapMeta.column - previousTap.column) > TAP_MAX_COLUMN_DELTA) + ) { + tap = { ...tap, count: 1 }; + } + this.#tap = tap; + + const tapPos = tapMeta.pos ?? this.#coordsToPos(clientX, clientY); + if (tapPos == null) return; + + if (tap.count >= 3) { + event.preventDefault(); + this.#selectLineAtPos(tapPos); + this.#selectionActive = true; + this.#showSelectionHandles(); + this.#showMenuDeferred("end"); + this.#vibrate(); + return; + } + + if (tap.count === 2) { + event.preventDefault(); + this.#selectWordAtPos(tapPos); + this.#selectionActive = true; + this.#showSelectionHandles(); + this.#showMenuDeferred("end"); + this.#vibrate(); + return; + } + + this.#moveCursorToCoords(clientX, clientY); + this.#selectionActive = false; + this.#hideMenu(); + this.#removeSelectionHandles(); + this.#showCursorHandle(); + }; + + #addTouchListeners() { + document.addEventListener("touchmove", this.#onTouchMove, { + passive: false, + }); + document.addEventListener("touchend", this.#onTouchEnd, { + passive: false, + }); + } + + #removeTouchListeners() { + document.removeEventListener("touchmove", this.#onTouchMove); + document.removeEventListener("touchend", this.#onTouchEnd); + } + + #clearLongPress() { + clearTimeout(this.#longPressTimer); + this.#longPressTimer = null; + } + + #getTapMeta(x, y) { + const pos = this.#coordsToPos(x, y); + if (pos == null) { + return { pos: null, line: null, column: null }; + } + const lineInfo = this.#view.state.doc.lineAt(pos); + return { + pos, + line: lineInfo.number, + column: pos - lineInfo.from, + }; + } + + #vibrate() { + if (!appSettings.value.vibrateOnTap) return; + navigator.vibrate?.(constants.VIBRATION_TIME); + } + + #syncHandleSize() { + const size = this.config.teardropSize; + this.$start.dataset.size = size; + this.$end.dataset.size = size; + this.$cursor.dataset.size = size; + } + + #isEdgeGestureStart(x) { + const edge = constants.SIDEBAR_SLIDE_START_THRESHOLD_PX; + const width = window.innerWidth || 0; + return x <= edge || x >= width - edge; + } + + #isInHandle($el, x, y, hitSlop = HANDLE_HIT_SLOP) { + const rect = getElementRect($el); + if (!rect) return false; + return ( + x >= rect.left - hitSlop && + x <= rect.right + hitSlop && + y >= rect.top - hitSlop && + y <= rect.bottom + hitSlop + ); + } + + #safeCoordsAtPos(view, pos) { + try { + return view.coordsAtPos(pos); + } catch { + return null; + } + } + + #applyStateChange() { + const pointerTriggered = this.#pendingPointerTriggered; + const selectionChanged = this.#pendingSelectionChanged; + this.#pendingPointerTriggered = false; + this.#pendingSelectionChanged = false; + + if (this.#hasSelection()) { + if (pointerTriggered || selectionChanged) { + this.#selectionActive = true; + } + if (this.#selectionActive) { + this.#showSelectionHandles(); + this.$cursor.remove(); + if (pointerTriggered && !this.#dragState && !this.#mouseSelecting) { + this.#showMenuDeferred("end"); + } + } + } else { + this.#removeSelectionHandles(); + this.#selectionActive = false; + this.#showCursorHandle(); + } + + if (this.#menuActive && !this.#dragState && !this.#hasSelection()) { + this.#hideMenu(); + } + } + + #showSelectionHandles() { + if (!this.config.teardropSize || !this.#hasSelection()) { + this.#removeSelectionHandles(); + return; + } + + this.#clearCursorHideTimer(); + this.$cursor.remove(); + this.#view.requestMeasure({ + read: (view) => { + const range = view.state.selection.main; + const startCoords = this.#safeCoordsAtPos(view, range.from); + const endCoords = this.#safeCoordsAtPos(view, range.to); + if (!startCoords || !endCoords) return null; + const containerRect = this.#container.getBoundingClientRect(); + return { + startLeft: + startCoords.left - containerRect.left - this.config.teardropSize, + startTop: startCoords.bottom - containerRect.top, + endLeft: endCoords.left - containerRect.left, + endTop: endCoords.bottom - containerRect.top, + }; + }, + write: (data) => { + if (!data || !this.#selectionActive || !this.#hasSelection()) { + this.#removeSelectionHandles(); + return; + } + + this.$start.style.left = `${data.startLeft}px`; + this.$start.style.top = `${data.startTop}px`; + this.$end.style.left = `${data.endLeft}px`; + this.$end.style.top = `${data.endTop}px`; + + if (!this.$start.isConnected) this.#container.append(this.$start); + if (!this.$end.isConnected) this.#container.append(this.$end); + }, + }); + } + + #removeSelectionHandles() { + this.$start.remove(); + this.$end.remove(); + } + + #showCursorHandle() { + if ( + !this.config.teardropSize || + !this.#view.hasFocus || + this.#selectionActive + ) { + this.$cursor.remove(); + return; + } + + this.#view.requestMeasure({ + read: (view) => { + const head = view.state.selection.main.head; + const caret = this.#safeCoordsAtPos(view, head); + if (!caret) return null; + const containerRect = this.#container.getBoundingClientRect(); + return { + left: caret.left - containerRect.left, + top: caret.bottom - containerRect.top, + }; + }, + write: (data) => { + if (!data || this.#selectionActive) { + this.$cursor.remove(); + return; + } + this.$cursor.style.left = `${data.left}px`; + this.$cursor.style.top = `${data.top}px`; + if (!this.$cursor.isConnected) this.#container.append(this.$cursor); + this.#cursorHandleGuardUntil = + performance.now() + CURSOR_HANDLE_GUARD_MS; + this.#clearCursorHideTimer(); + this.#cursorHideTimer = setTimeout(() => { + this.$cursor.remove(); + }, this.config.teardropTimeout); + }, + }); + } + + #clearCursorHideTimer() { + clearTimeout(this.#cursorHideTimer); + this.#cursorHideTimer = null; + } + + #clearScrollTimeout() { + clearTimeout(this.#scrollTimeout); + this.#scrollTimeout = null; + this.#isScrolling = false; + } + + #showMenu($trigger) { + const hasSelection = this.#hasSelection(); + const items = filterSelectionMenuItems(selectionMenu(), { + readOnly: this.#isReadOnly(), + hasSelection, + }); + + this.$menu.innerHTML = ""; + if (!items.length) { + this.#hideMenu(true); + return; + } + + items.forEach(({ onclick, text }) => { + const $item = document.createElement("div"); + if (typeof text === "string") { + $item.textContent = text; + } else if (text instanceof Node) { + $item.append(text.cloneNode(true)); + } + let handled = false; + const runAction = (event) => { + if (handled) return; + handled = true; + event.preventDefault(); + event.stopPropagation(); + this.#handlingMenuAction = true; + try { + onclick?.(); + } finally { + this.#handlingMenuAction = false; + this.#hideMenu(); + this.#view.focus(); + } + }; + $item.addEventListener("pointerdown", runAction); + $item.addEventListener("click", runAction); + this.$menu.append($item); + }); + + if (!this.$menu.isConnected) { + this.#container.append(this.$menu); + } + + const triggerRect = getElementRect($trigger); + if (!triggerRect) { + this.#hideMenu(true); + return; + } + + const containerRect = this.#container.getBoundingClientRect(); + const initialLeft = triggerRect.left; + const initialTop = triggerRect.bottom; + this.$menu.style.left = `${initialLeft - containerRect.left}px`; + this.$menu.style.top = `${initialTop - containerRect.top}px`; + + const menuRect = this.$menu.getBoundingClientRect(); + const clamped = clampMenuPosition( + { + left: menuRect.left, + top: menuRect.top, + width: menuRect.width, + height: menuRect.height, + }, + { + left: containerRect.left, + top: containerRect.top, + width: containerRect.width, + height: containerRect.height, + }, + ); + + this.$menu.style.left = `${clamped.left - containerRect.left}px`; + this.$menu.style.top = `${clamped.top - containerRect.top}px`; + this.#menuActive = true; + } + + #showMenuDeferred(triggerType = "auto") { + requestAnimationFrame(() => { + if (!this.#enabled) return; + let $trigger = null; + const normalized = + triggerType === "auto" + ? this.#hasSelection() + ? "end" + : "cursor" + : triggerType; + + if (normalized === "cursor") { + $trigger = this.$cursor; + if (!$trigger.isConnected) { + this.#showCursorHandle(); + requestAnimationFrame(() => { + if (!this.#enabled || !this.$cursor.isConnected) return; + this.#showMenu(this.$cursor); + }); + return; + } + this.#showMenu($trigger); + return; + } + + $trigger = normalized === "start" ? this.$start : this.$end; + if (!$trigger.isConnected) { + this.#showSelectionHandles(); + requestAnimationFrame(() => { + if (!this.#enabled || !this.#hasSelection()) return; + const $retryTrigger = + normalized === "start" + ? this.$start + : this.$end.isConnected + ? this.$end + : this.$start; + if (!$retryTrigger?.isConnected) return; + this.#showMenu($retryTrigger); + }); + return; + } + this.#showMenu($trigger); + }); + } + + #hideMenu(force = false, clearActive = true) { + if (!force && !this.#menuActive && !this.$menu.isConnected) return; + if (this.$menu.isConnected) { + this.$menu.remove(); + } + if (clearActive) { + this.#menuActive = false; + } + } + + #moveCursorToCoords(x, y) { + const pos = this.#coordsToPos(x, y); + if (pos == null) return null; + this.#view.dispatch({ + selection: EditorSelection.cursor(pos), + scrollIntoView: true, + userEvent: "select.pointer", + }); + return pos; + } + + #coordsToPos(x, y) { + let pos; + try { + pos = this.#view.posAtCoords({ x, y }); + } catch { + return null; + } + if (pos != null) return pos; + + const rect = this.#view.scrollDOM.getBoundingClientRect(); + const cx = clamp(x, rect.left + 1, rect.right - 1); + const cy = clamp(y, rect.top + 1, rect.bottom - 1); + try { + return this.#view.posAtCoords({ x: cx, y: cy }); + } catch { + return null; + } + } + + #selectWordAtCursor() { + const state = this.#view.state; + const head = state.selection.main.head; + this.#selectWordAtPos(head); + } + + #selectWordAtPos(pos) { + const state = this.#view.state; + const colorRange = getColorRange(); + if (colorRange) { + this.#view.dispatch({ + selection: EditorSelection.range(colorRange.from, colorRange.to), + scrollIntoView: true, + userEvent: "select.pointer", + }); + return; + } + + const word = state.wordAt(pos); + if (word) { + this.#view.dispatch({ + selection: EditorSelection.range(word.from, word.to), + scrollIntoView: true, + userEvent: "select.pointer", + }); + return; + } + + const line = state.doc.lineAt(pos); + this.#view.dispatch({ + selection: EditorSelection.range(line.from, line.to), + scrollIntoView: true, + userEvent: "select.pointer", + }); + } + + #selectLineAtCursor() { + const head = this.#view.state.selection.main.head; + this.#selectLineAtPos(head); + } + + #selectLineAtPos(pos) { + const line = this.#view.state.doc.lineAt(pos); + this.#view.dispatch({ + selection: EditorSelection.range(line.from, line.to), + scrollIntoView: true, + userEvent: "select.pointer", + }); + } + + #startDrag(type, x, y) { + this.#clearCursorHideTimer(); + this.#hideMenu(); + const range = this.#view.state.selection.main; + this.#dragState = { + type, + startX: x, + startY: y, + moved: false, + direction: 0, + fixedPos: + type === "start" ? range.to : type === "end" ? range.from : null, + }; + this.#pointer.x = x; + this.#pointer.y = y; + this.#addTouchListeners(); + } + + #dragTo(x, y) { + const state = this.#view.state; + const range = state.selection.main; + const lineHeight = this.#view.defaultLineHeight || 20; + const offsetY = y - lineHeight * DRAG_FINGER_OFFSET_FACTOR; + let effectiveX = x; + if (this.#dragState.type === "start") { + effectiveX += this.config.teardropSize; + } + const pos = this.#coordsToPos(effectiveX, offsetY); + if (pos == null) return; + const dragDistance = Math.hypot( + x - this.#dragState.startX, + y - this.#dragState.startY, + ); + if ( + !this.#dragState.moved && + dragDistance < this.config.touchMoveThreshold + ) { + return; + } + if (!this.#dragState.moved) { + this.#dragState.moved = true; + } + + if (this.#dragState.type === "cursor") { + this.#view.dispatch({ + selection: EditorSelection.cursor(pos), + scrollIntoView: true, + userEvent: "select.pointer", + }); + this.#showCursorHandle(); + return; + } + + let from = range.from; + let to = range.to; + if (this.#dragState.type === "start") { + to = this.#dragState.fixedPos ?? to; + const maxFrom = Math.max(0, to - 1); + from = clamp(pos, 0, maxFrom); + } else { + from = this.#dragState.fixedPos ?? from; + const minTo = Math.min(state.doc.length, from + 1); + to = clamp(pos, minTo, state.doc.length); + } + + this.#view.dispatch({ + selection: EditorSelection.range(from, to), + scrollIntoView: true, + userEvent: "select.pointer", + }); + this.#selectionActive = true; + this.#showSelectionHandles(); + this.#startAutoScrollIfNeeded(x, y); + } + + #finishDrag() { + this.#removeTouchListeners(); + this.#stopAutoScroll(); + const dragType = this.#dragState?.type; + const moved = !!this.#dragState?.moved; + this.#dragState = null; + if (dragType === "cursor") { + this.#showCursorHandle(); + this.#showMenuDeferred("cursor"); + } else { + this.#showSelectionHandles(); + if (moved || this.#hasSelection()) { + this.#showMenuDeferred(dragType === "start" ? "start" : "end"); + } + } + this.#view.focus(); + } + + #startAutoScrollIfNeeded(x, y) { + const rect = this.#view.scrollDOM.getBoundingClientRect(); + let direction = 0; + if (y < rect.top + EDGE_SCROLL_GAP) direction = -1; + if (y > rect.bottom - EDGE_SCROLL_GAP) direction = 1; + + if (!direction) { + this.#stopAutoScroll(); + return; + } + + this.#dragState.direction = direction; + if (this.#autoScrollRaf) return; + + const tick = () => { + if (!this.#dragState?.direction) { + this.#autoScrollRaf = 0; + return; + } + + this.#view.scrollDOM.scrollTop += + this.#dragState.direction * EDGE_SCROLL_STEP; + this.#dragTo(this.#pointer.x, this.#pointer.y); + this.#autoScrollRaf = requestAnimationFrame(tick); + }; + + this.#autoScrollRaf = requestAnimationFrame(tick); + } + + #stopAutoScroll() { + cancelAnimationFrame(this.#autoScrollRaf); + this.#autoScrollRaf = 0; + if (this.#dragState) { + this.#dragState.direction = 0; + } + } + + #isReadOnly() { + const activeFile = this.#getActiveFile(); + if (activeFile?.type === "editor") { + return !activeFile.editable || !!activeFile.loading; + } + return !!this.#view.state?.readOnly; + } + + #isIgnoredPointerTarget(target) { + let element = null; + if (target instanceof Element) { + element = target; + } else if (target instanceof Node) { + element = target.parentElement; + } + if (!element) return false; + if (element.closest(".cm-tooltip, .cm-panel")) return true; + if ( + element.closest( + 'input, textarea, select, button, a, [contenteditable], [role="button"]', + ) + ) { + return true; + } + return false; + } + + #hasSelection() { + const selection = this.#view.state.selection.main; + return selection.from !== selection.to; + } + + #clearSelectionUi() { + this.$cursor.remove(); + this.#removeSelectionHandles(); + } +} diff --git a/src/components/lspInfoDialog/index.js b/src/components/lspInfoDialog/index.js new file mode 100644 index 000000000..c2fa2e4e1 --- /dev/null +++ b/src/components/lspInfoDialog/index.js @@ -0,0 +1,706 @@ +import "./styles.scss"; +import lspClientManager from "cm/lsp/clientManager"; +import { getServerStats } from "cm/lsp/serverLauncher"; +import serverRegistry from "cm/lsp/serverRegistry"; +import toast from "components/toast"; +import actionStack from "lib/actionStack"; +import restoreTheme from "lib/restoreTheme"; + +let dialogInstance = null; + +const lspLogs = new Map(); +const MAX_LOGS = 200; +const logListeners = new Set(); +const IGNORED_LOG_PATTERNS = [ + /\$\/progress\b/i, + /\bProgress:/i, + /\bwindow\/workDoneProgress\/create\b/i, + /\bAuto-responded to window\/workDoneProgress\/create\b/i, +]; + +function shouldIgnoreLog(message) { + if (typeof message !== "string") return false; + return IGNORED_LOG_PATTERNS.some((pattern) => pattern.test(message)); +} + +function addLspLog(serverId, level, message, details = null) { + if (shouldIgnoreLog(message)) { + return; + } + + if (!lspLogs.has(serverId)) { + lspLogs.set(serverId, []); + } + const logs = lspLogs.get(serverId); + const entry = { + timestamp: new Date(), + level, + message, + details, + }; + logs.push(entry); + if (logs.length > MAX_LOGS) { + logs.shift(); + } + logListeners.forEach((fn) => fn(serverId, entry)); +} + +function getLspLogs(serverId) { + return lspLogs.get(serverId) || []; +} + +function clearLspLogs(serverId) { + lspLogs.delete(serverId); +} + +const originalConsoleInfo = console.info; +const originalConsoleWarn = console.warn; +const originalConsoleError = console.error; + +function stripAnsi(str) { + if (typeof str !== "string") return str; + return str.replace(/\x1b\[[0-9;]*m/g, ""); +} + +function extractServerId(message) { + const cleaned = stripAnsi(message); + // Match [LSP:serverId] format + const lspMatch = cleaned?.match?.(/\[LSP:([^\]]+)\]/); + if (lspMatch) return lspMatch[1]; + + // Match [LSP-STDERR:program] format from axs proxy + const stderrMatch = cleaned?.match?.(/\[LSP-STDERR:([^\]]+)\]/); + if (stderrMatch) { + const program = stderrMatch[1]; + return program; + } + + return null; +} + +function extractLogMessage(message) { + const cleaned = stripAnsi(message); + // Strip [LSP:...] and [LSP-STDERR:...] prefixes + // Strip ISO timestamps like 2026-02-05T08:26:24.745443Z + // Strip log levels like INFO, WARN, ERROR and the source like axs::lsp: + return ( + cleaned + ?.replace?.(/\[LSP:[^\]]+\]\s*/, "") + ?.replace?.(/\[LSP-STDERR:[^\]]+\]\s*/, "") + ?.replace?.(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\s*/g, "") + ?.replace?.(/\s*(INFO|WARN|ERROR|DEBUG|TRACE)\s+/gi, "") + ?.replace?.(/[a-z_]+::[a-z_]+:\s*/gi, "") + ?.trim() || cleaned + ); +} + +console.info = function (...args) { + originalConsoleInfo.apply(console, args); + const msg = args[0]; + if ( + typeof msg === "string" && + (msg.includes("[LSP:") || msg.includes("[LSP-STDERR:")) + ) { + const serverId = extractServerId(msg); + if (serverId) { + addLspLog(serverId, "info", extractLogMessage(msg)); + } + } +}; + +console.warn = function (...args) { + originalConsoleWarn.apply(console, args); + const msg = args[0]; + if ( + typeof msg === "string" && + (msg.includes("[LSP:") || msg.includes("[LSP-STDERR:")) + ) { + const serverId = extractServerId(msg); + if (serverId) { + // stderr from axs is logged as warn, mark it appropriately + const isStderr = msg.includes("[LSP-STDERR:"); + addLspLog(serverId, isStderr ? "stderr" : "warn", extractLogMessage(msg)); + } + } +}; + +console.error = function (...args) { + originalConsoleError.apply(console, args); + const msg = args[0]; + if ( + typeof msg === "string" && + (msg.includes("[LSP:") || msg.includes("[LSP-STDERR:")) + ) { + const serverId = extractServerId(msg); + if (serverId) { + addLspLog(serverId, "error", extractLogMessage(msg)); + } + } +}; + +function getActiveClients() { + try { + return lspClientManager.getActiveClients(); + } catch { + return []; + } +} + +function getCurrentFileLanguage() { + try { + const file = window.editorManager?.activeFile; + if (!file || file.type !== "editor") return null; + return file.currentMode?.toLowerCase() || null; + } catch { + return null; + } +} + +function getServersForCurrentFile() { + const language = getCurrentFileLanguage(); + if (!language) return []; + + try { + return serverRegistry.getServersForLanguage(language); + } catch { + return []; + } +} + +function getServerStatus(serverId) { + const activeClients = getActiveClients(); + const client = activeClients.find((c) => c.server?.id === serverId); + if (!client) return "stopped"; + try { + return client.client?.connected !== false ? "active" : "connecting"; + } catch { + return "stopped"; + } +} + +function getClientState(serverId) { + const activeClients = getActiveClients(); + return activeClients.find((c) => c.server?.id === serverId) || null; +} + +function getStatusColor(status) { + switch (status) { + case "active": + return "var(--lsp-status-active, #22c55e)"; + case "connecting": + return "var(--lsp-status-connecting, #f59e0b)"; + default: + return "var(--lsp-status-stopped, #6b7280)"; + } +} + +function copyLogsToClipboard(serverId, serverLabel) { + const logs = getLspLogs(serverId); + if (logs.length === 0) { + toast("No logs to copy"); + return; + } + + const text = logs + .map((log) => { + const time = log.timestamp.toLocaleTimeString("en-US", { + hour12: false, + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }); + return `[${time}] [${log.level.toUpperCase()}] ${log.message}`; + }) + .join("\n"); + + const header = `=== ${serverLabel} LSP Logs ===\n`; + + if (navigator.clipboard?.writeText) { + navigator.clipboard + .writeText(header + text) + .then(() => { + toast("Logs copied"); + }) + .catch(() => { + toast("Failed to copy"); + }); + } else if (cordova?.plugins?.clipboard) { + cordova.plugins.clipboard.copy(header + text); + toast("Logs copied"); + } else { + toast("Clipboard not available"); + } +} + +async function restartServer(serverId) { + addLspLog(serverId, "info", "Restart requested by user"); + toast("Restarting server..."); + + try { + const clientState = getClientState(serverId); + if (clientState) { + await clientState.dispose(); + } + + const { stopManagedServer } = await import("cm/lsp/serverLauncher"); + stopManagedServer(serverId); + + window.editorManager?.restartLsp?.(); + + addLspLog(serverId, "info", "Server restarted successfully"); + toast("Server restarted"); + } catch (err) { + addLspLog(serverId, "error", `Restart failed: ${err.message}`); + toast("Restart failed"); + } +} + +async function stopServer(serverId) { + addLspLog(serverId, "info", "Stop requested by user"); + toast("Stopping..."); + + try { + const clientState = getClientState(serverId); + if (clientState) { + await clientState.dispose(); + } + + const { stopManagedServer } = await import("cm/lsp/serverLauncher"); + stopManagedServer(serverId); + + addLspLog(serverId, "info", "Server stopped"); + toast("Server stopped"); + } catch (err) { + addLspLog(serverId, "error", `Stop failed: ${err.message}`); + toast("Failed to stop"); + } +} + +async function startAllServers() { + toast("Starting LSP servers..."); + try { + window.editorManager?.restartLsp?.(); + toast("Servers started"); + } catch (err) { + toast("Failed to start servers"); + } +} + +async function restartAllServers() { + const activeClients = getActiveClients(); + if (!activeClients.length) { + await startAllServers(); + return; + } + + const count = activeClients.length; + toast(`Restarting ${count} LSP server${count > 1 ? "s" : ""}...`); + + try { + await lspClientManager.dispose(); + window.editorManager?.restartLsp?.(); + toast("All servers restarted"); + } catch (err) { + toast("Failed to restart servers"); + } +} + +async function stopAllServers() { + const activeClients = getActiveClients(); + if (!activeClients.length) { + toast("No LSP servers are currently running"); + return; + } + + const count = activeClients.length; + + try { + await lspClientManager.dispose(); + toast(`Stopped ${count} LSP server${count > 1 ? "s" : ""}`); + } catch (err) { + toast("Failed to stop servers"); + } +} + +function showLspInfoDialog() { + if (dialogInstance) { + dialogInstance.hide(); + return; + } + + const relevantServers = getServersForCurrentFile(); + const currentLanguage = getCurrentFileLanguage(); + + let currentView = "list"; + let selectedServer = null; + + const $mask = ; + const $dialog = ( +
+
+ + Language Servers +
+
+
+ ); + + const $body = $dialog.querySelector(".lsp-dialog-body"); + + function renderList() { + $body.innerHTML = ""; + + if (relevantServers.length === 0) { + $body.appendChild( +
+ +

+ No language servers for{" "} + {currentLanguage || "this file"} +

+
, + ); + return; + } + + const $list =
    ; + + const runningServers = relevantServers.filter( + (s) => getServerStatus(s.id) !== "stopped", + ); + const hasRunning = runningServers.length > 0; + + const $actions = ( +
    + + {hasRunning && ( + + )} +
    + ); + $body.appendChild($actions); + + for (const server of relevantServers) { + const status = getServerStatus(server.id); + const statusColor = getStatusColor(status); + const logs = getLspLogs(server.id); + const errorCount = logs.filter((l) => l.level === "error").length; + + const $item = ( +
  • { + selectedServer = server; + currentView = "details"; + renderDetails(); + }} + > + +
    + {server.label} + {status} +
    + {errorCount > 0 && ( + {errorCount} + )} + +
  • + ); + $list.appendChild($item); + } + + $body.appendChild($list); + } + + function renderDetails() { + if (!selectedServer) return; + $body.innerHTML = ""; + + const server = selectedServer; + const status = getServerStatus(server.id); + const clientState = getClientState(server.id); + const isRunning = status !== "stopped"; + + const capabilities = []; + const hasCapabilities = clientState?.client?.serverCapabilities; + if (hasCapabilities) { + const caps = clientState.client.serverCapabilities; + if (caps.completionProvider) capabilities.push("Completion"); + if (caps.hoverProvider) capabilities.push("Hover"); + if (caps.definitionProvider) capabilities.push("Go to Definition"); + if (caps.referencesProvider) capabilities.push("Find References"); + if (caps.renameProvider) capabilities.push("Rename"); + if (caps.documentFormattingProvider) capabilities.push("Format"); + if (caps.signatureHelpProvider) capabilities.push("Signature Help"); + if (caps.inlayHintProvider) capabilities.push("Inlay Hints"); + if (caps.codeActionProvider) capabilities.push("Code Actions"); + if (caps.diagnosticProvider) capabilities.push("Diagnostics"); + } + if (isRunning && capabilities.length === 0 && hasCapabilities) { + capabilities.push("Diagnostics"); + } + + const logs = getLspLogs(server.id); + + const $details = ( +
    +
    + +
    + + {server.label} +
    +
    + + {isRunning && ( + + )} +
    +
    + + {isRunning && ( +
    +
    Capabilities
    +
    + {capabilities.length > 0 + ? capabilities.map((cap) => ( + {cap} + )) + : !hasCapabilities && ( + Initializing... + )} +
    +
    + )} + +
    +
    Supported
    +
    + {server.languages.map((lang) => ( + .{lang} + ))} +
    +
    + + {isRunning && ( +
    +
    Project
    +
    + {clientState?.rootUri || "(workspace folders mode)"} +
    +
    + )} + + {isRunning && ( +
    +
    Resources
    +
    +
    + Memory + + — + +
    +
    + Uptime + + — + +
    +
    + PID + + — + +
    +
    +
    + )} +
    + ); + + $body.appendChild($details); + + // Create simple collapsible logs section + const $logsSection = ( +
    +
    { + const section = e.currentTarget.closest(".lsp-logs-section"); + if (section) { + section.classList.toggle("collapsed"); + if (!section.classList.contains("collapsed")) { + const container = section.querySelector(".lsp-logs-container"); + if (container) container.scrollTop = container.scrollHeight; + } + } + }} + > +
    + + LSP Logs + {logs.length > 0 && ( + ({logs.length}) + )} +
    +
    + + +
    +
    +
    + {logs.length === 0 + ?
    No logs yet
    + : logs.slice(-50).map((log) => { + const time = log.timestamp.toLocaleTimeString("en-US", { + hour12: false, + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }); + return ( +
    + {time} + {log.message} +
    + ); + })} +
    +
    + ); + + $body.appendChild($logsSection); + + // Fetch and update stats asynchronously + if (isRunning) { + getServerStats(server.id).then((stats) => { + if (!stats) return; + const $mem = document.getElementById(`lsp-mem-${server.id}`); + const $uptime = document.getElementById(`lsp-uptime-${server.id}`); + const $pid = document.getElementById(`lsp-pid-${server.id}`); + if ($mem) $mem.textContent = stats.memoryFormatted; + if ($uptime) $uptime.textContent = stats.uptimeFormatted; + if ($pid) $pid.textContent = stats.pid ? String(stats.pid) : "—"; + }); + } + } + + function hide() { + $dialog.classList.add("hide"); + restoreTheme(); + actionStack.remove("lsp-info-dialog"); + setTimeout(() => { + $dialog.remove(); + $mask.remove(); + dialogInstance = null; + }, 200); + } + + dialogInstance = { hide, element: $dialog }; + + actionStack.push({ + id: "lsp-info-dialog", + action: hide, + }); + + restoreTheme(true); + document.body.appendChild($dialog); + document.body.appendChild($mask); + + if (currentView === "list") { + renderList(); + } +} + +function hasConnectedServers() { + const relevantServers = getServersForCurrentFile(); + return relevantServers.length > 0; +} + +export { showLspInfoDialog, hasConnectedServers, addLspLog, getLspLogs }; +export default showLspInfoDialog; diff --git a/src/components/lspInfoDialog/styles.scss b/src/components/lspInfoDialog/styles.scss new file mode 100644 index 000000000..be11bbfef --- /dev/null +++ b/src/components/lspInfoDialog/styles.scss @@ -0,0 +1,457 @@ +:root { + --lsp-status-active: #22c55e; + --lsp-status-connecting: #f59e0b; + --lsp-status-stopped: #6b7280; +} + +.lsp-info-dialog { + max-width: 360px; + min-width: 300px; + + .title { + display: flex; + align-items: center; + text-transform: none; + font-weight: 500; + } +} + +.lsp-dialog-body { + overflow-y: auto; + max-height: 65vh; + + &::-webkit-scrollbar { + width: 4px; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); + border-radius: 2px; + } +} + +.lsp-empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 48px 24px; + color: var(--popup-text-color); + text-align: center; + + .icon { + font-size: 2.5rem; + margin-bottom: 16px; + opacity: 0.3; + } + + p { + font-size: 0.9rem; + margin: 0; + opacity: 0.6; + + strong { + opacity: 1; + } + } +} + +.lsp-list-actions { + display: flex; + gap: 8px; + padding: 8px 12px; + border-bottom: 1px solid var(--border-color); +} + +.lsp-action-btn { + display: flex; + align-items: center; + gap: 6px; + flex: 1; + justify-content: center; + padding: 8px 12px; + background-color: var(--box-shadow-color); + border: none; + color: var(--popup-text-color); + cursor: pointer; + border-radius: 6px; + font-size: 0.75rem; + font-weight: 500; + transition: all 0.12s ease; + + .icon { + font-size: 0.9rem; + } + + &:hover { + background-color: var(--active-icon-color); + } + + &.danger { + color: var(--danger-color); + + &:hover { + background-color: color-mix(in srgb, var(--danger-color) 15%, transparent); + } + } +} + +.lsp-server-list { + list-style: none; + padding: 8px; + margin: 0; +} + +.lsp-server-item { + display: flex; + align-items: center; + gap: 12px; + padding: 14px 12px; + border-radius: 6px; + cursor: pointer; + transition: background-color 0.12s ease; + color: var(--popup-text-color); + + &:hover { + background-color: var(--box-shadow-color); + } + + &:active { + background-color: var(--active-icon-color); + } + + &:not(:last-child) { + border-bottom: 1px solid var(--border-color); + } +} + +.lsp-arrow { + font-size: 1.3rem; + opacity: 0.35; + margin-left: auto; +} + +.lsp-status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + flex-shrink: 0; +} + +.lsp-server-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: 2px; +} + +.lsp-server-name { + font-size: 0.95rem; + font-weight: 500; + color: var(--popup-text-color); +} + +.lsp-server-status { + font-size: 0.72rem; + color: var(--popup-text-color); + opacity: 0.5; + text-transform: capitalize; +} + +.lsp-error-badge { + display: flex; + align-items: center; + justify-content: center; + min-width: 18px; + height: 18px; + padding: 0 5px; + background-color: var(--danger-color); + color: var(--danger-text-color); + font-size: 0.65rem; + font-weight: 600; + border-radius: 9px; +} + +.lsp-details { + display: flex; + flex-direction: column; +} + +.lsp-details-header { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + border-bottom: 1px solid var(--border-color); +} + +.lsp-header-actions { + display: flex; + gap: 4px; + margin-left: auto; +} + +.lsp-icon-btn { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: transparent; + border: none; + color: var(--popup-text-color); + cursor: pointer; + border-radius: 6px; + padding: 0; + transition: all 0.12s ease; + opacity: 0.7; + + &:hover { + background-color: var(--box-shadow-color); + opacity: 1; + } + + &:active { + background-color: var(--active-icon-color); + } + + .icon { + font-size: 1.1rem; + } + + &.small { + width: 26px; + height: 26px; + + .icon { + font-size: 0.95rem; + } + } + + &.danger { + color: var(--danger-color); + + &:hover { + background-color: color-mix(in srgb, var(--danger-color) 15%, transparent); + } + } +} + +.lsp-details-title { + display: flex; + align-items: center; + gap: 10px; + font-size: 0.95rem; + font-weight: 500; + color: var(--popup-text-color); +} + +.lsp-section { + padding: 10px 14px; + + &:last-child { + border-bottom: none; + } +} + +.lsp-section-label { + font-size: 0.65rem; + font-weight: 600; + color: var(--popup-text-color); + opacity: 0.5; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 8px; +} + +.lsp-chip-container { + display: flex; + flex-wrap: wrap; + gap: 5px; +} + +.lsp-chip { + display: inline-flex; + align-items: center; + padding: 4px 10px; + background: var(--box-shadow-color); + color: var(--popup-text-color); + border-radius: 4px; + font-size: 0.7rem; + font-weight: 500; + + &.ext { + font-family: monospace; + font-weight: 600; + background: color-mix(in srgb, var(--active-color) 15%, transparent); + color: var(--active-color); + } +} + +.lsp-project-path { + font-size: 0.75rem; + font-family: monospace; + color: var(--popup-text-color); + opacity: 0.75; + word-break: break-all; + padding: 8px 10px; + background-color: var(--box-shadow-color); + border-radius: 6px; + line-height: 1.3; +} + +.lsp-logs-section { + margin: 8px 14px 12px; + + &.collapsed { + .lsp-logs-container { + display: none; + } + + .lsp-expand-icon { + transform: rotate(-90deg); + } + + .lsp-clear-btn { + display: none; + } + } +} + +.lsp-logs-header { + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + padding: 6px 8px; + margin: 0 -8px; +} + +.lsp-logs-title { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.75rem; + font-weight: 500; + color: var(--popup-text-color); + opacity: 0.7; +} + +.lsp-expand-icon { + font-size: 1.1rem; + transition: transform 0.15s ease; +} + +.lsp-log-count { + font-size: 0.65rem; + opacity: 0.5; + margin-left: 2px; +} + +.lsp-logs-actions { + display: flex; + gap: 2px; +} + +.lsp-logs-container { + max-height: 160px; + overflow-y: auto; + background-color: var(--box-shadow-color); + border-radius: 6px; + font-family: monospace; + font-size: 0.65rem; + margin-top: 4px; + + &::-webkit-scrollbar { + width: 3px; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); + border-radius: 2px; + } +} + +.lsp-logs-empty { + padding: 14px; + text-align: center; + color: var(--popup-text-color); + opacity: 0.4; + font-size: 0.7rem; + font-family: inherit; +} + +.lsp-log { + display: flex; + gap: 6px; + padding: 1px 8px; + line-height: 1.3; + + &:first-child { + padding-top: 4px; + } + + &:last-child { + padding-bottom: 4px; + } + + &.error .lsp-log-text { + color: var(--danger-color); + } + + &.warn .lsp-log-text { + color: var(--error-text-color); + } + + &.stderr .lsp-log-text { + color: var(--error-text-color); + } +} + +.lsp-log-time { + flex-shrink: 0; + color: var(--popup-text-color); + opacity: 0.35; + font-size: 0.6rem; +} + +.lsp-log-text { + flex: 1; + color: var(--popup-text-color); + opacity: 0.85; + word-break: break-word; +} + +.lsp-stats-container { + display: flex; + gap: 16px; +} + +.lsp-stat { + display: flex; + align-items: baseline; + gap: 6px; +} + +.lsp-stat-label { + font-size: 0.65rem; + font-weight: 500; + color: var(--popup-text-color); + opacity: 0.75; +} + +.lsp-stat-value { + font-size: 0.8rem; + font-weight: 600; + color: var(--popup-text-color); + font-family: monospace; +} \ No newline at end of file diff --git a/src/components/lspStatusBar/index.js b/src/components/lspStatusBar/index.js new file mode 100644 index 000000000..c8f2a6003 --- /dev/null +++ b/src/components/lspStatusBar/index.js @@ -0,0 +1,353 @@ +import "./style.scss"; + +/**@type {HTMLElement | null} */ +let $statusBar = null; + +/**@type {number | null} */ +let hideTimeout = null; + +/** + * @typedef {Object} ProgressItem + * @property {string} title - Task title + * @property {string} [message] - Current message + * @property {number} [percentage] - Progress percentage (0-100) + */ + +/**@type {Map} */ +const activeProgress = new Map(); + +/**@type {string | null} */ +let currentServerId = null; + +/**@type {string | null} */ +let currentServerLabel = null; + +/** + * @typedef {Object} LspStatusOptions + * @property {string} message - The status message to display + * @property {string} [icon] - Optional icon class name + * @property {'info' | 'success' | 'warning' | 'error'} [type='info'] - Status type + * @property {number | false} [duration=0] - Duration in ms, 0 for default (5000ms), false for persistent + * @property {boolean} [showProgress=false] - Whether to show a progress indicator + * @property {number} [progress] - Progress percentage (0-100) + * @property {string} [title] - Optional title for the status + * @property {string} [id] - Unique identifier for progress tracking + */ + +/** + * Ensure the status bar exists + * @returns {HTMLElement} + */ +function ensureStatusBar() { + if ($statusBar && document.body.contains($statusBar)) { + return $statusBar; + } + + $statusBar = ( +
    +
    + +
    + + +
    +
    + +
    +
    + +
    + ); + + // Find the quicktools footer to insert before it + const $footer = document.getElementById("quick-tools"); + if ($footer && $footer.parentNode) { + $footer.parentNode.insertBefore($statusBar, $footer); + } else { + // Fallback: append to app + const $app = document.getElementById("app") || document.body; + $app.appendChild($statusBar); + } + + return $statusBar; +} + +/** + * Build aggregated message from all active progress items + * @returns {{ message: string, avgProgress: number | null, taskCount: number }} + */ +function buildAggregatedStatus() { + const items = Array.from(activeProgress.values()); + const taskCount = items.length; + + if (taskCount === 0) { + return { message: "", avgProgress: null, taskCount: 0 }; + } + + // Calculate average progress for items that have percentage + const itemsWithProgress = items.filter( + (item) => typeof item.percentage === "number", + ); + const avgProgress = + itemsWithProgress.length > 0 + ? Math.round( + itemsWithProgress.reduce( + (sum, item) => sum + (item.percentage || 0), + 0, + ) / itemsWithProgress.length, + ) + : null; + + // Build message + if (taskCount === 1) { + const item = items[0]; + const parts = []; + if (item.message) { + parts.push(item.message); + } else if (item.title) { + parts.push(item.title); + } + return { message: parts.join(" "), avgProgress, taskCount }; + } + + // Multiple tasks - show count and maybe the most recent message + const latestWithMessage = items.filter((item) => item.message).pop(); + const message = latestWithMessage + ? `${taskCount} tasks: ${latestWithMessage.message}` + : `${taskCount} tasks running`; + + return { message, avgProgress, taskCount }; +} + +/** + * Update the status bar display + */ +function updateStatusBarDisplay() { + const bar = $statusBar; + if (!bar) return; + + const { message, avgProgress, taskCount } = buildAggregatedStatus(); + + if (taskCount === 0) { + hideStatusBar(); + return; + } + + const $title = bar.querySelector(".lsp-status-title"); + const $message = bar.querySelector(".lsp-status-message"); + const $progressText = bar.querySelector(".lsp-status-progress-text"); + const $progressContainer = bar.querySelector(".lsp-status-progress"); + const $icon = bar.querySelector(".lsp-status-icon"); + + if ($title) $title.textContent = currentServerLabel || ""; + if ($message) $message.textContent = message; + + if (avgProgress !== null && $progressText && $progressContainer) { + $progressText.textContent = `${avgProgress}%`; + $progressContainer.style.display = ""; + } else if ($progressContainer) { + $progressContainer.style.display = "none"; + } + + // Show spinning icon while progress is active + if ($icon) { + $icon.className = "lsp-status-icon icon autorenew"; + } + + bar.className = "lsp-status info"; + bar.classList.remove("hiding"); +} + +/** + * Hide the status bar + */ +function hideStatusBar() { + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } + + if ($statusBar) { + $statusBar.classList.add("hiding"); + setTimeout(() => { + if ($statusBar) { + $statusBar.remove(); + $statusBar = null; + } + }, 300); + } +} + +/** + * Show LSP status notification + * @param {LspStatusOptions} options - Status options + * @returns {string | undefined} The status ID for later updates/removal + */ +export function showLspStatus(options) { + const { + message, + icon = "autorenew", + type = "info", + duration = 0, + showProgress = false, + progress, + title, + id, + } = options; + + // Clear any existing hide timeout + if (hideTimeout) { + clearTimeout(hideTimeout); + hideTimeout = null; + } + + // If this is a progress item (has id), track it + if (id && id.includes("-progress-")) { + // Extract server info from id (format: serverId-progress-token) + const serverMatch = id.match(/^(.+?)-progress-/); + if (serverMatch) { + currentServerId = serverMatch[1]; + currentServerLabel = title || currentServerId; + } + + activeProgress.set(id, { + title: title || "", + message: message || "", + percentage: progress, + }); + + ensureStatusBar(); + updateStatusBarDisplay(); + return id; + } + + // For non-progress messages (errors, warnings, etc.) + const bar = ensureStatusBar(); + + const $title = bar.querySelector(".lsp-status-title"); + const $message = bar.querySelector(".lsp-status-message"); + const $progressText = bar.querySelector(".lsp-status-progress-text"); + const $progressContainer = bar.querySelector(".lsp-status-progress"); + const $icon = bar.querySelector(".lsp-status-icon"); + + if ($title) $title.textContent = title || ""; + if ($message) $message.textContent = message; + + const hasProgress = showProgress && typeof progress === "number"; + if (hasProgress && $progressText && $progressContainer) { + $progressText.textContent = `${Math.round(progress)}%`; + $progressContainer.style.display = ""; + } else if ($progressContainer) { + $progressContainer.style.display = "none"; + } + + if ($icon) { + $icon.className = `lsp-status-icon icon ${icon}`; + } + + bar.className = `lsp-status ${type}`; + bar.classList.remove("hiding"); + + // Auto-hide after duration unless duration is false + if (duration !== false) { + const ms = duration || 5000; + hideTimeout = window.setTimeout(() => { + // Only hide if no progress is active + if (activeProgress.size === 0) { + hideStatusBar(); + } + }, ms); + } + + return id; +} + +/** + * Hide a specific progress item by ID + * @param {string} id - The progress ID to hide + */ +export function hideStatus(id) { + if (activeProgress.has(id)) { + activeProgress.delete(id); + + if (activeProgress.size === 0) { + // All progress complete - hide after a brief delay + hideTimeout = window.setTimeout(() => { + hideStatusBar(); + }, 500); + } else { + updateStatusBarDisplay(); + } + } +} + +/** + * Hide the LSP status bar (legacy support - hides all) + */ +export function hideLspStatus() { + activeProgress.clear(); + hideStatusBar(); +} + +/** + * Update a progress item + * @param {Partial & { id?: string }} options - Options to update + * @returns {string | null} The status ID + */ +export function updateLspStatus(options) { + const { id, message, progress } = options; + + if (!id || !activeProgress.has(id)) { + return null; + } + + const item = activeProgress.get(id); + if (item) { + if (message !== undefined) item.message = message; + if (progress !== undefined) item.percentage = progress; + activeProgress.set(id, item); + updateStatusBarDisplay(); + } + + return id; +} + +/** + * Check if status bar is currently visible + * @returns {boolean} + */ +export function isLspStatusVisible() { + return $statusBar !== null && document.body.contains($statusBar); +} + +/** + * Get count of active progress items + * @returns {number} + */ +export function getActiveStatusCount() { + return activeProgress.size; +} + +/** + * Check if a specific progress item exists + * @param {string} id - The progress ID to check + * @returns {boolean} + */ +export function hasStatus(id) { + return activeProgress.has(id); +} + +export default { + show: showLspStatus, + hide: hideLspStatus, + hideById: hideStatus, + update: updateLspStatus, + isVisible: isLspStatusVisible, + getActiveCount: getActiveStatusCount, + has: hasStatus, +}; diff --git a/src/components/lspStatusBar/style.scss b/src/components/lspStatusBar/style.scss new file mode 100644 index 000000000..ac0a78e63 --- /dev/null +++ b/src/components/lspStatusBar/style.scss @@ -0,0 +1,198 @@ +@use "../../styles/mixins.scss"; + +#lsp-status-bar { + position: fixed; + bottom: 50px; + left: 0; + right: 0; + margin: 0 auto; + max-width: 95vw; + width: fit-content; + min-width: 200px; + padding: 8px 12px; + padding-right: 36px; + background-color: var(--secondary-color); + color: var(--secondary-text-color); + border-radius: 6px; + box-shadow: 0 2px 12px var(--box-shadow-color); + border: 1px solid var(--border-color); + z-index: 97; + animation: lspStatusSlideUp 0.3s ease-out; + transition: all 0.3s ease; + box-sizing: border-box; + + &.hiding { + animation: lspStatusSlideDown 0.3s ease-out forwards; + } + + .lsp-status-content { + display: flex; + align-items: center; + gap: 10px; + } + + .lsp-status-icon { + width: 20px; + height: 20px; + font-size: 1rem; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + + &.autorenew { + animation: lspSpinSlow 2s linear infinite; + } + } + + .lsp-status-text { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; + flex: 1; + } + + .lsp-status-title { + font-size: 0.75rem; + font-weight: 600; + color: var(--primary-text-color); + text-transform: uppercase; + letter-spacing: 0.5px; + opacity: 0.8; + } + + .lsp-status-message { + font-size: 0.85rem; + font-weight: 400; + color: var(--secondary-text-color); + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 60vw; + } + + .lsp-status-progress { + display: flex; + align-items: center; + gap: 8px; + margin-left: auto; + flex-shrink: 0; + } + + .lsp-status-progress-text { + font-size: 0.8rem; + font-weight: 500; + color: var(--active-color); + min-width: 36px; + text-align: right; + } + + .lsp-status-close { + position: absolute; + top: 50%; + right: 6px; + transform: translateY(-50%); + width: 24px; + height: 24px; + font-size: 0.9rem; + display: flex; + align-items: center; + justify-content: center; + background: transparent; + border: none; + color: var(--secondary-text-color); + cursor: pointer; + border-radius: 4px; + transition: all 0.2s ease; + padding: 0; + + &:hover, + &:active { + background-color: rgba(0, 0, 0, 0.1); + color: var(--primary-text-color); + } + } + + // Status type colors + &.info { + .lsp-status-icon { + color: var(--active-color); + } + } + + &.success { + .lsp-status-icon { + color: #48c158; + } + + .lsp-status-progress-text { + color: #48c158; + } + } + + &.warning { + .lsp-status-icon { + color: #f59e0b; + } + } + + &.error { + .lsp-status-icon { + color: var(--error-text-color); + } + } +} + +// Adjust position when quicktools has different heights +wc-page[footer-height="1"] #lsp-status-bar { + bottom: 50px; +} + +wc-page[footer-height="2"] #lsp-status-bar { + bottom: 90px; +} + +wc-page[footer-height="3"] #lsp-status-bar { + bottom: 130px; +} + +// When quicktools is hidden +wc-page:not([footer-height]) #lsp-status-bar { + bottom: 10px; +} + +@keyframes lspStatusSlideUp { + from { + transform: translateY(100%); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes lspStatusSlideDown { + from { + transform: translateY(0); + opacity: 1; + } + + to { + transform: translateY(100%); + opacity: 0; + } +} + +@keyframes lspSpinSlow { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/src/components/referencesPanel/index.js b/src/components/referencesPanel/index.js new file mode 100644 index 000000000..4e301fbd2 --- /dev/null +++ b/src/components/referencesPanel/index.js @@ -0,0 +1,336 @@ +import "./styles.scss"; +import actionStack from "lib/actionStack"; +import { openReferencesTab } from "./referencesTab"; +import { + buildFlatList, + clearHighlightCache, + createReferenceItem, + getReferencesStats, + navigateToReference, + sanitize, +} from "./utils"; + +let currentPanel = null; + +function createReferencesPanel() { + const state = { + visible: false, + expanded: false, + loading: true, + symbolName: "", + references: [], + collapsedFiles: new Set(), + flatItems: [], + }; + + const $mask = ; + const $panel =
    ; + const $dragHandle =
    ; + const $title =
    ; + const $subtitle = ; + const $content =
    ; + const $refList =
    ; + + const $openTabBtn = ( + + ); + + const $closeBtn = ( + + ); + + const $header = ( +
    +
    + {$title} + {$subtitle} +
    +
    + {$openTabBtn} + {$closeBtn} +
    +
    + ); + + $panel.append($dragHandle, $header, $content); + $mask.onclick = hide; + + let startY = 0; + let currentY = 0; + let isDragging = false; + + $dragHandle.ontouchstart = onDragStart; + $dragHandle.onmousedown = onDragStart; + + function onDragStart(e) { + isDragging = true; + startY = e.touches ? e.touches[0].clientY : e.clientY; + currentY = startY; + $panel.style.transition = "none"; + + document.addEventListener("touchmove", onDragMove, { passive: false }); + document.addEventListener("mousemove", onDragMove); + document.addEventListener("touchend", onDragEnd); + document.addEventListener("mouseup", onDragEnd); + } + + function onDragMove(e) { + if (!isDragging) return; + e.preventDefault(); + currentY = e.touches ? e.touches[0].clientY : e.clientY; + const deltaY = currentY - startY; + + if (deltaY > 0) { + $panel.style.transform = `translateY(${deltaY}px)`; + } else if (!state.expanded) { + const expansion = Math.min(Math.abs(deltaY), 100); + $panel.style.maxHeight = `${60 + (expansion / 100) * 25}vh`; + } + } + + function onDragEnd() { + isDragging = false; + document.removeEventListener("touchmove", onDragMove); + document.removeEventListener("mousemove", onDragMove); + document.removeEventListener("touchend", onDragEnd); + document.removeEventListener("mouseup", onDragEnd); + + $panel.style.transition = ""; + const deltaY = currentY - startY; + + if (deltaY > 100) { + hide(); + } else if (deltaY < -50 && !state.expanded) { + state.expanded = true; + $panel.classList.add("expanded"); + $panel.style.transform = ""; + $panel.style.maxHeight = ""; + } else { + $panel.style.transform = ""; + $panel.style.maxHeight = ""; + } + } + + function setTitle(symbolName) { + $title.innerHTML = ""; + $title.append( + , + References to , + {sanitize(symbolName)}, + ); + } + + function setSubtitle(text) { + $subtitle.textContent = text; + } + + function openInTab() { + const refs = state.references; + const sym = state.symbolName; + hide(); + openReferencesTab({ + symbolName: sym, + references: refs, + }); + } + + function toggleFile(uri) { + if (state.collapsedFiles.has(uri)) { + state.collapsedFiles.delete(uri); + } else { + state.collapsedFiles.add(uri); + } + renderReferencesList(); + } + + function renderLoading() { + $content.innerHTML = ""; + $content.append( +
    +
    + Finding references... +
    , + ); + } + + function renderEmpty() { + $content.innerHTML = ""; + $content.append( +
    + + No references found +
    , + ); + } + + function renderReferencesList() { + $refList.innerHTML = ""; + + const visibleItems = state.flatItems.filter((item) => { + if (item.type === "file-header") return true; + return !state.collapsedFiles.has(item.uri); + }); + + const fragment = document.createDocumentFragment(); + + for (const item of visibleItems) { + const $el = createReferenceItem(item, { + collapsedFiles: state.collapsedFiles, + onToggleFile: toggleFile, + onNavigate: (ref) => { + hide(); + navigateToReference(ref); + }, + }); + fragment.appendChild($el); + } + + $refList.appendChild(fragment); + $content.innerHTML = ""; + $content.appendChild($refList); + } + + async function renderReferences() { + $content.innerHTML = ""; + $content.append( +
    +
    + Highlighting code... +
    , + ); + + const stats = getReferencesStats(state.references); + setSubtitle(stats.text); + + state.flatItems = await buildFlatList(state.references, state.symbolName); + + renderReferencesList(); + } + + function show(options = {}) { + if (currentPanel && currentPanel !== panelInstance) { + currentPanel.hide(); + } + currentPanel = panelInstance; + + state.symbolName = options.symbolName || ""; + state.references = []; + state.loading = true; + state.expanded = false; + state.collapsedFiles.clear(); + state.flatItems = []; + + clearHighlightCache(); + + setTitle(state.symbolName); + setSubtitle("Searching..."); + renderLoading(); + + document.body.append($mask, $panel); + + requestAnimationFrame(() => { + $mask.classList.add("visible"); + $panel.classList.add("visible"); + $panel.classList.remove("expanded"); + }); + + state.visible = true; + + actionStack.push({ + id: "references-panel", + action: hide, + }); + } + + function hide() { + if (!state.visible) return; + state.visible = false; + + $mask.classList.remove("visible"); + $panel.classList.remove("visible"); + + actionStack.remove("references-panel"); + + setTimeout(() => { + $mask.remove(); + $panel.remove(); + }, 250); + + if (currentPanel === panelInstance) { + currentPanel = null; + } + } + + function setReferences(references) { + state.loading = false; + state.references = references || []; + + if (state.references.length === 0) { + setSubtitle("No references found"); + renderEmpty(); + } else { + renderReferences(); + } + } + + function setError(message) { + state.loading = false; + setSubtitle("Error"); + $content.innerHTML = ""; + $content.append( +
    + + {sanitize(message)} +
    , + ); + } + + const panelInstance = { + show, + hide, + setReferences, + setError, + get visible() { + return state.visible; + }, + }; + + return panelInstance; +} + +let panelSingleton = null; + +function getPanel() { + if (!panelSingleton) { + panelSingleton = createReferencesPanel(); + } + return panelSingleton; +} + +export function showReferencesPanel(options) { + const panel = getPanel(); + panel.show(options); + return panel; +} + +export function hideReferencesPanel() { + const panel = getPanel(); + panel.hide(); +} + +export { openReferencesTab }; + +export default { + show: showReferencesPanel, + hide: hideReferencesPanel, + getPanel, + openReferencesTab, +}; diff --git a/src/components/referencesPanel/referencesTab.js b/src/components/referencesPanel/referencesTab.js new file mode 100644 index 000000000..457254452 --- /dev/null +++ b/src/components/referencesPanel/referencesTab.js @@ -0,0 +1,149 @@ +import EditorFile from "lib/editorFile"; +import { + buildFlatList, + clearHighlightCache, + createReferenceItem, + getReferencesStats, + navigateToReference, + sanitize, +} from "./utils"; + +export function createReferencesTab(options = {}) { + const { + symbolName = "", + references = [], + flatItems: prebuiltItems = null, + } = options; + const collapsedFiles = new Set(); + let flatItems = prebuiltItems || []; + let isInitialized = false; + + const $container =
    ; + const $listContainer =
    ; + const $refList =
    ; + + const stats = getReferencesStats(references); + + const $header = ( +
    +
    + + + References to {sanitize(symbolName)} + + {stats.text} +
    +
    + ); + + const $loadingState = ( +
    +
    + Highlighting code... +
    + ); + + $container.append($header, $listContainer); + + function getVisibleItems() { + return flatItems.filter((item) => { + if (item.type === "file-header") return true; + return !collapsedFiles.has(item.uri); + }); + } + + function toggleFile(uri) { + if (collapsedFiles.has(uri)) { + collapsedFiles.delete(uri); + } else { + collapsedFiles.add(uri); + } + renderList(); + } + + function renderList() { + $refList.innerHTML = ""; + + const visibleItems = getVisibleItems(); + const fragment = document.createDocumentFragment(); + + for (const item of visibleItems) { + const $el = createReferenceItem(item, { + collapsedFiles, + onToggleFile: toggleFile, + onNavigate: navigateToReference, + }); + fragment.appendChild($el); + } + + $refList.appendChild(fragment); + } + + async function init() { + if (isInitialized) return; + isInitialized = true; + + if (!prebuiltItems || prebuiltItems.length === 0) { + $listContainer.appendChild($loadingState); + flatItems = await buildFlatList(references, symbolName); + $loadingState.remove(); + } + + renderList(); + $listContainer.appendChild($refList); + } + + function destroy() { + $refList.innerHTML = ""; + } + + return { + container: $container, + init, + destroy, + get symbolName() { + return symbolName; + }, + get referenceCount() { + return references.length; + }, + }; +} + +export async function openReferencesTab(options = {}) { + const { symbolName = "", references = [] } = options; + + const tabName = `Refs: ${symbolName}`; + const existingFile = editorManager.getFile(tabName, "filename"); + if (existingFile) { + existingFile.makeActive(); + return existingFile; + } + + clearHighlightCache(); + const flatItems = await buildFlatList(references, symbolName); + const stats = getReferencesStats(references); + + const tabView = createReferencesTab({ symbolName, references, flatItems }); + + const file = new EditorFile(tabName, { + type: "terminal", + content: tabView.container, + tabIcon: "icon linkinsert_link", + render: true, + }); + + file.setCustomTitle(() => stats.text); + tabView.init(); + + file.on("close", () => { + tabView.destroy(); + }); + + return file; +} + +export default { + createReferencesTab, + openReferencesTab, +}; diff --git a/src/components/referencesPanel/styles.scss b/src/components/referencesPanel/styles.scss new file mode 100644 index 000000000..b2c8a124b --- /dev/null +++ b/src/components/referencesPanel/styles.scss @@ -0,0 +1,380 @@ +@use "../../styles/mixins.scss"; + +.references-panel-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.4); + z-index: 100; + opacity: 0; + transition: opacity 200ms ease-out; + pointer-events: none; + + &.visible { + opacity: 1; + pointer-events: auto; + } +} + +.references-panel { + position: fixed; + left: 0; + right: 0; + bottom: 0; + z-index: 101; + background-color: var(--popup-background-color); + border-top-left-radius: 12px; + border-top-right-radius: 12px; + box-shadow: 0 -4px 20px var(--box-shadow-color); + transform: translateY(100%); + transition: transform 250ms ease-out, max-height 200ms ease-out; + display: flex; + flex-direction: column; + max-height: 60vh; + overflow: hidden; + + &.visible { + transform: translateY(0); + } + + &.expanded { + max-height: 85vh; + } + + .drag-handle { + display: flex; + justify-content: center; + align-items: center; + padding: 8px 0 4px 0; + cursor: grab; + flex-shrink: 0; + + &::after { + content: ""; + width: 36px; + height: 4px; + background-color: var(--border-color); + border-radius: 2px; + } + + &:active { + cursor: grabbing; + } + } + + .panel-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 12px 12px 16px; + border-bottom: 1px solid var(--border-color); + min-height: 44px; + flex-shrink: 0; + + .header-content { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; + min-width: 0; + + .header-title { + display: flex; + align-items: center; + gap: 8px; + font-size: 1rem; + font-weight: 600; + color: var(--primary-text-color); + + .icon { + font-size: 1.1em; + opacity: 0.7; + } + + .symbol-name { + font-family: monospace; + background-color: var(--secondary-color); + padding: 2px 8px; + border-radius: 4px; + max-width: 160px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .header-subtitle { + font-size: 0.85rem; + color: var(--secondary-text-color); + opacity: 0.8; + } + } + + .header-actions { + display: flex; + gap: 4px; + flex-shrink: 0; + } + + .action-btn { + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + border: none; + background: transparent; + color: var(--secondary-text-color); + border-radius: 50%; + cursor: pointer; + + &:active { + background-color: var(--active-icon-color); + } + + .icon { + font-size: 1.2em; + } + + &.open-tab-btn { + color: var(--active-color); + } + } + } + + .panel-content { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; + overscroll-behavior: contain; + + &::-webkit-scrollbar { + width: var(--scrollbar-width, 4px); + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--scrollbar-color, rgba(0, 0, 0, 0.333)); + border-radius: calc(var(--scrollbar-width, 4px) / 2); + } + } + + .loading-state { + display: flex; + align-items: center; + justify-content: center; + padding: 32px 16px; + color: var(--secondary-text-color); + gap: 12px; + + .loader { + @include mixins.circular-loader(24px); + } + } + + .empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 32px 16px; + color: var(--secondary-text-color); + text-align: center; + + .icon { + font-size: 2rem; + margin-bottom: 8px; + opacity: 0.5; + } + } +} + +.ref-file-header, +.ref-item { + box-sizing: border-box; + display: flex; + align-items: center; + will-change: transform; +} + +.ref-file-header { + gap: 8px; + padding: 0 16px; + cursor: pointer; + user-select: none; + background-color: color-mix(in srgb, var(--secondary-color) 50%, var(--primary-color)); + + &:active { + background-color: var(--active-icon-color); + } + + .chevron { + font-size: 1rem; + color: var(--secondary-text-color); + transition: transform 150ms ease; + width: 18px; + text-align: center; + flex-shrink: 0; + } + + &.collapsed .chevron { + transform: rotate(-90deg); + } + + .file-icon { + font-size: 1rem; + flex-shrink: 0; + } + + .file-name { + flex: 1; + font-size: 0.9rem; + font-weight: 500; + color: var(--primary-text-color); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 0; + } + + .ref-count { + font-size: 0.75rem; + color: var(--secondary-text-color); + background-color: var(--popup-background-color); + padding: 2px 8px; + border-radius: 10px; + flex-shrink: 0; + } +} + +.ref-item { + gap: 10px; + padding: 0 16px 0 36px; + cursor: pointer; + + &:active { + background-color: var(--active-icon-color); + } + + .line-number { + font-size: 0.75rem; + color: var(--secondary-text-color); + min-width: 32px; + text-align: right; + font-family: monospace; + flex-shrink: 0; + opacity: 0.7; + } + + .ref-preview { + flex: 1; + font-size: 0.85rem; + font-family: monospace; + color: var(--primary-text-color); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + line-height: 1.4; + min-width: 0; + direction: rtl; + text-align: left; + + span { + direction: ltr; + unicode-bidi: bidi-override; + } + + .symbol-match { + background-color: color-mix(in srgb, var(--active-color) 30%, transparent); + border-radius: 2px; + padding: 0 2px; + } + } +} + +.references-tab-container { + display: flex; + flex-direction: column; + height: 100%; + background-color: var(--primary-color); + color: var(--primary-text-color); + + .references-tab-header { + padding: 16px; + border-bottom: 1px solid var(--border-color); + background-color: var(--secondary-color); + flex-shrink: 0; + + .header-info { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + + .icon { + font-size: 1.2em; + opacity: 0.7; + } + + .header-title { + font-size: 1rem; + font-weight: 600; + color: var(--primary-text-color); + + code { + font-family: monospace; + background-color: var(--popup-background-color); + padding: 2px 8px; + border-radius: 4px; + margin-left: 4px; + } + } + + .header-stats { + font-size: 0.85rem; + color: var(--secondary-text-color); + margin-left: auto; + } + } + } + + .references-list-container { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; + overscroll-behavior: contain; + + &::-webkit-scrollbar { + width: var(--scrollbar-width, 4px); + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--scrollbar-color, rgba(0, 0, 0, 0.333)); + border-radius: calc(var(--scrollbar-width, 4px) / 2); + } + + .loading-state { + display: flex; + align-items: center; + justify-content: center; + padding: 32px 16px; + color: var(--secondary-text-color); + gap: 12px; + + .loader { + @include mixins.circular-loader(24px); + } + } + } +} \ No newline at end of file diff --git a/src/components/referencesPanel/utils.js b/src/components/referencesPanel/utils.js new file mode 100644 index 000000000..828cd0d37 --- /dev/null +++ b/src/components/referencesPanel/utils.js @@ -0,0 +1,145 @@ +import { EditorView } from "@codemirror/view"; +import Sidebar from "components/sidebar"; +import DOMPurify from "dompurify"; +import openFile from "lib/openFile"; +import { + clearHighlightCache, + highlightLine, + sanitize, +} from "utils/codeHighlight"; +import helpers from "utils/helpers"; + +export { clearHighlightCache, sanitize }; + +export function getFilename(uri) { + if (!uri) return ""; + try { + const decoded = decodeURIComponent(uri); + const parts = decoded.split("/").filter(Boolean); + return parts.pop() || ""; + } catch { + const parts = uri.split("/").filter(Boolean); + return parts.pop() || ""; + } +} + +export function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +export function groupReferencesByFile(references) { + const grouped = {}; + for (const ref of references) { + if (!grouped[ref.uri]) { + grouped[ref.uri] = []; + } + grouped[ref.uri].push(ref); + } + return grouped; +} + +export async function buildFlatList(references, symbolName) { + const grouped = groupReferencesByFile(references); + + const items = []; + for (const [uri, fileRefs] of Object.entries(grouped)) { + fileRefs.sort((a, b) => a.range.start.line - b.range.start.line); + + items.push({ + type: "file-header", + uri, + fileName: getFilename(uri), + count: fileRefs.length, + }); + + for (const ref of fileRefs) { + const highlightedText = await highlightLine( + ref.lineText || "", + uri, + symbolName, + ); + + items.push({ + type: "reference", + uri, + ref, + line: ref.range.start.line + 1, + lineText: ref.lineText || "", + highlightedText, + symbol: symbolName, + }); + } + } + return items; +} + +export function createReferenceItem(item, options = {}) { + const { collapsedFiles, onToggleFile, onNavigate } = options; + + if (item.type === "file-header") { + const isCollapsed = collapsedFiles?.has(item.uri); + const iconClass = helpers.getIconForFile(item.fileName); + + const $el = ( +
    onToggleFile?.(item.uri)} + > + + + {sanitize(item.fileName)} + {item.count} +
    + ); + + return $el; + } + + const $el = ( +
    onNavigate?.(item.ref)}> + {item.line} + +
    + ); + + $el.get(".ref-preview").innerHTML = DOMPurify.sanitize(item.highlightedText); + + return $el; +} + +export async function navigateToReference(ref) { + Sidebar.hide(); + + try { + await openFile(ref.uri, { render: true }); + const { editor } = editorManager; + if (!editor) return; + + const doc = editor.state.doc; + const startLine = doc.line(ref.range.start.line + 1); + const endLine = doc.line(ref.range.end.line + 1); + const from = Math.min( + startLine.from + ref.range.start.character, + startLine.to, + ); + const to = Math.min(endLine.from + ref.range.end.character, endLine.to); + + editor.dispatch({ + selection: { anchor: from, head: to }, + effects: EditorView.scrollIntoView(from, { y: "center" }), + }); + editor.focus(); + } catch (error) { + console.error("Failed to navigate to reference:", error); + } +} + +export function getReferencesStats(references) { + const fileCount = new Set(references.map((r) => r.uri)).size; + const refCount = references.length; + return { + fileCount, + refCount, + text: `${refCount} reference${refCount !== 1 ? "s" : ""} in ${fileCount} file${fileCount !== 1 ? "s" : ""}`, + }; +} diff --git a/src/components/sidebar/index.js b/src/components/sidebar/index.js index a331697d4..0b606960f 100644 --- a/src/components/sidebar/index.js +++ b/src/components/sidebar/index.js @@ -259,7 +259,8 @@ function create($container, $toggler) { root.style.removeProperty("margin-left"); root.style.removeProperty("width"); $el.remove(); - editorManager.editor.resize(true); + // TODO : Codemirror + //editorManager.editor.resize(true); } } diff --git a/src/components/symbolsPanel/index.js b/src/components/symbolsPanel/index.js new file mode 100644 index 000000000..5265f09b3 --- /dev/null +++ b/src/components/symbolsPanel/index.js @@ -0,0 +1,476 @@ +import "./styles.scss"; +import { fetchDocumentSymbols, navigateToSymbol } from "cm/lsp"; +import actionStack from "lib/actionStack"; + +let currentPanel = null; + +const SYMBOL_KIND_ABBREV = { + 1: "Fi", + 2: "Mo", + 3: "Ns", + 4: "Pk", + 5: "C", + 6: "M", + 7: "P", + 8: "F", + 9: "Co", + 10: "E", + 11: "I", + 12: "fn", + 13: "V", + 14: "c", + 15: "S", + 16: "#", + 17: "B", + 18: "[]", + 19: "{}", + 20: "K", + 21: "∅", + 22: "Em", + 23: "St", + 24: "Ev", + 25: "Op", + 26: "T", +}; + +function sanitize(str) { + if (!str) return ""; + return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function flattenSymbolsForDisplay(symbols, depth = 0) { + const result = []; + for (const sym of symbols) { + result.push({ + ...sym, + depth, + id: `${sym.selectionRange.startLine}-${sym.selectionRange.startCharacter}-${sym.name}`, + }); + if (sym.children && sym.children.length > 0) { + result.push(...flattenSymbolsForDisplay(sym.children, depth + 1)); + } + } + return result; +} + +function createSymbolsPanel() { + const state = { + visible: false, + expanded: false, + loading: true, + symbols: [], + flatSymbols: [], + filteredSymbols: [], + searchQuery: "", + editorView: null, + }; + + const $mask = ; + const $panel =
    ; + const $dragHandle =
    ; + const $title =
    ; + const $subtitle = ; + const $searchInput = ( + + ); + const $content =
    ; + const $symbolsList =
    ; + + const $closeBtn = ( + + ); + + const $header = ( +
    +
    + {$title} + {$subtitle} +
    +
    {$closeBtn}
    +
    + ); + + const $search =
    {$searchInput}
    ; + + $panel.append($dragHandle, $header, $search, $content); + $mask.onclick = hide; + + let startY = 0; + let currentY = 0; + let isDragging = false; + + $dragHandle.ontouchstart = onDragStart; + $dragHandle.onmousedown = onDragStart; + + function onDragStart(e) { + isDragging = true; + startY = e.touches ? e.touches[0].clientY : e.clientY; + currentY = startY; + $panel.style.transition = "none"; + + document.addEventListener("touchmove", onDragMove, { passive: false }); + document.addEventListener("mousemove", onDragMove); + document.addEventListener("touchend", onDragEnd); + document.addEventListener("mouseup", onDragEnd); + } + + function onDragMove(e) { + if (!isDragging) return; + e.preventDefault(); + currentY = e.touches ? e.touches[0].clientY : e.clientY; + const deltaY = currentY - startY; + + if (deltaY > 0) { + $panel.style.transform = `translateY(${deltaY}px)`; + } else if (!state.expanded) { + const expansion = Math.min(Math.abs(deltaY), 100); + $panel.style.maxHeight = `${60 + (expansion / 100) * 25}vh`; + } + } + + function onDragEnd() { + isDragging = false; + document.removeEventListener("touchmove", onDragMove); + document.removeEventListener("mousemove", onDragMove); + document.removeEventListener("touchend", onDragEnd); + document.removeEventListener("mouseup", onDragEnd); + + $panel.style.transition = ""; + const deltaY = currentY - startY; + + if (deltaY > 100) { + hide(); + } else if (deltaY < -50 && !state.expanded) { + state.expanded = true; + $panel.classList.add("expanded"); + $panel.style.transform = ""; + $panel.style.maxHeight = ""; + } else { + $panel.style.transform = ""; + $panel.style.maxHeight = ""; + } + } + + function setTitle(text) { + $title.innerHTML = ""; + $title.append( + , + {sanitize(text)}, + ); + } + + function setSubtitle(text) { + $subtitle.textContent = text; + } + + function onSearchInput(e) { + state.searchQuery = e.target.value.trim(); + filterSymbols(); + } + + function clearSearch() { + $searchInput.value = ""; + state.searchQuery = ""; + } + + function filterSymbols() { + const query = state.searchQuery.toLowerCase(); + + if (!query) { + state.filteredSymbols = state.flatSymbols; + } else { + state.filteredSymbols = state.flatSymbols.filter((sym) => { + const nameMatch = sym.name.toLowerCase().includes(query); + const kindMatch = sym.kindName.toLowerCase().includes(query); + const detailMatch = sym.detail?.toLowerCase().includes(query); + return nameMatch || kindMatch || detailMatch; + }); + } + + updateList(); + } + + function updateList() { + setSubtitle(getSubtitle()); + renderSymbolsList(); + } + + function getSubtitle() { + const total = state.flatSymbols.length; + const filtered = state.filteredSymbols.length; + + if (total === 0) return "No symbols"; + if (filtered === total) return `${total} symbol${total !== 1 ? "s" : ""}`; + return `${filtered} of ${total} symbols`; + } + + function renderLoading() { + $content.innerHTML = ""; + $content.append( +
    +
    + Loading symbols... +
    , + ); + } + + function renderEmpty() { + const message = state.searchQuery + ? "No matching symbols" + : "No symbols found"; + $content.innerHTML = ""; + $content.append( +
    + + {message} +
    , + ); + } + + function renderNotSupported() { + $content.innerHTML = ""; + $content.append( +
    + + Language server does not support document symbols +
    , + ); + } + + function highlightMatch(text, query) { + if (!query) return sanitize(text); + + const lowerText = text.toLowerCase(); + const lowerQuery = query.toLowerCase(); + const index = lowerText.indexOf(lowerQuery); + + if (index === -1) return sanitize(text); + + const before = sanitize(text.slice(0, index)); + const match = sanitize(text.slice(index, index + query.length)); + const after = sanitize(text.slice(index + query.length)); + + return `${before}${match}${after}`; + } + + function createSymbolItem(symbol) { + const kindName = symbol.kindName || "Unknown"; + const kindClass = `kind-${kindName.toLowerCase().replace(/\s+/g, "")}`; + const abbrev = SYMBOL_KIND_ABBREV[symbol.kind] || "?"; + const indent = (symbol.depth || 0) * 16; + const startLine = symbol.selectionRange?.startLine ?? 0; + + const $item = ( +
    onSymbolClick(symbol)}> + + {abbrev} + + + {symbol.detail && ( + {sanitize(symbol.detail)} + )} + + :{startLine + 1} +
    + ); + + $item.get(".symbol-name").innerHTML = highlightMatch( + symbol.name, + state.searchQuery, + ); + + return $item; + } + + function renderSymbolsList() { + $symbolsList.innerHTML = ""; + + if (state.filteredSymbols.length === 0) { + renderEmpty(); + return; + } + + $content.innerHTML = ""; + const fragment = document.createDocumentFragment(); + + for (const symbol of state.filteredSymbols) { + fragment.appendChild(createSymbolItem(symbol)); + } + + $symbolsList.appendChild(fragment); + $content.appendChild($symbolsList); + } + + function onSymbolClick(symbol) { + if (!state.editorView) return; + hide(); + navigateToSymbol(state.editorView, symbol); + } + + async function loadSymbols() { + if (!state.editorView) { + renderNotSupported(); + return; + } + + renderLoading(); + + try { + const symbols = await fetchDocumentSymbols(state.editorView); + + if (symbols === null) { + state.loading = false; + setSubtitle("Not supported"); + renderNotSupported(); + return; + } + + state.loading = false; + state.symbols = symbols; + state.flatSymbols = flattenSymbolsForDisplay(symbols); + state.filteredSymbols = state.flatSymbols; + + if (state.flatSymbols.length === 0) { + setSubtitle("No symbols"); + renderEmpty(); + } else { + setSubtitle(getSubtitle()); + renderSymbolsList(); + } + } catch (error) { + console.error("Failed to load symbols:", error); + state.loading = false; + setSubtitle("Error"); + $content.innerHTML = ""; + $content.append( +
    + + {sanitize(error.message || "Failed to load symbols")} +
    , + ); + } + } + + function show(options = {}) { + if (currentPanel && currentPanel !== panelInstance) { + currentPanel.hide(); + } + currentPanel = panelInstance; + + state.editorView = options.view || null; + state.symbols = []; + state.flatSymbols = []; + state.filteredSymbols = []; + state.searchQuery = ""; + state.loading = true; + state.expanded = false; + + clearSearch(); + setTitle("Document Outline"); + setSubtitle("Loading..."); + renderLoading(); + + document.body.append($mask, $panel); + + requestAnimationFrame(() => { + $mask.classList.add("visible"); + $panel.classList.add("visible"); + $panel.classList.remove("expanded"); + }); + + state.visible = true; + + actionStack.push({ + id: "symbols-panel", + action: hide, + }); + + loadSymbols(); + } + + function hide() { + if (!state.visible) return; + state.visible = false; + + $mask.classList.remove("visible"); + $panel.classList.remove("visible"); + + actionStack.remove("symbols-panel"); + + setTimeout(() => { + $mask.remove(); + $panel.remove(); + }, 250); + + if (currentPanel === panelInstance) { + currentPanel = null; + } + + if (state.editorView) { + state.editorView.focus(); + } + } + + const panelInstance = { + show, + hide, + get visible() { + return state.visible; + }, + }; + + return panelInstance; +} + +let panelSingleton = null; + +function getPanel() { + if (!panelSingleton) { + panelSingleton = createSymbolsPanel(); + } + return panelSingleton; +} + +export function showSymbolsPanel(options) { + const panel = getPanel(); + panel.show(options); + return panel; +} + +export function hideSymbolsPanel() { + const panel = getPanel(); + panel.hide(); +} + +export async function showDocumentSymbols(view) { + if (!view) { + const em = globalThis.editorManager; + view = em?.editor; + } + + if (!view) { + const toast = globalThis.toast; + toast?.("No editor available"); + return false; + } + + showSymbolsPanel({ view }); + return true; +} + +export default { + show: showSymbolsPanel, + hide: hideSymbolsPanel, + showDocumentSymbols, + getPanel, +}; diff --git a/src/components/symbolsPanel/styles.scss b/src/components/symbolsPanel/styles.scss new file mode 100644 index 000000000..e08b42c7d --- /dev/null +++ b/src/components/symbolsPanel/styles.scss @@ -0,0 +1,409 @@ +@use "../../styles/mixins.scss"; + +.symbols-panel-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.4); + z-index: 100; + opacity: 0; + transition: opacity 200ms ease-out; + pointer-events: none; + + &.visible { + opacity: 1; + pointer-events: auto; + } +} + +.symbols-panel { + position: fixed; + left: 0; + right: 0; + bottom: 0; + z-index: 101; + background-color: var(--popup-background-color); + border-top-left-radius: 12px; + border-top-right-radius: 12px; + box-shadow: 0 -4px 20px var(--box-shadow-color); + transform: translateY(100%); + transition: transform 250ms ease-out, max-height 200ms ease-out; + display: flex; + flex-direction: column; + max-height: 60vh; + overflow: hidden; + + &.visible { + transform: translateY(0); + } + + &.expanded { + max-height: 85vh; + } + + .drag-handle { + display: flex; + justify-content: center; + align-items: center; + padding: 8px 0 4px 0; + cursor: grab; + flex-shrink: 0; + + &::after { + content: ""; + width: 36px; + height: 4px; + background-color: var(--border-color); + border-radius: 2px; + } + + &:active { + cursor: grabbing; + } + } + + .panel-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 12px 12px 16px; + border-bottom: 1px solid var(--border-color); + min-height: 44px; + flex-shrink: 0; + + .header-content { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; + min-width: 0; + + .header-title { + display: flex; + align-items: center; + gap: 8px; + font-size: 1rem; + font-weight: 600; + color: var(--primary-text-color); + + .icon { + font-size: 1.1em; + opacity: 0.7; + } + } + + .header-subtitle { + font-size: 0.85rem; + color: var(--secondary-text-color); + opacity: 0.8; + } + } + + .header-actions { + display: flex; + gap: 4px; + flex-shrink: 0; + } + + .action-btn { + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + border: none; + background: transparent; + color: var(--secondary-text-color); + border-radius: 50%; + cursor: pointer; + + &:active { + background-color: var(--active-icon-color); + } + + .icon { + font-size: 1.2em; + } + } + } + + .panel-search { + padding: 8px 16px; + border-bottom: 1px solid var(--border-color); + flex-shrink: 0; + + input { + width: 100%; + background-color: var(--secondary-color); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 10px 12px; + font-size: 0.9rem; + color: var(--primary-text-color); + outline: none; + + &::placeholder { + color: var(--secondary-text-color); + opacity: 0.7; + } + + &:focus { + border-color: var(--active-color); + } + } + } + + .panel-content { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; + overscroll-behavior: contain; + + &::-webkit-scrollbar { + width: var(--scrollbar-width, 4px); + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--scrollbar-color, rgba(0, 0, 0, 0.333)); + border-radius: calc(var(--scrollbar-width, 4px) / 2); + } + } + + .loading-state { + display: flex; + align-items: center; + justify-content: center; + padding: 32px 16px; + color: var(--secondary-text-color); + gap: 12px; + + .loader { + @include mixins.circular-loader(24px); + } + } + + .empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 32px 16px; + color: var(--secondary-text-color); + text-align: center; + + .icon { + font-size: 2rem; + margin-bottom: 8px; + opacity: 0.5; + } + } +} + +.symbol-item { + box-sizing: border-box; + display: flex; + align-items: center; + gap: 10px; + padding: 0 16px; + height: 44px; + cursor: pointer; + user-select: none; + will-change: transform; + + &:active { + background-color: var(--active-icon-color); + } + + .symbol-indent { + flex-shrink: 0; + } + + .symbol-icon { + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + flex-shrink: 0; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; + + &.kind-file { + background-color: rgba(158, 158, 158, 0.2); + color: #9e9e9e; + } + + &.kind-module { + background-color: rgba(255, 152, 0, 0.2); + color: #ff9800; + } + + &.kind-namespace { + background-color: rgba(255, 152, 0, 0.2); + color: #ff9800; + } + + &.kind-package { + background-color: rgba(121, 85, 72, 0.2); + color: #795548; + } + + &.kind-class { + background-color: rgba(255, 193, 7, 0.2); + color: #ffc107; + } + + &.kind-method { + background-color: rgba(156, 39, 176, 0.2); + color: #9c27b0; + } + + &.kind-property { + background-color: rgba(0, 150, 136, 0.2); + color: #009688; + } + + &.kind-field { + background-color: rgba(0, 150, 136, 0.2); + color: #009688; + } + + &.kind-constructor { + background-color: rgba(156, 39, 176, 0.2); + color: #9c27b0; + } + + &.kind-enum { + background-color: rgba(255, 152, 0, 0.2); + color: #ff9800; + } + + &.kind-interface { + background-color: rgba(0, 188, 212, 0.2); + color: #00bcd4; + } + + &.kind-function { + background-color: rgba(103, 58, 183, 0.2); + color: #673ab7; + } + + &.kind-variable { + background-color: rgba(33, 150, 243, 0.2); + color: #2196f3; + } + + &.kind-constant { + background-color: rgba(33, 150, 243, 0.2); + color: #2196f3; + } + + &.kind-string { + background-color: rgba(76, 175, 80, 0.2); + color: #4caf50; + } + + &.kind-number { + background-color: rgba(139, 195, 74, 0.2); + color: #8bc34a; + } + + &.kind-boolean { + background-color: rgba(33, 150, 243, 0.2); + color: #2196f3; + } + + &.kind-array { + background-color: rgba(255, 87, 34, 0.2); + color: #ff5722; + } + + &.kind-object { + background-color: rgba(96, 125, 139, 0.2); + color: #607d8b; + } + + &.kind-key { + background-color: rgba(233, 30, 99, 0.2); + color: #e91e63; + } + + &.kind-null { + background-color: rgba(158, 158, 158, 0.2); + color: #9e9e9e; + } + + &.kind-enummember { + background-color: rgba(255, 152, 0, 0.2); + color: #ff9800; + } + + &.kind-struct { + background-color: rgba(96, 125, 139, 0.2); + color: #607d8b; + } + + &.kind-event { + background-color: rgba(255, 235, 59, 0.2); + color: #fdd835; + } + + &.kind-operator { + background-color: rgba(158, 158, 158, 0.2); + color: #9e9e9e; + } + + &.kind-typeparameter { + background-color: rgba(0, 188, 212, 0.2); + color: #00bcd4; + } + } + + .symbol-info { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + + .symbol-name { + font-size: 0.9rem; + font-weight: 500; + color: var(--primary-text-color); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + .symbol-match { + background-color: color-mix(in srgb, var(--active-color) 30%, transparent); + border-radius: 2px; + padding: 0 2px; + } + } + + .symbol-detail { + font-size: 0.75rem; + color: var(--secondary-text-color); + opacity: 0.8; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .symbol-line { + font-size: 0.75rem; + color: var(--secondary-text-color); + font-family: monospace; + flex-shrink: 0; + opacity: 0.7; + } +} \ No newline at end of file diff --git a/src/dialogs/prompt.js b/src/dialogs/prompt.js index 9c24a6288..4a0c988fa 100644 --- a/src/dialogs/prompt.js +++ b/src/dialogs/prompt.js @@ -27,12 +27,11 @@ export default function prompt( type = "text", options = {}, ) { - const commands = editorManager.editor.commands; - const originalExec = commands.exec; + // CodeMirror doesn't use commands.exec like ACE, so we store a reference to the editor + // to potentially disable keymaps if needed in the future + const editor = editorManager.editor; const { capitalize = true } = options; - commands.exec = () => {}; // Disable all shortcuts - return new Promise((resolve) => { const inputType = type === "textarea" ? "textarea" : "input"; type = type === "filename" ? "text" : type; @@ -161,7 +160,7 @@ export default function prompt( } function hide() { - commands.exec = originalExec; + // CodeMirror keymaps are handled differently - no need to restore commands.exec actionStack.remove("prompt"); system.setInputType(appSettings.value.keyboardMode); hidePrompt(); diff --git a/src/handlers/editorFileTab.js b/src/handlers/editorFileTab.js index 2e199cba2..9fdc2b420 100644 --- a/src/handlers/editorFileTab.js +++ b/src/handlers/editorFileTab.js @@ -208,14 +208,15 @@ function releaseDrag(e) { } else if ( $target.tagName === "INPUT" || $target.tagName === "TEXTAREA" || - $target.classList.contains("ace_text-input") || - $target.closest(".ace_editor") + $target.isContentEditable || + $target.closest(".cm-editor") ) { - // If released on an input area or ace editor + // If released on an input area or CodeMirror editor const filePath = editorManager.activeFile.uri; if (filePath) { - if ($target.closest(".ace_editor")) { - editorManager.editor.insert(filePath); + if ($target.closest(".cm-editor")) { + const view = editorManager.editor; + view.dispatch(view.state.replaceSelection(filePath)); } else { $target.value += filePath; } diff --git a/src/handlers/keyboard.js b/src/handlers/keyboard.js index 62567f8fe..7e5b21608 100644 --- a/src/handlers/keyboard.js +++ b/src/handlers/keyboard.js @@ -64,6 +64,13 @@ export default function keyboardHandler(e) { if (!ctrlKey && !shiftKey && !altKey && !metaKey) return; if (["Control", "Alt", "Meta", "Shift"].includes(key)) return; + const target = editorManager?.editor?.contentDOM; + if (!target) return; + + // Physical keyboard events already reaching CodeMirror should not be + // re-dispatched from the document listener. + if ($target === target || (target.contains?.($target) ?? false)) return; + const event = KeyboardEvent("keydown", { key, ctrlKey, @@ -71,8 +78,7 @@ export default function keyboardHandler(e) { altKey, metaKey, }); - const editor = editorManager.editor.textInput.getElement(); - editor.dispatchEvent(event); + target?.dispatchEvent?.(event); } document.addEventListener("admob.banner.size", async (event) => { diff --git a/src/handlers/quickTools.js b/src/handlers/quickTools.js index 534a6ce41..a0341f76f 100644 --- a/src/handlers/quickTools.js +++ b/src/handlers/quickTools.js @@ -1,3 +1,13 @@ +import { + findNext as cmFindNext, + findPrevious as cmFindPrevious, + replaceAll as cmReplaceAll, + replaceNext as cmReplaceNext, + getSearchQuery, + SearchQuery, + setSearchQuery, +} from "@codemirror/search"; +import { executeCommand } from "cm/commandRegistry"; import quickTools from "components/quickTools"; import actionStack from "lib/actionStack"; import searchHistory from "lib/searchHistory"; @@ -22,6 +32,88 @@ const events = { meta: [], }; +function getRefValue(ref) { + if (!ref) return ""; + const direct = ref.value; + if (typeof direct === "string") return direct; + if (typeof direct === "number") return String(direct); + if (ref.el) { + const elValue = ref.el.value; + if (typeof elValue === "string") return elValue; + if (typeof elValue === "number") return String(elValue); + } + return ""; +} + +function setRefValue(ref, value) { + if (!ref) return; + const normalized = typeof value === "string" ? value : String(value ?? ""); + if (ref.el) ref.el.value = normalized; + ref.value = normalized; +} + +function applySearchQuery(editor, searchValue, replaceValue) { + if (!editor) return null; + const options = appSettings?.value?.search ?? {}; + const queryConfig = { + search: String(searchValue ?? ""), + caseSensitive: !!options.caseSensitive, + regexp: !!options.regExp, + wholeWord: !!options.wholeWord, + }; + if (replaceValue !== undefined) { + queryConfig.replace = String(replaceValue ?? ""); + } + const query = new SearchQuery(queryConfig); + editor.dispatch({ effects: setSearchQuery.of(query) }); + return query; +} + +function clearSearchQuery(editor) { + if (!editor) return; + editor.dispatch({ + effects: setSearchQuery.of(new SearchQuery({ search: "" })), + }); +} + +function getSelectedText(editor) { + if (!editor) return ""; + if (typeof editor.getSelectedText === "function") { + try { + return editor.getSelectedText() ?? ""; + } catch (_) { + // fall back to CodeMirror state + } + } + try { + const { state } = editor; + if (!state) return ""; + const { from, to } = state.selection.main ?? {}; + if (typeof from !== "number" || typeof to !== "number") return ""; + if (from === to) return ""; + return state.sliceDoc(from, to); + } catch (_) { + return ""; + } +} + +function selectionMatchesQuery(editor, query) { + try { + if (!editor || !query || !query.valid || !query.search) return false; + const range = editor.state?.selection?.main; + if (!range || range.from === range.to) return false; + const cursor = query.getCursor(editor.state.doc, range.from, range.to); + cursor.next(); + return ( + !cursor.done && + cursor.value.from === range.from && + cursor.value.to === range.to + ); + } catch (_) { + return false; + } +} + /** * @typedef { 'shift' | 'alt' | 'ctrl' | 'meta' } QuickToolsEvent * @typedef {(value: boolean)=>void} QuickToolsEventListener @@ -40,7 +132,7 @@ quickTools.$input.addEventListener("input", (e) => { } const event = KeyboardEvent("keydown", keyCombination); - input = input || editorManager.editor.textInput.getElement(); + input = input || editorManager.editor.contentDOM; resetKeys(); input.dispatchEvent(event); @@ -62,8 +154,8 @@ quickTools.$input.addEventListener("keydown", (e) => { if (input && input !== quickTools.$input) { input.dispatchEvent(event); } else { - // Otherwise fallback to editor input - editorManager.editor.textInput.getElement().dispatchEvent(event); + // Otherwise fallback to editor view content + editorManager.editor.contentDOM.dispatchEvent(event); } }); @@ -96,7 +188,7 @@ function setupHistoryNavigation() { const newValue = searchHistory.navigateSearchUp($searchInput.el.value); $searchInput.el.value = newValue; // Trigger search - if (newValue) find(0, false); + find(0, false); } else if (e.key === "ArrowDown") { e.preventDefault(); const newValue = searchHistory.navigateSearchDown( @@ -104,7 +196,7 @@ function setupHistoryNavigation() { ); $searchInput.el.value = newValue; // Trigger search - if (newValue) find(0, false); + find(0, false); } else if (e.key === "Enter" || e.key === "Escape") { // Reset navigation on enter or escape searchHistory.resetSearchNavigation(); @@ -207,9 +299,12 @@ export default function actions(action, value) { editor.insert(value); return true; - case "command": - editor.execCommand(value); - return true; + case "command": { + const commandName = + typeof value === "string" ? value : String(value ?? ""); + if (!commandName) return false; + return executeCommand(commandName, editor); + } case "key": { value = Number.parseInt(value, 10); @@ -260,14 +355,36 @@ export default function actions(action, value) { if ($replaceInput.value) { searchHistory.addToHistory($replaceInput.value); } - editor.replace($replaceInput.value || ""); + if (editor) { + const replaceValue = getRefValue($replaceInput); + const query = applySearchQuery( + editor, + getRefValue(quickTools.$searchInput), + replaceValue, + ); + if (query && query.search && query.valid) { + cmReplaceNext(editor); + } + updateSearchState(); + } return true; case "search-replace-all": if ($replaceInput.value) { searchHistory.addToHistory($replaceInput.value); } - editor.replaceAll($replaceInput.value || ""); + if (editor) { + const replaceValue = getRefValue($replaceInput); + const query = applySearchQuery( + editor, + getRefValue(quickTools.$searchInput), + replaceValue, + ); + if (query && query.search && query.valid) { + cmReplaceAll(editor); + } + } + updateSearchState(); return true; default: @@ -293,7 +410,7 @@ function toggleSearch() { const $searchInput = quickTools.$searchInput.el; const $toggler = quickTools.$toggler; const { editor } = editorManager; - const selectedText = editor.getSelectedText(); + const selectedText = getSelectedText(editor); if (!$footer.contains($searchRow1)) { const { className } = quickTools.$toggler; @@ -302,16 +419,18 @@ function toggleSearch() { $toggler.className = "floating icon clearclose"; $footer.content = [$searchRow1, $searchRow2]; - $searchInput.value = selectedText || ""; + setRefValue($searchInput, selectedText || ""); - $searchInput.oninput = function (e) { - if (this.value) find(0, false); + $searchInput.oninput = function () { + find(0, false); }; $searchInput.onsearch = function () { if (this.value) { searchHistory.addToHistory(this.value); find(1, false); + } else { + find(0, false); } }; @@ -331,9 +450,9 @@ function toggleSearch() { }, }); } else { - const inputValue = $searchInput?.value || ""; + const inputValue = getRefValue($searchInput); if (inputValue !== selectedText) { - $searchInput.value = selectedText; + setRefValue($searchInput, selectedText || ""); find(0, false); return; } @@ -342,7 +461,6 @@ function toggleSearch() { } $searchInput.focus(); - editor.resize(true); } function toggle() { @@ -381,7 +499,6 @@ function setHeight(height = 1, save = true) { if (save) { appSettings.update({ quickTools: height }, false); } - editor.resize(true); if (!height) { $row1.remove(); @@ -425,7 +542,7 @@ function removeSearch() { // Reset history navigation when search is closed searchHistory.resetAllNavigation(); - const { activeFile } = editorManager; + const { activeFile, editor } = editorManager; // Check if current tab is a terminal if ( @@ -437,6 +554,7 @@ function removeSearch() { activeFile.terminalComponent.searchAddon?.clearActiveDecoration(); return; } + clearSearchQuery(editor); focusEditor(); } @@ -457,12 +575,24 @@ function find(skip, backward) { ) { activeFile.terminalComponent.search($searchInput.value, skip, backward); } else { - // Use ACE editor search for regular files - editorManager.editor.find($searchInput.value, { - skipCurrent: skip, - ...appSettings.value.search, - backwards: backward, - }); + const editor = editorManager.editor; + const searchValue = getRefValue($searchInput); + const query = applySearchQuery(editor, searchValue); + if (!query || !query.search || !query.valid) { + updateSearchState(); + return; + } + + const normalizedSkip = Number(skip) || 0; + if (normalizedSkip === 0 && selectionMatchesQuery(editor, query)) { + updateSearchState(); + return; + } + const steps = Math.max(1, normalizedSkip); + const runCommand = backward ? cmFindPrevious : cmFindNext; + for (let i = 0; i < steps; ++i) { + if (!runCommand(editor)) break; + } } updateSearchState(); @@ -470,7 +600,7 @@ function find(skip, backward) { function updateSearchState() { const MAX_COUNT = 999; - const { activeFile } = editorManager; + const { activeFile, editor } = editorManager; const { $searchPos, $searchTotal } = quickTools; // Check if current tab is a terminal @@ -482,30 +612,31 @@ function updateSearchState() { $searchPos.textContent = "?"; return; } + const query = editor ? getSearchQuery(editor.state) : null; + if (!query || !query.search || !query.valid) { + $searchTotal.textContent = "0"; + $searchPos.textContent = "0"; + return; + } - // Use ACE editor search state for regular files - const { editor } = editorManager; - let regex = editor.$search.$options.re; - let all = 0; + const cursor = query.getCursor(editor.state.doc); + let total = 0; let before = 0; - if (regex) { - const value = editor.getValue(); - const offset = editor.session.doc.positionToIndex(editor.selection.anchor); - let last = (regex.lastIndex = 0); - let m; - while ((m = regex.exec(value))) { - all++; - last = m.index; - if (last <= offset) before++; - if (all > MAX_COUNT) break; - if (!m[0]) { - regex.lastIndex = last += 1; - if (last >= value.length) break; - } + let limited = false; + const cursorPos = editor.state.selection.main.head; + for (cursor.next(); !cursor.done; cursor.next()) { + total++; + if (cursorPos >= cursor.value.from) { + before = Math.min(total, MAX_COUNT); + } + if (total === MAX_COUNT) { + cursor.next(); + limited = !cursor.done; + break; } } - $searchTotal.textContent = all > MAX_COUNT ? "999+" : all; - $searchPos.textContent = before; + $searchTotal.textContent = limited ? "999+" : String(total); + $searchPos.textContent = String(before); } /** diff --git a/src/handlers/quickToolsInit.js b/src/handlers/quickToolsInit.js index b07b7232c..5c803b7ee 100644 --- a/src/handlers/quickToolsInit.js +++ b/src/handlers/quickToolsInit.js @@ -81,12 +81,6 @@ export default function init() { $footer.removeAttribute("data-unsaved"); }); - editorManager.editor.on("focus", () => { - if (key.shift || key.ctrl || key.alt || key.meta) { - quickTools.$input.focus(); - } - }); - root.append($footer, $toggler); document.body.append($input); if ( diff --git a/src/index.d.ts b/src/index.d.ts index fef316150..db7d7fbf6 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -32,3 +32,68 @@ interface String { */ hash(): string; } + +type ExecutorCallback = ( + type: "stdout" | "stderr" | "exit", + data: string, +) => void; + +interface Executor { + execute: (command: string, alpine: boolean) => Promise; + start: ( + command: string, + callback: ExecutorCallback, + alpine: boolean, + ) => Promise; + write: (uuid: string, input: string) => Promise; + stop: (uuid: string) => Promise; + isRunning: (uuid: string) => Promise; + /** Move the executor service to the foreground (shows notification) */ + moveToForeground: () => Promise; + /** Move the executor service to the background (hides notification) */ + moveToBackground: () => Promise; + /** Stop the executor service completely */ + stopService: () => Promise; + /** + * Background executor + */ + BackgroundExecutor: Executor; +} + +declare const Executor: Executor | undefined; + +interface Window { + Executor?: Executor; + editorManager?: EditorManager; +} + +interface EditorManager { + editor?: import("@codemirror/view").EditorView; + activeFile?: AcodeFile; + getLspMetadata?: (file: AcodeFile) => LspFileMetadata | null; +} + +interface LspFileMetadata { + uri: string; + languageId?: string; + languageName?: string; + view?: import("@codemirror/view").EditorView; + file?: AcodeFile; + rootUri?: string; +} + +/** + * Acode file object + */ +interface AcodeFile { + uri?: string; + name?: string; + session?: unknown; + cacheFile?: string; + [key: string]: unknown; +} + +// Extend globalThis with Executor +declare global { + var Executor: Executor | undefined; +} diff --git a/src/lib/acode.js b/src/lib/acode.js index b324a85d3..c6fb6b18d 100644 --- a/src/lib/acode.js +++ b/src/lib/acode.js @@ -1,7 +1,21 @@ import fsOperation from "fileSystem"; import sidebarApps from "sidebarApps"; +import { HighlightStyle, syntaxHighlighting } from "@codemirror/language"; +import { EditorView } from "@codemirror/view"; import ajax from "@deadlyjack/ajax"; -import { addMode, removeMode } from "ace/modelist"; +import { tags } from "@lezer/highlight"; +import { + getRegisteredCommands as listRegisteredCommands, + refreshCommandKeymap, + registerExternalCommand, + removeExternalCommand, + executeCommand as runCommand, +} from "cm/commandRegistry"; +import lspClientManager from "cm/lsp/clientManager"; +import { registerLspFormatter } from "cm/lsp/formatter"; +import serverRegistry from "cm/lsp/serverRegistry"; +import { addMode, getModeForPath, removeMode } from "cm/modelist"; +import cmThemeRegistry from "cm/themes"; import Contextmenu from "components/contextmenu"; import inputhints from "components/inputhints"; import Page from "components/page"; @@ -51,26 +65,12 @@ import KeyboardEvent from "utils/keyboardEvent"; import Url from "utils/Url"; import constants from "./constants"; -const { Fold } = ace.require("ace/edit_session/fold"); -const { Range } = ace.require("ace/range"); - export default class Acode { #modules = {}; #pluginsInit = {}; #pluginUnmount = {}; - #formatter = [ - { - id: "default", - name: "Default", - exts: ["*"], - format: async () => { - const { beautify } = ace.require("ace/ext/beautify"); - const cursorPos = editorManager.editor.getCursorPosition(); - beautify(editorManager.editor.session); - editorManager.editor.gotoLine(cursorPos.row + 1, cursorPos.column); - }, - }, - ]; + // Registered formatter implementations (populated by plugins) + #formatter = []; #pluginWatchers = {}; /** @@ -105,17 +105,149 @@ export default class Acode { apply: () => {}, }; + // CodeMirror editor theme API for plugins + const normalizeThemeSpec = (spec) => { + if (!spec || typeof spec !== "object" || Array.isArray(spec)) { + console.warn( + "[editorThemes] register(spec) expects an object: { id, caption?, dark?, getExtension|extensions|extension|theme, config? }", + ); + return null; + } + + const id = spec.id || spec.name; + if (!id) { + console.warn("[editorThemes] register(spec) requires a valid `id`."); + return null; + } + + const extensionSource = + spec.getExtension || spec.extensions || spec.extension || spec.theme; + if (extensionSource === undefined || extensionSource === null) { + console.warn( + `[editorThemes] register('${id}') requires extensions via getExtension/extensions/extension/theme.`, + ); + return null; + } + + return { + id, + caption: spec.caption || spec.label || id, + isDark: spec.isDark ?? spec.dark ?? false, + getExtension: + typeof extensionSource === "function" + ? extensionSource + : () => extensionSource, + config: spec.config ?? null, + }; + }; + + const createHighlightStyle = (spec) => { + if (!spec) return null; + if (Array.isArray(spec)) return HighlightStyle.define(spec); + return spec; + }; + + const createTheme = ({ + styles, + dark = false, + highlightStyle, + extensions = [], + } = {}) => { + const ext = []; + + if (styles && typeof styles === "object") { + ext.push(EditorView.theme(styles, { dark: !!dark })); + } + + const resolvedHighlight = createHighlightStyle(highlightStyle); + if (resolvedHighlight) { + ext.push(syntaxHighlighting(resolvedHighlight)); + } + + if (Array.isArray(extensions)) { + ext.push(...extensions); + } else if (extensions) { + ext.push(extensions); + } + + return ext; + }; + + const editorThemesModule = { + /** + * Register a CodeMirror theme from plugin code. + * @param {{ + * id: string, + * caption?: string, + * dark?: boolean, + * getExtension?: Function, + * extensions?: unknown, + * config?: object + * }} spec + * `isDark`, `extension`, and `theme` are accepted aliases for compatibility. + * @returns {boolean} + */ + register: (spec) => { + const resolved = normalizeThemeSpec(spec); + if (!resolved) return false; + return cmThemeRegistry.addTheme( + resolved.id, + resolved.caption, + resolved.isDark, + resolved.getExtension, + resolved.config, + ); + }, + unregister: (id) => cmThemeRegistry.removeTheme(id), + list: () => cmThemeRegistry.getThemes(), + apply: (id) => editorManager?.editor?.setTheme?.(id), + get: (id) => cmThemeRegistry.getThemeById(id), + getConfig: (id) => cmThemeRegistry.getThemeConfig(id), + createTheme, + createHighlightStyle, + cm: { + EditorView, + HighlightStyle, + syntaxHighlighting, + tags, + }, + }; + const sidebarAppsModule = { add: sidebarApps.add, get: sidebarApps.get, remove: sidebarApps.remove, }; + const lspModule = { + registerServer: (definition, options) => + serverRegistry.registerServer(definition, options), + unregisterServer: (id) => serverRegistry.unregisterServer(id), + updateServer: (id, updater) => serverRegistry.updateServer(id, updater), + getServer: (id) => serverRegistry.getServer(id), + listServers: () => serverRegistry.listServers(), + getServersForLanguage: (languageId, options) => + serverRegistry.getServersForLanguage(languageId, options), + clientManager: { + setOptions: (options) => lspClientManager.setOptions(options), + getActiveClients: () => lspClientManager.getActiveClients(), + }, + }; + const aceModes = { addMode, removeMode, }; + // Preferred CodeMirror language registration API for plugins + const editorLanguages = { + // name: string, extensions: string|Array, caption?: string, + // loader?: () => Extension | Promise + register: (name, extensions, caption, loader) => + addMode(name, extensions, caption, loader), + unregister: (name) => removeMode(name), + }; + const intent = { addHandler: addIntentHandler, removeHandler: removeIntentHandler, @@ -163,6 +295,9 @@ export default class Acode { this.define("tutorial", tutorial); this.define("aceModes", aceModes); this.define("themes", themesModule); + this.define("editorLanguages", editorLanguages); + this.define("editorThemes", editorThemesModule); + this.define("lsp", lspModule); this.define("settings", appSettings); this.define("sideButton", SideButton); this.define("EditorFile", EditorFile); @@ -184,6 +319,9 @@ export default class Acode { this.define("terminal", terminalModule); this.define("createKeyboardEvent", KeyboardEvent); this.define("toInternalUrl", helpers.toInternalUri); + this.define("commands", this.#createCommandApi()); + + registerLspFormatter(this); } /** @@ -504,10 +642,20 @@ export default class Acode { delete appSettings.uiSettings[`plugin-${id}`]; } - registerFormatter(id, extensions, format) { + registerFormatter(id, extensions, format, displayName) { + let exts; + if (Array.isArray(extensions)) { + exts = extensions.filter(Boolean); + if (!exts.length) exts = ["*"]; + } else if (typeof extensions === "string" && extensions) { + exts = [extensions]; + } else { + exts = ["*"]; + } this.#formatter.unshift({ id, - exts: extensions, + name: displayName, + exts: exts, format, }); } @@ -527,28 +675,42 @@ export default class Acode { async format(selectIfNull = true) { const file = editorManager.activeFile; - if (!file?.session) return; - - const name = (file.session.getMode().$id || "").split("/").pop(); - const formatterId = appSettings.value.formatter[name]; + if (!file || file.type !== "editor") return false; + + let resolvedMode = file.currentMode; + if (!resolvedMode) { + try { + resolvedMode = getModeForPath(file.filename)?.name; + } catch (_) { + resolvedMode = null; + } + } + const modeName = resolvedMode || "text"; + const formatterMap = appSettings.value.formatter || {}; + const formatterId = formatterMap[modeName]; const formatter = this.#formatter.find(({ id }) => id === formatterId); if (!formatter) { - if (!selectIfNull) { + if (formatterId) { + delete formatterMap[modeName]; + await appSettings.update(false); + } + + if (selectIfNull) { + formatterSettings(modeName); + this.#afterSelectFormatter(modeName); + } else { toast(strings["please select a formatter"]); - return; } - formatterSettings(name); - this.#afterSelectFormatter(name); - return; + return false; } - const foldsSnapshot = this.#captureFoldState(file.session); - try { await formatter.format(); - } finally { - this.#restoreFoldState(file.session, foldsSnapshot); + return true; + } catch (error) { + helpers.error(error); + return false; } } @@ -567,77 +729,6 @@ export default class Acode { return fsOperation(file); } - #captureFoldState(session) { - if (!session?.getAllFolds) return null; - return this.#serializeFolds(session.getAllFolds()); - } - - #restoreFoldState(session, folds) { - if (!session || !Array.isArray(folds) || !folds.length) return; - - try { - const foldObjects = this.#parseSerializableFolds(folds); - if (!foldObjects.length) return; - session.removeAllFolds?.(); - session.addFolds?.(foldObjects); - } catch (error) { - console.warn("Failed to restore folds after formatting:", error); - } - } - - #serializeFolds(folds) { - if (!Array.isArray(folds) || !folds.length) return null; - - return folds - .map((fold) => { - if (!fold?.range) return null; - const { start, end } = fold.range; - if (!start || !end) return null; - - return { - range: { - start: { row: start.row, column: start.column }, - end: { row: end.row, column: end.column }, - }, - placeholder: fold.placeholder, - ranges: this.#serializeFolds(fold.ranges || []), - }; - }) - .filter(Boolean); - } - - #parseSerializableFolds(folds) { - if (!Array.isArray(folds) || !folds.length) return []; - - return folds - .map((fold) => { - const { range, placeholder, ranges } = fold; - const { start, end } = range || {}; - if (!start || !end) return null; - - try { - const foldInstance = new Fold( - new Range(start.row, start.column, end.row, end.column), - placeholder, - ); - - if (Array.isArray(ranges) && ranges.length) { - const subFolds = this.#parseSerializableFolds(ranges); - if (subFolds.length) { - foldInstance.subFolds = subFolds; - foldInstance.ranges = subFolds; - } - } - - return foldInstance; - } catch (error) { - console.warn("Failed to parse fold:", error); - return null; - } - }) - .filter(Boolean); - } - newEditorFile(filename, options) { new EditorFile(filename, options); } @@ -786,4 +877,62 @@ export default class Acode { unregisterFileHandler(id) { fileTypeHandler.unregisterFileHandler(id); } + + addCommand(descriptor) { + const command = registerExternalCommand(descriptor); + this.#refreshCommandBindings(); + return command; + } + + removeCommand(name) { + if (!name) return; + removeExternalCommand(name); + this.#refreshCommandBindings(); + } + + execCommand(name, view, args) { + if (!name) return false; + const targetView = view || window.editorManager?.editor; + return runCommand(name, targetView, args); + } + + listCommands() { + return listRegisteredCommands(); + } + + #refreshCommandBindings() { + const view = window.editorManager?.editor; + if (view) refreshCommandKeymap(view); + } + + #createCommandApi() { + const commandRegistry = { + add: this.addCommand, + execute: this.execCommand, + remove: this.removeCommand, + list: this.listCommands, + }; + + const addCommand = (descriptor) => { + try { + return this.addCommand(descriptor); + } catch (error) { + console.error("Failed to add command", descriptor?.name); + throw error; + } + }; + + const removeCommand = (name) => { + if (!name) return; + this.removeCommand(name); + }; + + return { + addCommand, + removeCommand, + get registry() { + return commandRegistry; + }, + }; + } } diff --git a/src/lib/applySettings.js b/src/lib/applySettings.js index a70d85933..819ec962f 100644 --- a/src/lib/applySettings.js +++ b/src/lib/applySettings.js @@ -23,6 +23,8 @@ export default { }); system.setInputType(appSettings.value.keyboardMode); + // Keep native context menu enabled globally; editor manager scopes disabling to CodeMirror focus. + system.setNativeContextMenuDisabled(false); }, afterRender() { const { value: settings } = appSettings; diff --git a/src/lib/checkFiles.js b/src/lib/checkFiles.js index 3b369d481..e22dcafc6 100644 --- a/src/lib/checkFiles.js +++ b/src/lib/checkFiles.js @@ -20,6 +20,8 @@ export default async function checkFiles() { return; } const files = editorManager.files; + // @ts-check + /** @type {{ editor: import('@codemirror/view').EditorView }} */ const { editor } = editorManager; recursiveFileCheck([...files]); @@ -70,7 +72,7 @@ export default async function checkFiles() { } const text = await fs.readFile(file.encoding); - const loadedText = file.session.getValue(); + const loadedText = file.session.doc.toString(); if (text !== loadedText) { try { @@ -87,7 +89,6 @@ export default async function checkFiles() { file.markChanged = false; file.session.setValue(text); editor.gotoLine(cursorPos.row, cursorPos.column); - editor.renderer.scrollCursorIntoView(cursorPos, 0.5); } catch (error) { // ignore } diff --git a/src/lib/commands.js b/src/lib/commands.js index cad2b8d8c..86b30b23b 100644 --- a/src/lib/commands.js +++ b/src/lib/commands.js @@ -1,4 +1,5 @@ import fsOperation from "fileSystem"; +import { selectAll } from "@codemirror/commands"; import Sidebar from "components/sidebar"; import { TerminalManager } from "components/terminal"; import color from "dialogs/color"; @@ -143,12 +144,9 @@ export default { }); if (!res) return; - - const [line, col] = `${res}`.split("."); - const editor = editorManager.editor; - - editor.focus(); - editor.gotoLine(line, col, true); + const [lineStr, colStr] = String(res).split("."); + const { editor } = editorManager; + editor.gotoLine(lineStr, colStr); }, async "new-file"() { let filename = await prompt(strings["enter file name"], "", "filename", { @@ -201,19 +199,19 @@ export default { default: return; } - editorManager.editor.blur(); + editorManager.editor.contentDOM.blur(); }, "open-with"() { editorManager.activeFile.openWith(); }, "open-file"() { - editorManager.editor.blur(); + editorManager.editor.contentDOM.blur(); FileBrowser("file") .then(FileBrowser.openFile) .catch(FileBrowser.openFileError); }, "open-folder"() { - editorManager.editor.blur(); + editorManager.editor.contentDOM.blur(); FileBrowser("folder") .then(FileBrowser.openFolder) .catch(FileBrowser.openFolderError); @@ -251,7 +249,8 @@ export default { this.find(); }, "resize-editor"() { - editorManager.editor.resize(true); + // TODO : Codemirror + //editorManager.editor.resize(true); }, "open-inapp-browser"(url) { browser.open(url); @@ -315,9 +314,17 @@ export default { async "insert-color"() { const { editor } = editorManager; const range = getColorRange(); - let defaultColor = range ? editor.session.getTextRange(range) : ""; + let defaultColor = ""; - editor.blur(); + if (range) { + try { + defaultColor = editor.state.doc.sliceString(range.from, range.to); + } catch (_) { + defaultColor = ""; + } + } + + editor.contentDOM.blur(); const wasFocused = editorManager.activeFile.focused; const res = await color(defaultColor, () => { if (wasFocused) { @@ -326,7 +333,9 @@ export default { }); if (range) { - editor.session.replace(range, res); + editor.dispatch({ + changes: { from: range.from, to: range.to, insert: res }, + }); return; } editor.insert(res); @@ -342,8 +351,7 @@ export default { }, "select-all"() { const { editor } = editorManager; - editor.execCommand("selectall"); - editor.scrollToRow(Number.POSITIVE_INFINITY); + selectAll(editor); }, async rename(file) { file = file || editorManager.activeFile; @@ -395,8 +403,11 @@ export default { const { editor } = editorManager; const pos = editor.getCursorPosition(); - await acode.format(selectIfNull); - editor.selection.moveCursorToPosition(pos); + const didFormat = await acode.format(selectIfNull); + if (didFormat) { + // Restore cursor position after formatting (pos.row is now 1-based) + editor.gotoLine(pos.row, pos.column); + } }, async eol() { const eol = await select(strings["new line mode"], ["unix", "windows"], { @@ -495,4 +506,8 @@ Additional Info: const devTools = (await import("lib/devTools")).default; devTools.show(); }, + async "lsp-info"() { + const { showLspInfoDialog } = await import("components/lspInfoDialog"); + showLspInfoDialog(); + }, }; diff --git a/src/lib/editorFile.js b/src/lib/editorFile.js index bf44701dc..e5d8113bd 100644 --- a/src/lib/editorFile.js +++ b/src/lib/editorFile.js @@ -1,4 +1,13 @@ import fsOperation from "fileSystem"; +// CodeMirror imports for document state management +import { EditorState, Text } from "@codemirror/state"; +import { + clearSelection, + restoreFolds, + restoreSelection, + setScrollPosition, +} from "cm/editorUtils"; +import { getModeForPath } from "cm/modelist"; import Sidebar from "components/sidebar"; import tile from "components/tile"; import confirm from "dialogs/confirm"; @@ -16,8 +25,188 @@ import run from "./run"; import saveFile from "./saveFile"; import appSettings from "./settings"; -const { Fold } = ace.require("ace/edit_session/fold"); -const { Range } = ace.require("ace/range"); +/** + * Creates a Proxy around an EditorState that provides Ace-compatible methods. + * @param {EditorState} state - The raw CodeMirror EditorState + * @param {EditorFile} file - The parent EditorFile instance + * @returns {Proxy} Proxied state with Ace-compatible methods + */ +function createSessionProxy(state, file) { + if (!state) return null; + + /** + * Convert Ace position {row, column} to CodeMirror offset + */ + function positionToOffset(pos, doc) { + if (!pos || !doc) return 0; + try { + const lineNum = Math.max(1, Math.min((pos.row ?? 0) + 1, doc.lines)); + const line = doc.line(lineNum); + const col = Math.max(0, Math.min(pos.column ?? 0, line.length)); + return line.from + col; + } catch (_) { + return 0; + } + } + + /** + * Convert CodeMirror offset to Ace position {row, column} + */ + function offsetToPosition(offset, doc) { + if (!doc) return { row: 0, column: 0 }; + try { + const line = doc.lineAt(offset); + return { row: line.number - 1, column: offset - line.from }; + } catch (_) { + return { row: 0, column: 0 }; + } + } + + return new Proxy(state, { + get(target, prop) { + // Ace-compatible method: getValue() + if (prop === "getValue") { + return () => target.doc.toString(); + } + + // Ace-compatible method: setValue(text) + if (prop === "setValue") { + return (text) => { + const newText = String(text ?? ""); + const { activeFile, editor } = editorManager; + if (activeFile?.id === file.id && editor) { + // Active file: dispatch to live EditorView + editor.dispatch({ + changes: { + from: 0, + to: editor.state.doc.length, + insert: newText, + }, + }); + } else { + // Inactive file: update stored state + file._setRawSession( + target.update({ + changes: { from: 0, to: target.doc.length, insert: newText }, + }).state, + ); + } + }; + } + + // Ace-compatible method: getLine(row) + if (prop === "getLine") { + return (row) => { + try { + return target.doc.line(row + 1).text; + } catch (_) { + return ""; + } + }; + } + + // Ace-compatible method: getLength() + if (prop === "getLength") { + return () => target.doc.lines; + } + + // Ace-compatible method: getTextRange(range) + if (prop === "getTextRange") { + return (range) => { + if (!range) return ""; + try { + const from = positionToOffset(range.start, target.doc); + const to = positionToOffset(range.end, target.doc); + return target.doc.sliceString(from, to); + } catch (_) { + return ""; + } + }; + } + + // Ace-compatible method: insert(position, text) + if (prop === "insert") { + return (position, text) => { + const { activeFile, editor } = editorManager; + const offset = positionToOffset(position, target.doc); + if (activeFile?.id === file.id && editor) { + editor.dispatch({ + changes: { from: offset, insert: String(text ?? "") }, + }); + } else { + file._setRawSession( + target.update({ + changes: { from: offset, insert: String(text ?? "") }, + }).state, + ); + } + }; + } + + // Ace-compatible method: remove(range) + if (prop === "remove") { + return (range) => { + if (!range) return ""; + const from = positionToOffset(range.start, target.doc); + const to = positionToOffset(range.end, target.doc); + const removed = target.doc.sliceString(from, to); + const { activeFile, editor } = editorManager; + if (activeFile?.id === file.id && editor) { + editor.dispatch({ changes: { from, to, insert: "" } }); + } else { + file._setRawSession( + target.update({ changes: { from, to, insert: "" } }).state, + ); + } + return removed; + }; + } + + // Ace-compatible method: replace(range, text) + if (prop === "replace") { + return (range, text) => { + if (!range) return; + const from = positionToOffset(range.start, target.doc); + const to = positionToOffset(range.end, target.doc); + const { activeFile, editor } = editorManager; + if (activeFile?.id === file.id && editor) { + editor.dispatch({ + changes: { from, to, insert: String(text ?? "") }, + }); + } else { + file._setRawSession( + target.update({ + changes: { from, to, insert: String(text ?? "") }, + }).state, + ); + } + }; + } + + // Ace-compatible method: getWordRange(row, column) + if (prop === "getWordRange") { + return (row, column) => { + const offset = positionToOffset({ row, column }, target.doc); + const word = target.wordAt(offset); + if (word) { + return { + start: offsetToPosition(word.from, target.doc), + end: offsetToPosition(word.to, target.doc), + }; + } + return { start: { row, column }, end: { row, column } }; + }; + } + + // Pass through all other properties to the real EditorState + const value = target[prop]; + if (typeof value === "function") { + return value.bind(target); + } + return value; + }, + }); +} /** * @typedef {'run'|'save'|'change'|'focus'|'blur'|'close'|'rename'|'load'|'loadError'|'loadStart'|'loadEnd'|'changeMode'|'changeEncoding'|'changeReadOnly'} FileEvents @@ -93,10 +282,10 @@ export default class EditorFile { */ deletedFile = false; /** - * EditSession of the file - * @type {AceAjax.IEditSession} + * Raw CodeMirror EditorState. Use session getter to access with Ace-compatible methods. + * @type {EditorState} */ - session = null; + #rawSession = null; /** * Encoding of the text e.g. 'gbk' * @type {string} @@ -340,7 +529,9 @@ export default class EditorFile { editorManager.emit("new-file", this); if (this.#type === "editor") { - this.session = ace.createEditSession(options?.text || ""); + this.#rawSession = EditorState.create({ + doc: options?.text || "", + }); this.setMode(); this.#setupSession(); } @@ -360,6 +551,32 @@ export default class EditorFile { return this.#content; } + /** + * Session with Ace-compatible methods + * Returns a Proxy over the raw EditorState. + * @returns {Proxy} + */ + get session() { + return createSessionProxy(this.#rawSession, this); + } + + /** + * Set the session + * @param {EditorState} value + */ + set session(value) { + this.#rawSession = value; + } + + /** + * Internal method to update the raw session state. + * Used by the Proxy for inactive file updates. + * @param {EditorState} state + */ + _setRawSession(state) { + this.#rawSession = state; + } + /** * File unique id. */ @@ -413,10 +630,10 @@ export default class EditorFile { this.#tab.text = value; this.#name = value; + if (oldExt !== newExt) this.setMode(); + editorManager.onupdate("rename-file"); editorManager.emit("rename-file", this); - - if (oldExt !== newExt) this.setMode(); })(); } @@ -490,7 +707,7 @@ export default class EditorFile { * End of line */ get eol() { - return /\r/.test(this.session.getValue()) ? "windows" : "unix"; + return /\r/.test(this.session.doc.toString()) ? "windows" : "unix"; } /** @@ -500,7 +717,7 @@ export default class EditorFile { set eol(value) { if (this.type !== "editor") return; if (this.eol === value) return; - let text = this.session.getValue(); + let text = this.session.doc.toString(); if (value === "windows") { text = text.replace(/(? { @@ -772,13 +990,32 @@ export default class EditorFile { return this.#save(true); } + setReadOnly(value) { + try { + const { editor, readOnlyCompartment } = editorManager; + if (!editor) return; + if (!readOnlyCompartment) return; + editor.dispatch({ + effects: readOnlyCompartment.reconfigure( + EditorState.readOnly.of(!!value), + ), + }); + } catch (_) {} + + // Sync internal flags and header + this.readOnly = !!value; + this.#editable = !this.readOnly; + if (editorManager.activeFile?.id === this.id) { + editorManager.header.subText = this.#getTitle(); + } + } + /** * Sets syntax highlighting of the file. * @param {string} [mode] */ setMode(mode) { if (this.type !== "editor") return; - const modelist = ace.require("ace/ext/modelist"); const event = createFileEvent(this); this.#emit("changemode", event); if (event.defaultPrevented) return; @@ -789,12 +1026,16 @@ export default class EditorFile { if (modes?.[ext]) { mode = modes[ext]; } else { - mode = modelist.getModeForPath(this.filename).mode; + const modeInfo = getModeForPath(this.filename); + mode = modeInfo?.name || "text"; } } - // sets ace editor EditSession mode - this.session.setMode(mode); + // Store mode info for later use when creating editor view + this.currentMode = mode; + this.currentLanguageExtension = getModeForPath( + this.filename, + )?.getExtension(); // sets file icon this.#tab.lead( @@ -827,7 +1068,11 @@ export default class EditorFile { if (this.focused) { editor.focus(); } else { - editor.blur(); + editor.contentDOM.blur(); + // Ensure any native DOM selection is cleared on blur to avoid sticky selection handles + try { + document.getSelection()?.removeAllRanges(); + } catch (_) {} } } else { editorManager.container.style.display = "none"; @@ -837,8 +1082,9 @@ export default class EditorFile { editorManager.container.parentElement.appendChild(this.content); } } + if (activeFile && activeFile.type === "editor") { - activeFile.session.selection.clearSelection(); + clearSelection(editorManager.editor); } } @@ -1064,12 +1310,20 @@ export default class EditorFile { this.#loadOptions = null; - editor.setReadOnly(true); + this.setReadOnly(true); this.loading = true; this.markChanged = false; this.#emit("loadstart", createFileEvent(this)); this.session.setValue(strings["loading..."]); + // Immediately reflect "loading..." in the visible editor if this tab is active + try { + const { activeFile, emit } = editorManager; + if (activeFile?.id === this.id) { + emit("file-loaded", this); + } + } catch (_) {} + try { const cacheFs = fsOperation(this.cacheFile); const cacheExists = await cacheFs.exists(); @@ -1099,22 +1353,20 @@ export default class EditorFile { const { activeFile, emit } = editorManager; if (activeFile.id === this.id) { - editor.setReadOnly(false); + this.setReadOnly(false); } setTimeout(() => { this.#emit("load", createFileEvent(this)); emit("file-loaded", this); - if (cursorPos) - this.session.selection.moveCursorTo(cursorPos.row, cursorPos.column); - if (scrollTop) this.session.setScrollTop(scrollTop); - if (scrollLeft) this.session.setScrollLeft(scrollLeft); - if (editable !== undefined) this.editable = editable; - - if (Array.isArray(folds)) { - const parsedFolds = EditorFile.#parseFolds(folds); - this.session?.addFolds(parsedFolds); + if (cursorPos) { + restoreSelection(editor, cursorPos); } + if (scrollTop || scrollLeft) { + setScrollPosition(editor, scrollTop, scrollLeft); + } + if (editable !== undefined) this.editable = editable; + restoreFolds(editor, folds); }, 0); } catch (error) { this.#emit("loaderror", createFileEvent(this)); @@ -1127,55 +1379,18 @@ export default class EditorFile { } } - static #onfold(e) { - editorManager.editor._emit("fold", e); - } + // TODO: Implement CodeMirror equivalents for folding and scroll events + // static #onfold(e) { + // editorManager.editor._emit("fold", e); + // } - static #onscrolltop(e) { - editorManager.editor._emit("scrolltop", e); - } + // static #onscrolltop(e) { + // editorManager.editor._emit("scrolltop", e); + // } - static #onscrollleft(e) { - editorManager.editor._emit("scrollleft", e); - } - - /** - * Parse folds - * @param {Array} folds - */ - static #parseFolds(folds) { - if (!Array.isArray(folds)) return []; - - const foldDataAr = []; - - folds.forEach((fold) => { - if (!fold || !fold.range) return; - - const { range } = fold; - const { start, end } = range; - - if (!start || !end) return; - - try { - const foldData = new Fold( - new Range(start.row, start.column, end.row, end.column), - fold.placeholder, - ); - - if (Array.isArray(fold.ranges) && fold.ranges.length > 0) { - const subFolds = EditorFile.#parseFolds(fold.ranges); - foldData.subFolds = subFolds; - foldData.ranges = subFolds; - } - - foldDataAr.push(foldData); - } catch (error) { - console.warn("Error parsing fold:", error); - } - }); - - return foldDataAr; - } + // static #onscrollleft(e) { + // editorManager.editor._emit("scrollleft", e); + // } #save(as) { const event = createFileEvent(this); @@ -1201,35 +1416,26 @@ export default class EditorFile { } /** - * Setup Ace EditSession for the file + * Setup CodeMirror EditorState for the file */ #setupSession() { if (this.type !== "editor") return; - const { value: settings } = appSettings; - - this.session.setTabSize(settings.tabSize); - this.session.setUseSoftTabs(settings.softTab); - this.session.setUseWrapMode(settings.textWrap); - this.session.setUseWorker(false); - - this.session.on("changeScrollTop", EditorFile.#onscrolltop); - this.session.on("changeScrollLeft", EditorFile.#onscrollleft); - this.session.on("changeFold", EditorFile.#onfold); - this.session.on("changeAnnotation", () => { - editorManager.editor._emit("changeAnnotation", this); - }); + // CodeMirror configuration will be handled in the EditorView + // Store settings for when the editor view is created + this.editorSettings = { + tabSize: appSettings.value.tabSize, + softTab: appSettings.value.softTab, + textWrap: appSettings.value.textWrap, + }; } #destroy() { this.#emit("close", createFileEvent(this)); appSettings.off("update:openFileListPos", this.#onFilePosChange); if (this.type === "editor") { - this.session?.off("changeScrollTop", EditorFile.#onscrolltop); - this.session?.off("changeScrollLeft", EditorFile.#onscrollleft); - this.session?.off("changeFold", EditorFile.#onfold); this.#removeCache(); - this.session?.destroy(); - delete this.session; + // CodeMirror EditorState doesn't need explicit cleanup + this.session = null; } else if (this.content) { this.content.remove(); } diff --git a/src/lib/editorManager.js b/src/lib/editorManager.js index 87ec6aab7..c78241179 100644 --- a/src/lib/editorManager.js +++ b/src/lib/editorManager.js @@ -1,13 +1,72 @@ import sidebarApps from "sidebarApps"; -import initColorView, { deactivateColorView } from "ace/colorView"; -import { setCommands, setKeyBindings } from "ace/commands"; -import touchListeners, { scrollAnimationFrame } from "ace/touchHandler"; +import { indentUnit } from "@codemirror/language"; +import { search } from "@codemirror/search"; +import { Compartment, EditorState, Prec, StateEffect } from "@codemirror/state"; +import { oneDark } from "@codemirror/theme-one-dark"; +import { + EditorView, + highlightActiveLineGutter, + highlightTrailingWhitespace, + highlightWhitespace, + keymap, + lineNumbers, + scrollPastEnd, +} from "@codemirror/view"; +import { + abbreviationTracker, + EmmetKnownSyntax, + emmetCompletionSource, + emmetConfig, + expandAbbreviation, + wrapWithAbbreviation, +} from "@emmetio/codemirror6-plugin"; +import createBaseExtensions from "cm/baseExtensions"; +import { + setKeyBindings as applyKeyBindings, + executeCommand, + getCommandKeymapExtension, + getRegisteredCommands, + refreshCommandKeymap, + registerExternalCommand, + removeExternalCommand, +} from "cm/commandRegistry"; +import lspClientManager from "cm/lsp/clientManager"; +import { + getLspDiagnostics, + LSP_DIAGNOSTICS_EVENT, + lspDiagnosticsClientExtension, + lspDiagnosticsUiExtension, +} from "cm/lsp/diagnostics"; +import { stopManagedServer } from "cm/lsp/serverLauncher"; +import serverRegistry from "cm/lsp/serverRegistry"; +// CodeMirror mode management +import { + getModeForPath, + getModes, + getModesByName, + initModes, +} from "cm/modelist"; +import createTouchSelectionMenu from "cm/touchSelectionMenu"; +import "cm/supportedModes"; +import { autocompletion } from "@codemirror/autocomplete"; +import colorView from "cm/colorView"; +import { + getAllFolds, + restoreFolds, + restoreSelection, + setScrollPosition, +} from "cm/editorUtils"; +import indentGuides from "cm/indentGuides"; +import rainbowBrackets from "cm/rainbowBrackets"; +import { getThemeExtensions } from "cm/themes"; import list from "components/collapsableList"; import quickTools from "components/quickTools"; import ScrollBar from "components/scrollbar"; import SideButton, { sideButtonContainer } from "components/sideButton"; import keyboardHandler, { keydownState } from "handlers/keyboard"; import EditorFile from "./editorFile"; +import openFile from "./openFile"; +import { addedFolder } from "./openFolder"; import appSettings from "./settings"; import { getSystemConfiguration, @@ -35,6 +94,26 @@ async function EditorManager($header, $body) { let lastScrollTop = 0; let lastScrollLeft = 0; + // Debounce timers for CodeMirror change handling + let checkTimeout = null; + let autosaveTimeout = null; + let touchSelectionController = null; + let touchSelectionSyncRaf = 0; + let nativeContextMenuDisabled = null; + + const setNativeContextMenuDisabled = (disabled) => { + const value = !!disabled; + if (nativeContextMenuDisabled === value) return; + nativeContextMenuDisabled = value; + const api = globalThis.system?.setNativeContextMenuDisabled; + if (typeof api !== "function") return; + try { + api.call(globalThis.system, value); + } catch (error) { + console.warn("Failed to update native context menu state", error); + } + }; + const { scrollbarSize } = appSettings.value; const events = { "switch-file": [], @@ -54,6 +133,11 @@ async function EditorManager($header, $body) { }, }; const $container =
    ; + // Ensure the container participates well in flex layouts and can constrain the editor + $container.style.flex = "1 1 auto"; + $container.style.minHeight = "0"; // allow child scroller to size correctly + $container.style.height = "100%"; + $container.style.width = "100%"; const problemButton = SideButton({ text: strings.problems, icon: "warningreport_problem", @@ -63,7 +147,1034 @@ async function EditorManager($header, $body) { acode.exec("open", "problems"); }, }); - const editor = ace.edit($container); + + // Make CodeMirror fill the container height and manage scrolling internally + const fixedHeightTheme = EditorView.theme({ + "&": { height: "100%" }, + ".cm-scroller": { height: "100%", overflow: "auto" }, + }); + + const pointerCursorVisibilityExtension = EditorView.updateListener.of( + (update) => { + if (!update.selectionSet) return; + const pointerTriggered = update.transactions.some( + (tr) => + tr.isUserEvent("pointer") || + tr.isUserEvent("select") || + tr.isUserEvent("select.pointer") || + tr.isUserEvent("touch") || + tr.isUserEvent("select.touch"), + ); + if (!pointerTriggered) return; + requestAnimationFrame(() => { + if (!isCursorVisible()) scrollCursorIntoView({ behavior: "instant" }); + }); + }, + ); + + const touchSelectionUpdateExtension = EditorView.updateListener.of( + (update) => { + if (!touchSelectionController) return; + const pointerTriggered = update.transactions.some( + (tr) => + tr.isUserEvent("pointer") || + tr.isUserEvent("select") || + tr.isUserEvent("select.pointer") || + tr.isUserEvent("touch") || + tr.isUserEvent("select.touch"), + ); + if ( + update.selectionSet || + update.docChanged || + update.geometryChanged || + update.viewportChanged || + pointerTriggered + ) { + cancelAnimationFrame(touchSelectionSyncRaf); + touchSelectionSyncRaf = requestAnimationFrame(() => { + touchSelectionController?.onStateChanged({ + pointerTriggered, + selectionChanged: update.selectionSet, + }); + }); + } + }, + ); + + // Compartment to swap editor theme dynamically + const themeCompartment = new Compartment(); + // Compartments to control indentation, tab width, and font styling dynamically + const indentUnitCompartment = new Compartment(); + const tabSizeCompartment = new Compartment(); + const fontStyleCompartment = new Compartment(); + // Compartment for line wrapping + const wrapCompartment = new Compartment(); + // Compartment for line numbers + const lineNumberCompartment = new Compartment(); + // Compartment for text direction (RTL/LTR) + const rtlCompartment = new Compartment(); + // Compartment for whitespace visualization + const whitespaceCompartment = new Compartment(); + // Compartment for fold gutter theme (fade) + const foldThemeCompartment = new Compartment(); + // Compartment for autocompletion behavior + const completionCompartment = new Compartment(); + // Compartment for rainbow bracket colorizer + const rainbowCompartment = new Compartment(); + // Compartment for indent guides + const indentGuidesCompartment = new Compartment(); + // Compartment for read-only toggling + const readOnlyCompartment = new Compartment(); + // Compartment for language mode (allows async loading/reconfigure) + const languageCompartment = new Compartment(); + // Compartment for LSP extensions so we can swap per file + const lspCompartment = new Compartment(); + const diagnosticsClientExt = lspDiagnosticsClientExtension(); + const buildDiagnosticsUiExt = () => + lspDiagnosticsUiExtension(appSettings?.value?.lintGutter !== false); + let lspRequestToken = 0; + let lastLspUri = null; + const UNTITLED_URI_PREFIX = "untitled://acode/"; + + function getEditorFontFamily() { + const font = appSettings?.value?.editorFont || "Roboto Mono"; + return `${font}, Noto Mono, Monaco, monospace`; + } + + function makeFontTheme() { + const fontSize = appSettings?.value?.fontSize || "12px"; + const lineHeight = appSettings?.value?.lineHeight || 1.6; + const fontFamily = getEditorFontFamily(); + return EditorView.theme({ + "&": { fontSize, lineHeight: String(lineHeight) }, + ".cm-content": { fontFamily }, + ".cm-gutter": { fontFamily }, + ".cm-tooltip, .cm-tooltip *": { fontFamily }, + }); + } + + function makeWrapExtension() { + return appSettings?.value?.textWrap ? EditorView.lineWrapping : []; + } + + function makeLineNumberExtension() { + const { linenumbers = true, relativeLineNumbers = false } = + appSettings?.value || {}; + if (!linenumbers) + return EditorView.theme({ + ".cm-gutter": { + display: "none !important", + width: "0px !important", + minWidth: "0px !important", + border: "none !important", + }, + }); + if (!relativeLineNumbers) + return Prec.highest([lineNumbers(), highlightActiveLineGutter()]); + return Prec.highest([ + lineNumbers({ + formatNumber: (lineNo, state) => { + try { + const cur = state.doc.lineAt(state.selection.main.head).number; + const diff = Math.abs(lineNo - cur); + return diff === 0 ? String(lineNo) : String(diff); + } catch (_) { + return String(lineNo); + } + }, + }), + highlightActiveLineGutter(), + ]); + } + + function makeIndentExtensions() { + const { softTab = true, tabSize = 2 } = appSettings?.value || {}; + const unit = softTab ? " ".repeat(Math.max(1, Number(tabSize) || 2)) : "\t"; + return { + indentExt: indentUnit.of(unit), + tabSizeExt: EditorState.tabSize.of(Math.max(1, Number(tabSize) || 2)), + }; + } + + function makeWhitespaceTheme() { + return EditorView.theme({ + ".cm-highlightSpace": { + backgroundImage: + "radial-gradient(circle at 50% 54%, var(--cm-space-marker-color) 0.08em, transparent 0.1em)", + backgroundPosition: "center", + backgroundRepeat: "no-repeat", + opacity: "0.5", + }, + ".cm-highlightTab": { + backgroundSize: "auto 70%", + backgroundPosition: "right 60%", + opacity: "0.65", + }, + ".cm-trailingSpace": { + backgroundColor: "var(--cm-trailing-space-color)", + borderRadius: "2px", + }, + "&": { + "--cm-space-marker-color": "rgba(127, 127, 127, 0.6)", + "--cm-trailing-space-color": "rgba(255, 77, 77, 0.2)", + }, + }); + } + + // Centralised CodeMirror options registry for organized configuration + // Each spec declares related settings keys, its compartment(s), and a builder returning extension(s) + const cmOptionSpecs = [ + { + keys: ["linenumbers", "relativeLineNumbers"], + compartments: [lineNumberCompartment], + build() { + return makeLineNumberExtension(); + }, + }, + { + keys: ["rainbowBrackets"], + compartments: [rainbowCompartment], + build() { + const enabled = appSettings?.value?.rainbowBrackets ?? true; + if (!enabled) return []; + return rainbowBrackets(); + }, + }, + { + keys: ["indentGuides"], + compartments: [indentGuidesCompartment], + build() { + const enabled = appSettings?.value?.indentGuides ?? true; + if (!enabled) return []; + return indentGuides({ + highlightActiveGuide: true, + hideOnBlankLines: false, + }); + }, + }, + { + keys: ["fontSize", "editorFont", "lineHeight"], + compartments: [fontStyleCompartment], + build() { + return makeFontTheme(); + }, + }, + { + keys: ["textWrap"], + compartments: [wrapCompartment], + build() { + return makeWrapExtension(); + }, + }, + { + keys: ["softTab", "tabSize"], + compartments: [indentUnitCompartment, tabSizeCompartment], + build() { + const { indentExt, tabSizeExt } = makeIndentExtensions(); + return [indentExt, tabSizeExt]; + }, + }, + { + keys: ["rtlText"], + compartments: [rtlCompartment], + build() { + const rtl = !!appSettings?.value?.rtlText; + return EditorView.theme({ + "&": { direction: rtl ? "rtl" : "ltr" }, + }); + }, + }, + { + keys: ["showSpaces"], + compartments: [whitespaceCompartment], + build() { + const show = !!appSettings?.value?.showSpaces; + return show + ? [ + highlightWhitespace(), + highlightTrailingWhitespace(), + makeWhitespaceTheme(), + ] + : []; + }, + }, + { + keys: ["fadeFoldWidgets"], + compartments: [foldThemeCompartment], + build() { + const fade = !!appSettings?.value?.fadeFoldWidgets; + if (!fade) return []; + return EditorView.theme({ + ".cm-gutter.cm-foldGutter .cm-gutterElement": { + opacity: 0, + pointerEvents: "none", + transition: "opacity .12s ease", + }, + ".cm-gutter.cm-foldGutter:hover .cm-gutterElement, .cm-gutter.cm-foldGutter .cm-gutterElement:hover": + { + opacity: 1, + pointerEvents: "auto", + }, + }); + }, + }, + { + keys: ["liveAutoCompletion"], + compartments: [completionCompartment], + build() { + const live = !!appSettings?.value?.liveAutoCompletion; + return autocompletion({ activateOnTyping: live }); + }, + }, + ]; + + function getBaseExtensionsFromOptions() { + /** @type {import("@codemirror/state").Extension[]} */ + const exts = []; + for (const spec of cmOptionSpecs) { + const built = spec.build(); + if (spec.compartments.length === 1) { + exts.push(spec.compartments[0].of(built)); + } else { + const arr = Array.isArray(built) ? built : [built]; + for (let i = 0; i < spec.compartments.length; i++) { + const comp = spec.compartments[i]; + const ext = arr[i]; + if (ext !== undefined) exts.push(comp.of(ext)); + } + } + } + return exts; + } + + function createEmmetExtensionSet({ + syntax, + tracker = {}, + config: emmetOverrides = {}, + } = {}) { + const resolvedSyntax = + syntax === undefined ? EmmetKnownSyntax.html : syntax; + if (!resolvedSyntax) return []; + const trackerExtension = abbreviationTracker({ + syntax: resolvedSyntax, + ...tracker, + }); + const { autocompleteTab = ["markup", "stylesheet"], ...restOverrides } = + emmetOverrides || {}; + const emmetConfigExtension = emmetConfig.of({ + syntax: resolvedSyntax, + autocompleteTab, + ...restOverrides, + }); + return [ + Prec.high(trackerExtension), + wrapWithAbbreviation(), + keymap.of([{ key: "Mod-e", run: expandAbbreviation }]), + emmetConfigExtension, + ]; + } + + function applyOptions(keys) { + const filter = keys ? new Set(keys) : null; + for (const spec of cmOptionSpecs) { + if (filter && !spec.keys.some((k) => filter.has(k))) continue; + const built = spec.build(); + const effects = []; + if (spec.compartments.length === 1) { + effects.push(spec.compartments[0].reconfigure(built)); + } else { + const arr = Array.isArray(built) ? built : [built]; + for (let i = 0; i < spec.compartments.length; i++) { + const comp = spec.compartments[i]; + const ext = arr[i] ?? []; + effects.push(comp.reconfigure(ext)); + } + } + editor.dispatch({ effects }); + } + } + + function buildLspMetadata(file) { + if (!file || file.type !== "editor") return null; + const uri = getFileLspUri(file); + if (!uri) return null; + const languageId = getFileLanguageId(file); + return { + uri, + languageId, + languageName: file.currentMode || file.mode || languageId, + view: editor, + file, + rootUri: resolveRootUriForContext({ uri, file }), + }; + } + + async function configureLspForFile(file) { + const metadata = buildLspMetadata(file); + const token = ++lspRequestToken; + if (!metadata) { + detachActiveLsp(); + editor.dispatch({ effects: lspCompartment.reconfigure([]) }); + return; + } + if (metadata.uri !== lastLspUri) { + detachActiveLsp(); + } + try { + const extensions = + (await lspClientManager.getExtensionsForFile(metadata)) || []; + if (token !== lspRequestToken) return; + if (!extensions.length) { + lastLspUri = null; + editor.dispatch({ effects: lspCompartment.reconfigure([]) }); + return; + } + lastLspUri = metadata.uri; + editor.dispatch({ + effects: lspCompartment.reconfigure(extensions), + }); + } catch (error) { + if (token !== lspRequestToken) return; + console.error("Failed to configure LSP", error); + lastLspUri = null; + editor.dispatch({ effects: lspCompartment.reconfigure([]) }); + } + } + + function detachLspForFile(file) { + if (!file || file.type !== "editor") return; + const uri = getFileLspUri(file); + if (!uri) return; + try { + lspClientManager.detach(uri); + } catch (error) { + console.warn(`Failed to detach LSP client for ${uri}`, error); + } + if (uri === lastLspUri && manager.activeFile?.id === file.id) { + lastLspUri = null; + editor.dispatch({ effects: lspCompartment.reconfigure([]) }); + } + } + + // Plugin already wires CSS completions; attach extras for related syntaxes. + const emmetCompletionSyntaxes = new Set([ + EmmetKnownSyntax.scss, + EmmetKnownSyntax.less, + EmmetKnownSyntax.sass, + EmmetKnownSyntax.sss, + EmmetKnownSyntax.stylus, + EmmetKnownSyntax.postcss, + ]); + + function maybeAttachEmmetCompletions(targetExtensions, syntax) { + if (emmetCompletionSyntaxes.has(syntax)) { + targetExtensions.push( + EditorState.languageData.of(() => [ + { autocomplete: emmetCompletionSource }, + ]), + ); + } + } + + function getFileLspUri(file) { + if (!file) return null; + if (file.uri) return file.uri; + return `${UNTITLED_URI_PREFIX}${file.id}`; + } + + function getFileLanguageId(file) { + if (!file) return "plaintext"; + const mode = file.currentMode || file.mode; + if (mode) return String(mode).toLowerCase(); + try { + const guess = getModeForPath(file.filename || file.name || ""); + if (guess?.name) return String(guess.name).toLowerCase(); + } catch (_) {} + return "plaintext"; + } + + function resolveRootUriForContext(context = {}) { + const uri = context.uri || context.file?.uri; + if (!uri) return null; + for (const folder of addedFolder) { + try { + const base = folder?.url; + if (!base) continue; + if (uri.startsWith(base)) return base; + } catch (_) {} + } + return uri; + } + + function detachActiveLsp() { + if (!lastLspUri) return; + try { + lspClientManager.detach(lastLspUri, editor); + } catch (error) { + console.warn(`Failed to detach LSP session for ${lastLspUri}`, error); + } + lastLspUri = null; + } + + function applyLspSettings() { + const { lsp } = appSettings.value || {}; + if (!lsp) return; + const overrides = lsp.servers || {}; + for (const [id, config] of Object.entries(overrides)) { + if (!config || typeof config !== "object") continue; + const key = String(id || "") + .trim() + .toLowerCase(); + if (!key) continue; + const existing = serverRegistry.getServer(key); + if (existing) { + serverRegistry.updateServer(key, (current) => { + const next = { ...current }; + if (Array.isArray(config.languages) && config.languages.length) { + next.languages = config.languages.map((lang) => + String(lang).toLowerCase(), + ); + } + if (config.transport && typeof config.transport === "object") { + next.transport = { ...current.transport, ...config.transport }; + delete next.transport.protocols; + } + if (config.clientConfig && typeof config.clientConfig === "object") { + next.clientConfig = { + ...current.clientConfig, + ...config.clientConfig, + }; + } + if ( + config.initializationOptions && + typeof config.initializationOptions === "object" + ) { + next.initializationOptions = { + ...current.initializationOptions, + ...config.initializationOptions, + }; + } + if ( + typeof config.startupTimeout === "number" && + Number.isFinite(config.startupTimeout) && + config.startupTimeout > 0 + ) { + next.startupTimeout = Math.floor(config.startupTimeout); + } + if (config.launcher && typeof config.launcher === "object") { + next.launcher = { ...current.launcher, ...config.launcher }; + } + if (Object.prototype.hasOwnProperty.call(config, "enabled")) { + next.enabled = !!config.enabled; + } + return next; + }); + if (config.enabled === false) { + stopManagedServer(key); + } + } else if ( + Array.isArray(config.languages) && + config.languages.length && + config.transport && + typeof config.transport === "object" + ) { + try { + serverRegistry.registerServer({ + id: key, + label: config.label || key, + languages: config.languages, + transport: config.transport, + clientConfig: config.clientConfig, + initializationOptions: config.initializationOptions, + startupTimeout: config.startupTimeout, + launcher: config.launcher, + enabled: config.enabled !== false, + }); + serverRegistry.updateServer(key, (current) => { + if (current.transport?.protocols) { + const updated = { ...current }; + updated.transport = { ...current.transport }; + delete updated.transport.protocols; + return updated; + } + return current; + }); + if (config.enabled === false) { + stopManagedServer(key); + } + } catch (error) { + console.warn( + `Failed to register LSP server override for ${key}`, + error, + ); + } + } + } + } + + // Create minimal CodeMirror editor + const editorState = EditorState.create({ + doc: "", + extensions: [ + // Emmet needs highest precedence so place before default keymaps + ...createEmmetExtensionSet({ syntax: EmmetKnownSyntax.html }), + ...createBaseExtensions(), + getCommandKeymapExtension(), + // Default theme + themeCompartment.of(oneDark), + fixedHeightTheme, + scrollPastEnd(), + pointerCursorVisibilityExtension, + touchSelectionUpdateExtension, + search(), + // Ensure read-only can be toggled later via compartment + readOnlyCompartment.of(EditorState.readOnly.of(false)), + // Editor options driven by settings via compartments + ...getBaseExtensionsFromOptions(), + ], + }); + + const editor = new EditorView({ + state: editorState, + parent: $container, + }); + + await applyKeyBindings(editor); + + editor.execCommand = function (commandName, args) { + if (!commandName) return false; + return executeCommand(String(commandName), editor, args); + }; + + editor.commands = { + addCommand(descriptor) { + const command = registerExternalCommand(descriptor); + refreshCommandKeymap(editor); + return command; + }, + removeCommand(name) { + if (!name) return; + removeExternalCommand(name); + refreshCommandKeymap(editor); + }, + }; + + Object.defineProperty(editor.commands, "commands", { + get() { + const map = {}; + getRegisteredCommands().forEach((cmd) => { + map[cmd.name] = cmd; + }); + return map; + }, + }); + + // Provide editor.session for Ace API compatibility + // Returns the active file's session (Proxy with Ace-like methods) + Object.defineProperty(editor, "session", { + get() { + return manager.activeFile?.session ?? null; + }, + }); + + touchSelectionController = createTouchSelectionMenu(editor, { + container: $container, + getActiveFile: () => manager?.activeFile || null, + }); + + // Provide minimal Ace-like API compatibility used by plugins + /** + * Insert text at the current selection/cursor in the editor + * @param {string} text + * @returns {boolean} success + */ + editor.insert = function (text) { + try { + const { from, to } = editor.state.selection.main; + const insertText = String(text ?? ""); + // Replace current selection and move cursor to end of inserted text + editor.dispatch({ + changes: { from, to, insert: insertText }, + selection: { + anchor: from + insertText.length, + head: from + insertText.length, + }, + }); + return true; + } catch (_) { + return false; + } + }; + + // Set CodeMirror theme by id registered in our registry + editor.setTheme = function (themeId) { + try { + const id = String(themeId || ""); + const ext = getThemeExtensions(id, [oneDark]); + editor.dispatch({ effects: themeCompartment.reconfigure(ext) }); + return true; + } catch (_) { + return false; + } + }; + + /** + * Go to a specific line and column in the editor (CodeMirror implementation) + * Supports multiple input formats: + * - Simple line number: gotoLine(16) or gotoLine(16, 5) + * - Relative offsets: gotoLine("+5") or gotoLine("-3") + * - Percentages: gotoLine("50%") or gotoLine("25%") + * - Line:column format: gotoLine("16:5") + * - Mixed formats: gotoLine("+5:10") or gotoLine("50%:5") + * + * @param {number|string} line - Line number (1-based), or string with special formats + * @param {number} column - Column number (0-based) - only used with numeric line parameter + * @param {boolean} animate - Whether to animate (not used in CodeMirror, for compatibility) + * @returns {boolean} success + */ + editor.gotoLine = function (line, column = 0, animate = false) { + try { + const { state } = editor; + const { doc } = state; + + let targetLine, + targetColumn = column; + + // If line is a string, parse it for special formats + if (typeof line === "string") { + const match = /^([+-])?(\d+)?(:\d+)?(%)?$/.exec(line.trim()); + if (!match) { + console.warn("Invalid gotoLine format:", line); + return false; + } + + const currentLine = doc.lineAt(state.selection.main.head); + const [, sign, lineNum, colonColumn, percent] = match; + + // Parse column if specified in line:column format + if (colonColumn) { + targetColumn = Math.max(0, +colonColumn.slice(1) - 1); // Convert to 0-based + } + + // Parse line number + let parsedLine = lineNum ? +lineNum : currentLine.number; + + if (lineNum && percent) { + // Percentage format: "50%" or "+10%" + let percentage = parsedLine / 100; + if (sign) { + percentage = + percentage * (sign === "-" ? -1 : 1) + + currentLine.number / doc.lines; + } + targetLine = Math.round(doc.lines * percentage); + } else if (lineNum && sign) { + // Relative format: "+5" or "-3" + targetLine = + parsedLine * (sign === "-" ? -1 : 1) + currentLine.number; + } else if (lineNum) { + // Absolute line number + targetLine = parsedLine; + } else { + // No line number specified, stay on current line + targetLine = currentLine.number; + } + } else { + // Simple numeric line parameter + targetLine = line; + } + + // Clamp line number to valid range + const lineNum = Math.max(1, Math.min(targetLine, doc.lines)); + const docLine = doc.line(lineNum); + + // Clamp column to line length + const col = Math.max(0, Math.min(targetColumn, docLine.length)); + const pos = docLine.from + col; + + // Move cursor and scroll into view + editor.dispatch({ + selection: { anchor: pos, head: pos }, + effects: EditorView.scrollIntoView(pos, { y: "center" }), + }); + editor.focus(); + return true; + } catch (error) { + console.error("Error in gotoLine:", error); + return false; + } + }; + + /** + * Get current cursor position) + * @returns {{row: number, column: number}} Cursor position + */ + editor.getCursorPosition = function () { + try { + const head = editor.state.selection.main.head; + const cursor = editor.state.doc.lineAt(head); + const line = cursor.number; + const col = head - cursor.from; + return { row: line, column: col }; + } catch (_) { + return { row: 1, column: 0 }; + } + }; + + /** + * Move cursor to specific position + * @param {{row: number, column: number}} pos - Position to move to + */ + editor.moveCursorToPosition = function (pos) { + try { + const lineNum = Math.max(1, pos.row || 1); + const col = Math.max(0, pos.column || 0); + editor.gotoLine(lineNum, col); + } catch (_) { + // ignore + } + }; + + /** + * Get the entire document value + * @returns {string} Document content + */ + editor.getValue = function () { + try { + return editor.state.doc.toString(); + } catch (_) { + return ""; + } + }; + + /** + * Compatibility object for selection-related methods + */ + editor.selection = { + /** + * Get current selection anchor + * @returns {number} Anchor position + */ + get anchor() { + try { + return editor.state.selection.main.anchor; + } catch (_) { + return 0; + } + }, + + /** + * Get current selection range + * @returns {{start: {row: number, column: number}, end: {row: number, column: number}}} Selection range + */ + getRange: function () { + try { + const { from, to } = editor.state.selection.main; + const fromLine = editor.state.doc.lineAt(from); + const toLine = editor.state.doc.lineAt(to); + return { + start: { + row: fromLine.number, + column: from - fromLine.from, + }, + end: { + row: toLine.number, + column: to - toLine.from, + }, + }; + } catch (_) { + return { start: { row: 1, column: 0 }, end: { row: 1, column: 0 } }; // Default to line 1 + } + }, + + /** + * Get cursor position + * @returns {{row: number, column: number}} Cursor position + */ + getCursor: function () { + return editor.getCursorPosition(); + }, + }; + + /** + * Get selected text or text under cursor (CodeMirror implementation) + * @returns {string} Selected text + */ + editor.getCopyText = function () { + try { + const { from, to } = editor.state.selection.main; + if (from === to) return ""; // No selection + return editor.state.doc.sliceString(from, to); + } catch (_) { + return ""; + } + }; + + editor.setSelection = function (value) { + touchSelectionController?.setSelection(!!value); + }; + + editor.setMenu = function (value) { + touchSelectionController?.setMenu(!!value); + }; + + // Helper: apply a file's content and language to the editor view + function applyFileToEditor(file) { + if (!file || file.type !== "editor") return; + const syntax = getEmmetSyntaxForFile(file); + const baseExtensions = [ + // Emmet needs to precede default keymaps so tracker Tab wins over indent + ...createEmmetExtensionSet({ syntax }), + ...createBaseExtensions(), + getCommandKeymapExtension(), + // keep compartment in the state to allow dynamic theme changes later + themeCompartment.of(oneDark), + fixedHeightTheme, + scrollPastEnd(), + pointerCursorVisibilityExtension, + touchSelectionUpdateExtension, + search(), + // Keep dynamic compartments across state swaps + ...getBaseExtensionsFromOptions(), + ]; + const exts = [...baseExtensions]; + maybeAttachEmmetCompletions(exts, syntax); + try { + const langExtFn = file.currentLanguageExtension; + let initialLang = []; + if (typeof langExtFn === "function") { + let result; + try { + result = langExtFn(); + } catch (_) { + result = []; + } + // If the loader returns a Promise, reconfigure when it resolves + if (result && typeof result.then === "function") { + initialLang = []; + result + .then((ext) => { + try { + editor.dispatch({ + effects: languageCompartment.reconfigure(ext || []), + }); + } catch (_) {} + }) + .catch(() => { + // ignore load errors; remain in plain text + }); + } else { + initialLang = result || []; + } + } + // Ensure language compartment is present (empty -> plain text) + exts.push(languageCompartment.of(initialLang)); + } catch (e) { + // ignore language extension errors; fallback to plain text + } + + // Color preview plugin when enabled + if (appSettings.value.colorPreview) { + exts.push(colorView(true)); + } + + // Apply read-only state based on file.editable/loading using Compartment + try { + const ro = !file.editable || !!file.loading; + exts.push(readOnlyCompartment.of(EditorState.readOnly.of(ro))); + } catch (e) { + // safe to ignore; editor will remain editable by default + } + + // Keep file.session in sync and handle caching/autosave + exts.push(getDocSyncListener()); + exts.push(lspCompartment.of([])); + + // Preserve previous state for restoring selection/folds after swap + const prevState = file.session || null; + + const doc = prevState ? prevState.doc.toString() : ""; + const state = EditorState.create({ doc, extensions: exts }); + file.session = state; + editor.setState(state); + touchSelectionController?.onSessionChanged(); + // Re-apply selected theme after state replacement + const desiredTheme = appSettings?.value?.editorTheme; + if (desiredTheme) editor.setTheme(desiredTheme); + + // Ensure dynamic compartments reflect current settings + applyOptions(); + + // Restore selection from previous state if available + try { + const sel = prevState?.selection; + if (sel && Array.isArray(sel.ranges)) { + const ranges = sel.ranges.map((r) => ({ from: r.from, to: r.to })); + const mainIndex = sel.mainIndex ?? 0; + restoreSelection(editor, { ranges, mainIndex }); + } + } catch (_) {} + + // Restore folds from previous state if available + try { + const folds = prevState ? getAllFolds(prevState) : []; + if (folds && folds.length) { + restoreFolds(editor, folds); + } + } catch (_) {} + + // Restore last known scroll position if present + if ( + typeof file.lastScrollTop === "number" || + typeof file.lastScrollLeft === "number" + ) { + setScrollPosition(editor, file.lastScrollTop, file.lastScrollLeft); + } + + void configureLspForFile(file); + } + + function getEmmetSyntaxForFile(file) { + const mode = (file?.currentMode || "").toLowerCase(); + const name = (file?.filename || "").toLowerCase(); + const ext = name.includes(".") ? name.split(".").pop() : ""; + if (ext === "tsx" || mode.includes("tsx")) return EmmetKnownSyntax.tsx; + if (ext === "jsx" || mode.includes("jsx")) return EmmetKnownSyntax.jsx; + if (mode.includes("javascript") && (ext === "jsx" || ext === "tsx")) { + return ext === "tsx" ? EmmetKnownSyntax.tsx : EmmetKnownSyntax.jsx; + } + if (ext === "css" || mode.includes("css")) return EmmetKnownSyntax.css; + if (ext === "scss" || mode.includes("scss")) return EmmetKnownSyntax.scss; + if (ext === "sass" || mode.includes("sass")) return EmmetKnownSyntax.sass; + if (ext === "less" || mode.includes("less")) return EmmetKnownSyntax.less; + if (ext === "sss" || mode.includes("sss")) return EmmetKnownSyntax.sss; + if (ext === "styl" || ext === "stylus" || mode.includes("styl")) + return EmmetKnownSyntax.stylus; + if (ext === "postcss" || mode.includes("postcss")) + return EmmetKnownSyntax.postcss; + if (ext === "xml" || mode.includes("xml")) return EmmetKnownSyntax.xml; + if (ext === "xsl" || mode.includes("xsl")) return EmmetKnownSyntax.xsl; + if (ext === "haml" || mode.includes("haml")) return EmmetKnownSyntax.haml; + if ( + ext === "pug" || + ext === "jade" || + mode.includes("pug") || + mode.includes("jade") + ) + return EmmetKnownSyntax.pug; + if (ext === "slim" || mode.includes("slim")) return EmmetKnownSyntax.slim; + if (ext === "vue" || mode.includes("vue")) return EmmetKnownSyntax.vue; + if (ext === "php" || mode.includes("php")) return EmmetKnownSyntax.html; + if ( + ext === "htm" || + ext === "html" || + ext === "xhtml" || + mode.includes("html") + ) + return EmmetKnownSyntax.html; + return null; + } + const $vScrollbar = ScrollBar({ width: scrollbarSize, onscroll: onscrollV, @@ -83,6 +1194,7 @@ async function EditorManager($header, $body) { activeFile: null, addFile, editor, + readOnlyCompartment, getFile, switchFile, hasUnsavedFiles, @@ -90,6 +1202,7 @@ async function EditorManager($header, $body) { getEditorWidth, header: $header, container: $container, + getLspMetadata: buildLspMetadata, get isScrolling() { return isScrolling; }, @@ -128,42 +1241,177 @@ async function EditorManager($header, $body) { events.emit(detailedEvent, ...detailedEventArgs); } }, + /** + * Restart LSP for the active file + * Useful after stopping/restarting language servers + */ + restartLsp() { + const activeFile = manager.activeFile; + if (activeFile?.type === "editor") { + void configureLspForFile(activeFile); + } + }, }; - // set mode text - editor.setSession(ace.createEditSession("", "ace/mode/text")); + if (typeof document !== "undefined") { + const globalTarget = + typeof globalThis !== "undefined" ? globalThis : document; + const diagnosticsListenerKey = "__acodeDiagnosticsListener"; + const existing = globalTarget?.[diagnosticsListenerKey]; + if (typeof existing === "function") { + document.removeEventListener(LSP_DIAGNOSTICS_EVENT, existing); + } + const listener = () => { + const active = manager.activeFile; + if (active?.type === "editor") { + try { + active.session = editor.state; + } catch (_) {} + } + toggleProblemButton(); + }; + document.addEventListener(LSP_DIAGNOSTICS_EVENT, listener); + if (globalTarget) { + globalTarget[diagnosticsListenerKey] = listener; + } + } + + lspClientManager.setOptions({ + resolveRoot: resolveRootUriForContext, + onClientIdle: ({ server }) => { + if (server?.id) stopManagedServer(server.id); + }, + displayFile: async (targetUri) => { + if (!targetUri) return null; + // Decode URI components (e.g., %40 -> @) since LSP returns encoded URIs + const decodedUri = decodeURIComponent(targetUri); + const existing = manager.getFile(decodedUri, "uri"); + if (existing?.type === "editor") { + existing.makeActive(); + return editor; + } + try { + await openFile(decodedUri, { render: true }); + const opened = manager.getFile(decodedUri, "uri"); + if (opened?.type === "editor") { + opened.makeActive(); + return editor; + } + } catch (error) { + console.error("[LSP] Failed to open file", decodedUri, error); + } + return null; + }, + openFile: async (targetUri) => { + if (!targetUri) return null; + // Decode URI components (e.g., %40 -> @) + const decodedUri = decodeURIComponent(targetUri); + const existing = manager.getFile(decodedUri, "uri"); + if (existing?.type === "editor") { + existing.makeActive(); + return editor; + } + try { + await openFile(decodedUri, { render: true }); + const opened = manager.getFile(decodedUri, "uri"); + if (opened?.type === "editor") { + opened.makeActive(); + return editor; + } + } catch (error) { + console.error("[LSP] Failed to open file", decodedUri, error); + } + return null; + }, + resolveLanguageId: (uri) => { + if (!uri) return "plaintext"; + try { + const mode = getModeForPath(uri); + if (mode?.name) return String(mode.name).toLowerCase(); + } catch (_) {} + return "plaintext"; + }, + clientExtensions: [diagnosticsClientExt], + diagnosticsUiExtension: buildDiagnosticsUiExt(), + }); + applyLspSettings(); + $body.append($container); + initModes(); // Initialize CodeMirror modes await setupEditor(); + // Initialize theme from settings or fallback + try { + const desired = appSettings?.value?.editorTheme || "one_dark"; + editor.setTheme(desired); + } catch (_) {} + + // Ensure initial options reflect settings + applyOptions(); + $hScrollbar.onshow = $vScrollbar.onshow = updateFloatingButton.bind( {}, false, ); $hScrollbar.onhide = $vScrollbar.onhide = updateFloatingButton.bind({}, true); - appSettings.on("update:textWrap", function (value) { + appSettings.on("update:textWrap", function () { updateMargin(); - for (let file of manager.files) { - file.session.setUseWrapMode(value); - if (!value) file.session.on("changeScrollLeft", onscrollleft); - else file.session.off("changeScrollLeft", onscrollleft); + applyOptions(["textWrap"]); + }); + + function updateEditorIndentationSettings() { + applyOptions(["softTab", "tabSize"]); + } + + function updateEditorStyleFromSettings() { + applyOptions(["fontSize", "editorFont", "lineHeight"]); + } + + function updateEditorWrapFromSettings() { + applyOptions(["textWrap"]); + if (appSettings.value.textWrap) { + $hScrollbar.hide(); } + } + + function updateEditorLineNumbersFromSettings() { + applyOptions(["linenumbers", "relativeLineNumbers"]); + } + + appSettings.on("update:tabSize", function () { + updateEditorIndentationSettings(); }); - appSettings.on("update:tabSize", function (value) { - manager.files.forEach((file) => file.session.setTabSize(value)); + appSettings.on("update:softTab", function () { + updateEditorIndentationSettings(); }); - appSettings.on("update:softTab", function (value) { - manager.files.forEach((file) => file.session.setUseSoftTabs(value)); + // Show spaces/tabs and trailing whitespace + appSettings.on("update:showSpaces", function () { + applyOptions(["showSpaces"]); }); - appSettings.on("update:showSpaces", function (value) { - editor.setOption("showInvisibles", value); + // Font size update for CodeMirror + appSettings.on("update:fontSize", function () { + updateEditorStyleFromSettings(); }); - appSettings.on("update:fontSize", function (value) { - editor.setFontSize(value); + // Font family update for CodeMirror + appSettings.on("update:editorFont", function () { + updateEditorStyleFromSettings(); + }); + + appSettings.on("update:lsp", async function () { + applyLspSettings(); + const active = manager.activeFile; + if (active?.type === "editor") { + void configureLspForFile(active); + } else { + detachActiveLsp(); + editor.dispatch({ effects: lspCompartment.reconfigure([]) }); + await lspClientManager.dispose(); + } }); appSettings.on("update:openFileListPos", function (value) { @@ -171,69 +1419,175 @@ async function EditorManager($header, $body) { $vScrollbar.resize(); }); - appSettings.on("update:showPrintMargin", function (value) { - editorManager.editor.setOption("showPrintMargin", value); - }); + // appSettings.on("update:showPrintMargin", function (value) { + // // manager.editor.setOption("showPrintMargin", value); + // }); appSettings.on("update:scrollbarSize", function (value) { $vScrollbar.size = value; $hScrollbar.size = value; }); - appSettings.on("update:liveAutoCompletion", function (value) { - editor.setOption("enableLiveAutocompletion", value); + // Live autocompletion (activateOnTyping) + appSettings.on("update:liveAutoCompletion", function () { + applyOptions(["liveAutoCompletion"]); }); - appSettings.on("update:linenumbers", function (value) { + appSettings.on("update:linenumbers", function () { updateMargin(true); - editor.resize(true); + updateEditorLineNumbersFromSettings(); }); - appSettings.on("update:lineHeight", function (value) { - editor.container.style.lineHeight = value; + // Line height update for CodeMirror + appSettings.on("update:lineHeight", function () { + updateEditorStyleFromSettings(); }); - appSettings.on("update:relativeLineNumbers", function (value) { - editor.setOption("relativeLineNumbers", value); + appSettings.on("update:relativeLineNumbers", function () { + updateEditorLineNumbersFromSettings(); }); - appSettings.on("update:elasticTabstops", function (value) { - editor.setOption("useElasticTabstops", value); + appSettings.on("update:lintGutter", function (value) { + lspClientManager.setOptions({ + diagnosticsUiExtension: lspDiagnosticsUiExtension(value !== false), + }); + const active = manager.activeFile; + if (active?.type === "editor") { + void configureLspForFile(active); + } }); - appSettings.on("update:rtlText", function (value) { - editor.setOption("rtlText", value); - }); + // appSettings.on("update:elasticTabstops", function (_value) { + // // Not applicable in CodeMirror (Ace-era). No-op for now. + // }); - appSettings.on("update:hardWrap", function (value) { - editor.setOption("hardWrap", value); + appSettings.on("update:rtlText", function () { + applyOptions(["rtlText"]); }); - appSettings.on("update:printMargin", function (value) { - editor.setOption("printMarginColumn", value); - }); + // appSettings.on("update:hardWrap", function (_value) { + // // Not applicable in CodeMirror (Ace-era). No-op for now. + // }); - appSettings.on("update:colorPreview", function (value) { - if (value) { - return initColorView(editor, true); - } + // appSettings.on("update:printMargin", function (_value) { + // // Not applicable in CodeMirror (Ace-era). No-op for now. + // }); - deactivateColorView(); + appSettings.on("update:colorPreview", function () { + const file = manager.activeFile; + if (file?.type === "editor") applyFileToEditor(file); }); appSettings.on("update:showSideButtons", function () { updateMargin(); updateSideButtonContainer(); + toggleProblemButton(); }); appSettings.on("update:showAnnotations", function () { updateMargin(true); }); - appSettings.on("update:fadeFoldWidgets", function (value) { - editor.setOption("fadeFoldWidgets", value); + appSettings.on("update:fadeFoldWidgets", function () { + applyOptions(["fadeFoldWidgets"]); + }); + + // Toggle rainbow brackets + appSettings.on("update:rainbowBrackets", function () { + applyOptions(["rainbowBrackets"]); }); + // Toggle indent guides + appSettings.on("update:indentGuides", function () { + applyOptions(["indentGuides"]); + }); + + // Keep file.session and cache in sync on every edit + function getDocSyncListener() { + return EditorView.updateListener.of((update) => { + const file = manager.activeFile; + if (!file || file.type !== "editor") return; + + // Only run expensive work when the document actually changed + if (!update.docChanged) return; + + // Mirror latest state only on doc changes to avoid clobbering async loads + try { + file.session = update.state; + } catch (_) {} + + // Debounced change handling (unsaved flag, cache, autosave) + if (checkTimeout) clearTimeout(checkTimeout); + if (autosaveTimeout) clearTimeout(autosaveTimeout); + + checkTimeout = setTimeout(async () => { + const changed = await file.isChanged(); + file.isUnsaved = changed; + try { + await file.writeToCache(); + } catch (_) {} + + events.emit("file-content-changed", file); + manager.onupdate("file-changed"); + manager.emit("update", "file-changed"); + toggleProblemButton(); + + const { autosave } = appSettings.value; + if (file.uri && changed && autosave) { + autosaveTimeout = setTimeout(() => { + acode.exec("save", false); + }, autosave); + } + + file.markChanged = true; + }, TIMEOUT_VALUE); + }); + } + + // Register critical listeners + manager.on(["file-loaded"], (file) => { + if (!file) return; + if (manager.activeFile?.id === file.id && file.type === "editor") { + applyFileToEditor(file); + } + }); + + manager.on(["update:read-only"], () => { + const file = manager.activeFile; + if (file?.type !== "editor") return; + try { + const ro = !file.editable || !!file.loading; + editor.dispatch({ + effects: readOnlyCompartment.reconfigure(EditorState.readOnly.of(ro)), + }); + touchSelectionController?.onStateChanged(); + } catch (_) { + // Fallback: full re-apply + applyFileToEditor(file); + } + }); + + manager.on(["remove-file"], (file) => { + detachLspForFile(file); + toggleProblemButton(); + }); + + manager.on(["rename-file"], (file) => { + if (file?.type !== "editor") return; + if (manager.activeFile?.id === file.id) { + // Re-apply file to editor to update language/syntax highlighting + applyFileToEditor(file); + void configureLspForFile(file); + } + }); + + // Attach doc-sync listener to the current editor instance + try { + editor.dispatch({ + effects: StateEffect.appendConfig.of(getDocSyncListener()), + }); + } catch (_) {} + return manager; /** @@ -245,6 +1599,7 @@ async function EditorManager($header, $body) { manager.files.push(file); manager.openFileList.append(file.tab); $header.text = file.name; + toggleProblemButton(); } /** @@ -252,8 +1607,6 @@ async function EditorManager($header, $body) { * @returns {Promise} A promise that resolves once the editor is set up. */ async function setupEditor() { - const Emmet = ace.require("ace/ext/emmet"); - const textInput = editor.textInput.getElement(); const settings = appSettings.value; const { leftMargin, textWrap, colorPreview, fontSize, lineHeight } = appSettings.value; @@ -265,170 +1618,140 @@ async function EditorManager($header, $body) { let checkTimeout = null; let autosaveTimeout; let scrollTimeout; + const scroller = editor.scrollDOM; - editor.on("focus", async () => { - const { activeFile } = manager; - activeFile.focused = true; - keyboardHandler.on("keyboardShow", scrollCursorIntoView); + function handleEditorScroll() { + if (!scroller) return; + onscrolltop(); + onscrollleft(); + touchSelectionController?.onScroll(); + clearTimeout(scrollTimeout); + isScrolling = true; + scrollTimeout = setTimeout(() => { + isScrolling = false; + }, 100); + } - if (isScrolling) return; + scroller?.addEventListener("scroll", handleEditorScroll, { passive: true }); + handleEditorScroll(); - $hScrollbar.hide(); - $vScrollbar.hide(); + keyboardHandler.on("keyboardShowStart", () => { + requestAnimationFrame(() => { + scrollCursorIntoView({ behavior: "instant" }); + }); }); + keyboardHandler.on("keyboardShow", scrollCursorIntoView); - editor.on("blur", async () => { + // Attach native DOM event listeners directly to the editor's contentDOM + const contentDOM = editor.contentDOM; + const isFocused = + contentDOM === document.activeElement || + contentDOM.contains(document.activeElement); + setNativeContextMenuDisabled(isFocused); + + contentDOM.addEventListener("focus", (_event) => { + setNativeContextMenuDisabled(true); + const { activeFile } = manager; + if (activeFile) { + activeFile.focused = true; + } + touchSelectionController?.onStateChanged(); + }); + + contentDOM.addEventListener("blur", async (_event) => { + setNativeContextMenuDisabled(false); + touchSelectionController?.setMenu(false); const { hardKeyboardHidden, keyboardHeight } = await getSystemConfiguration(); const blur = () => { const { activeFile } = manager; - activeFile.focused = false; - activeFile.focusedBefore = false; + if (activeFile) { + activeFile.focused = false; + activeFile.focusedBefore = false; + } }; - if ( hardKeyboardHidden === HARDKEYBOARDHIDDEN_NO && keyboardHeight < 100 ) { - // external keyboard + // external keyboard - blur immediately blur(); return; } - + // soft keyboard - wait for keyboard to hide const onKeyboardHide = () => { keyboardHandler.off("keyboardHide", onKeyboardHide); blur(); }; - keyboardHandler.on("keyboardHide", onKeyboardHide); }); - editor.on("change", (e) => { - if (checkTimeout) clearTimeout(checkTimeout); - if (autosaveTimeout) clearTimeout(autosaveTimeout); - - checkTimeout = setTimeout(async () => { - const { activeFile } = manager; - - if (activeFile.markChanged) { - const changed = await activeFile.isChanged(); - activeFile.isUnsaved = changed; - activeFile.writeToCache(); - events.emit("file-content-changed", activeFile); - manager.onupdate("file-changed"); - manager.emit("update", "file-changed"); - - const { autosave } = appSettings.value; - if (activeFile.uri && changed && autosave) { - autosaveTimeout = setTimeout(() => { - acode.exec("save", false); - }, autosave); - } - } - activeFile.markChanged = true; - }, TIMEOUT_VALUE); - }); - - editor.on("changeAnnotation", toggleProblemButton); - - editor.on("scroll", () => { - clearTimeout(scrollTimeout); - isScrolling = true; - scrollTimeout = setTimeout(() => { - isScrolling = false; - }, 100); - }); - - editor.renderer.on("resize", () => { - $vScrollbar.resize($vScrollbar.visible); - $hScrollbar.resize($hScrollbar.visible); - }); - - editor.on("scrolltop", onscrolltop); - editor.on("scrollleft", onscrollleft); - textInput.addEventListener("keydown", (e) => { - if (e.key === "Escape") { - keydownState.esc = { value: true, target: textInput }; + contentDOM.addEventListener("keydown", (event) => { + if (event.key === "Escape") { + keydownState.esc = { value: true, target: contentDOM }; } }); - if (colorPreview) { - initColorView(editor); - } - - touchListeners(editor); - setCommands(editor); - await setKeyBindings(editor); - Emmet.setCore(window.emmet); - editor.setFontSize(fontSize); - editor.setHighlightSelectedWord(true); - editor.container.style.lineHeight = lineHeight; - - ace.require("ace/ext/language_tools"); - editor.setOption("animatedScroll", false); - editor.setOption("tooltipFollowsMouse", false); - editor.setOption("theme", settings.editorTheme); - editor.setOption( - "showGutter", - settings.linenumbers || settings.showAnnotations, - ); - editor.setOption("showLineNumbers", settings.linenumbers); - editor.setOption("enableEmmet", true); - editor.setOption("showInvisibles", settings.showSpaces); - editor.setOption("indentedSoftWrap", false); - editor.setOption("scrollPastEnd", 0.5); - editor.setOption("showPrintMargin", settings.showPrintMargin); - editor.setOption("relativeLineNumbers", settings.relativeLineNumbers); - editor.setOption("useElasticTabstops", settings.elasticTabstops); - editor.setOption("useTextareaForIME", settings.useTextareaForIME); - editor.setOption("rtlText", settings.rtlText); - editor.setOption("hardWrap", settings.hardWrap); - editor.setOption("spellCheck", settings.spellCheck); - editor.setOption("printMarginColumn", settings.printMargin); - editor.setOption("enableBasicAutocompletion", true); - editor.setOption("enableLiveAutocompletion", settings.liveAutoCompletion); - editor.setOption("copyWithEmptySelection", true); - editor.setOption("fadeFoldWidgets", settings.fadeFoldWidgets); - // editor.setOption('enableInlineAutocompletion', settings.inlineAutoCompletion); - updateMargin(true); updateSideButtonContainer(); - editor.renderer.setScrollMargin( - scrollMarginTop, - scrollMarginBottom, - scrollMarginLeft, - scrollMarginRight, - ); + toggleProblemButton(); } /** * Scrolls the cursor into view if it is not currently visible. */ - function scrollCursorIntoView() { - keyboardHandler.off("keyboardShow", scrollCursorIntoView); - if (isCursorVisible()) return; - const { teardropSize } = appSettings.value; - editor.renderer.scrollCursorIntoView(); - editor.renderer.scrollBy(0, teardropSize + 10); - editor._emit("scroll-intoview"); + function scrollCursorIntoView(options = {}) { + const view = editor; + const scroller = view?.scrollDOM; + if (!view || !scroller) return; + + const { behavior = "smooth" } = options; + const { head } = view.state.selection.main; + const caret = safeCoordsAtPos(view, head); + if (!caret) return; + + const scrollerRect = scroller.getBoundingClientRect(); + const relativeTop = caret.top - scrollerRect.top + scroller.scrollTop; + const relativeBottom = caret.bottom - scrollerRect.top + scroller.scrollTop; + const topMargin = 16; + const bottomMargin = (appSettings.value?.teardropSize || 24) + 12; + + const scrollTop = scroller.scrollTop; + const visibleTop = scrollTop + topMargin; + const visibleBottom = scrollTop + scroller.clientHeight - bottomMargin; + + if (relativeTop < visibleTop) { + const nextTop = Math.max(relativeTop - topMargin, 0); + scroller.scrollTo({ top: nextTop, behavior }); + } else if (relativeBottom > visibleBottom) { + const delta = relativeBottom - visibleBottom; + scroller.scrollTo({ top: scrollTop + delta, behavior }); + } } /** - * Checks if the cursor is visible within the Ace editor. + * Checks if the cursor is visible within the CodeMirror viewport. * @returns {boolean} - True if the cursor is visible, false otherwise. */ function isCursorVisible() { - const { editor, container } = editorManager; - const { teardropSize } = appSettings.value; - const cursorPos = editor.getCursorPosition(); - const contentTop = container.getBoundingClientRect().top; - const contentBottom = contentTop + container.clientHeight; - const cursorTop = editor.renderer.textToScreenCoordinates( - cursorPos.row, - cursorPos.column, - ).pageY; - const cursorBottom = cursorTop + teardropSize + 10; - return cursorTop >= contentTop && cursorBottom <= contentBottom; + const view = editor; + const scroller = view?.scrollDOM; + if (!view || !scroller) return true; + + const { head } = view.state.selection.main; + const caret = safeCoordsAtPos(view, head); + if (!caret) return true; + + const scrollerRect = scroller.getBoundingClientRect(); + return caret.top >= scrollerRect.top && caret.bottom <= scrollerRect.bottom; + } + + function safeCoordsAtPos(view, pos) { + try { + return view.coordsAtPos(pos); + } catch (_) { + return null; + } } /** @@ -436,14 +1759,16 @@ async function EditorManager($header, $body) { * @param {Number} value */ function onscrollV(value) { + const scroller = editor?.scrollDOM; + if (!scroller) return; + const normalized = clamp01(value); + const maxScroll = Math.max( + scroller.scrollHeight - scroller.clientHeight, + 0, + ); preventScrollbarV = true; - const session = editor.getSession(); - const editorHeight = getEditorHeight(editor); - const scroll = editorHeight * value; - - session.setScrollTop(scroll); - editor._emit("scroll", editor); - cancelAnimationFrame(scrollAnimationFrame); + scroller.scrollTop = normalized * maxScroll; + lastScrollTop = scroller.scrollTop; } /** @@ -451,6 +1776,7 @@ async function EditorManager($header, $body) { */ function onscrollVend() { preventScrollbarV = false; + setVScrollValue(); } /** @@ -458,14 +1784,14 @@ async function EditorManager($header, $body) { * @param {number} value - The scroll value. */ function onscrollH(value) { + if (appSettings.value.textWrap) return; + const scroller = editor?.scrollDOM; + if (!scroller) return; + const normalized = clamp01(value); + const maxScroll = Math.max(scroller.scrollWidth - scroller.clientWidth, 0); preventScrollbarH = true; - const session = editor.getSession(); - const editorWidth = getEditorWidth(editor); - const scroll = editorWidth * value; - - session.setScrollLeft(scroll); - editor._emit("scroll", editor); - cancelAnimationFrame(scrollAnimationFrame); + scroller.scrollLeft = normalized * maxScroll; + lastScrollLeft = scroller.scrollLeft; } /** @@ -473,6 +1799,7 @@ async function EditorManager($header, $body) { */ function onscrollHEnd() { preventScrollbarH = false; + setHScrollValue(); } /** @@ -480,17 +1807,19 @@ async function EditorManager($header, $body) { */ function setHScrollValue() { if (appSettings.value.textWrap || preventScrollbarH) return; - const session = editor.getSession(); - const scrollLeft = session.getScrollLeft(); - + const scroller = editor?.scrollDOM; + if (!scroller) return; + const maxScroll = Math.max(scroller.scrollWidth - scroller.clientWidth, 0); + if (maxScroll <= 0) { + lastScrollLeft = 0; + $hScrollbar.value = 0; + return; + } + const scrollLeft = scroller.scrollLeft; if (scrollLeft === lastScrollLeft) return; - - const editorWidth = getEditorWidth(editor); - const factor = (scrollLeft / editorWidth).toFixed(2); - lastScrollLeft = scrollLeft; - $hScrollbar.value = factor; - editor._emit("scroll", "horizontal"); + const factor = scrollLeft / maxScroll; + $hScrollbar.value = clamp01(factor); } /** @@ -498,6 +1827,19 @@ async function EditorManager($header, $body) { * Updates the horizontal scroll value and renders the horizontal scrollbar. */ function onscrollleft() { + if (appSettings.value.textWrap) { + $hScrollbar.hide(); + return; + } + const scroller = editor?.scrollDOM; + if (!scroller) return; + const maxScroll = Math.max(scroller.scrollWidth - scroller.clientWidth, 0); + if (maxScroll <= 0) { + $hScrollbar.hide(); + lastScrollLeft = 0; + $hScrollbar.value = 0; + return; + } setHScrollValue(); $hScrollbar.render(); } @@ -507,17 +1849,22 @@ async function EditorManager($header, $body) { */ function setVScrollValue() { if (preventScrollbarV) return; - const session = editor.getSession(); - const scrollTop = session.getScrollTop(); - + const scroller = editor?.scrollDOM; + if (!scroller) return; + const maxScroll = Math.max( + scroller.scrollHeight - scroller.clientHeight, + 0, + ); + if (maxScroll <= 0) { + lastScrollTop = 0; + $vScrollbar.value = 0; + return; + } + const scrollTop = scroller.scrollTop; if (scrollTop === lastScrollTop) return; - - const editorHeight = getEditorHeight(editor); - const factor = (scrollTop / editorHeight).toFixed(2); - lastScrollTop = scrollTop; - $vScrollbar.value = factor; - editor._emit("scroll", "vertical"); + const factor = scrollTop / maxScroll; + $vScrollbar.value = clamp01(factor); } /** @@ -525,10 +1872,28 @@ async function EditorManager($header, $body) { * Updates the vertical scroll value and renders the vertical scrollbar. */ function onscrolltop() { + const scroller = editor?.scrollDOM; + if (!scroller) return; + const maxScroll = Math.max( + scroller.scrollHeight - scroller.clientHeight, + 0, + ); + if (maxScroll <= 0) { + $vScrollbar.hide(); + lastScrollTop = 0; + $vScrollbar.value = 0; + return; + } setVScrollValue(); $vScrollbar.render(); } + function clamp01(value) { + if (value <= 0) return 0; + if (value >= 1) return 1; + return value; + } + /** * Updates the floating button visibility based on the provided show parameter. * @param {boolean} [show=false] - Indicates whether to show the floating button. @@ -573,20 +1938,50 @@ async function EditorManager($header, $body) { /** * Toggles the visibility of the problem button based on the presence of annotations in the files. */ + function fileHasProblems(file) { + const state = getDiagnosticStateForFile(file); + if (!state) return false; + + const session = file.session; + if (session && typeof session.getAnnotations === "function") { + try { + const annotations = session.getAnnotations() || []; + if (annotations.length) return true; + } catch (_) {} + } + + if (typeof state.field !== "function") return false; + try { + const diagnostics = getLspDiagnostics(state); + return diagnostics.length > 0; + } catch (_) {} + + return false; + } + function toggleProblemButton() { - const fileWithProblems = manager.files.find((file) => { - if (file.type !== "editor") return false; - const annotations = file?.session?.getAnnotations(); - return !!annotations.length; - }); + const { showSideButtons } = appSettings.value; + if (!showSideButtons) { + problemButton.hide(); + return; + } - if (fileWithProblems) { + const hasProblems = manager.files.some((file) => fileHasProblems(file)); + if (hasProblems) { problemButton.show(); } else { problemButton.hide(); } } + function getDiagnosticStateForFile(file) { + if (!file || file.type !== "editor") return null; + if (manager.activeFile?.id === file.id && editor?.state) { + return editor.state; + } + return file.session || null; + } + /** * Updates the side button container based on the value of `showSideButtons` in `appSettings`. * If `showSideButtons` is `false`, the side button container is removed from the DOM. @@ -612,15 +2007,15 @@ async function EditorManager($header, $body) { const bottom = 0; const right = showSideButtons ? 15 : 0; const left = linenumbers ? (showAnnotations ? 0 : -16) : 0; - - editor.renderer.setMargin(top, bottom, left, right); + // TODO + //editor.renderer.setMargin(top, bottom, left, right); if (!updateGutter) return; - editor.setOptions({ - showGutter: linenumbers || showAnnotations, - showLineNumbers: linenumbers, - }); + // editor.setOptions({ + // showGutter: linenumbers || showAnnotations, + // showLineNumbers: linenumbers, + // }); } /** @@ -641,11 +2036,24 @@ async function EditorManager($header, $body) { manager.activeFile.content.style.display = "none"; } + // Persist the previous editor's state before switching away + const prev = manager.activeFile; + if (prev?.type === "editor") { + try { + prev.session = editor.state; + } catch (_) {} + try { + prev.lastScrollTop = editor.scrollDOM?.scrollTop || 0; + prev.lastScrollLeft = editor.scrollDOM?.scrollLeft || 0; + } catch (_) {} + } + manager.activeFile = file; if (file.type === "editor") { - editor.setSession(file.session); - editor.setReadOnly(!file.editable || !!file.loading); + touchSelectionController?.setEnabled(true); + // Apply active file content and language to CodeMirror + applyFileToEditor(file); $container.style.display = "block"; $hScrollbar.hideImmediately(); @@ -656,6 +2064,7 @@ async function EditorManager($header, $body) { setHScrollValue(); } } else { + touchSelectionController?.setEnabled(false); $container.style.display = "none"; if (file.content) { file.content.style.display = "block"; @@ -663,9 +2072,6 @@ async function EditorManager($header, $body) { $container.parentElement.appendChild(file.content); } } - if (manager.activeFile && manager.activeFile.type === "editor") { - manager.activeFile.session.selection.clearSelection(); - } } file.tab.classList.add("active"); @@ -675,6 +2081,8 @@ async function EditorManager($header, $body) { $header.subText = file.headerSubtitle || ""; manager.onupdate("switch-file"); events.emit("switch-file", file); + + toggleProblemButton(); } /** @@ -773,31 +2181,42 @@ async function EditorManager($header, $body) { /** * Gets the height of the editor - * @param {AceAjax.Editor} editor + * @param {object} editor * @returns */ function getEditorHeight(editor) { - const { renderer, session } = editor; - const offset = (renderer.$size.scrollerHeight + renderer.lineHeight) * 0.5; - const editorHeight = - session.getScreenLength() * renderer.lineHeight - offset; - return editorHeight; + try { + const view = editor; + if (!view || !view.scrollDOM) return 0; + + const total = view.scrollDOM.scrollHeight || 0; + const viewport = view.scrollDOM.clientHeight || 0; + return Math.max(total - viewport, 0); + } catch (_) { + return 0; + } } /** * Gets the height of the editor - * @param {AceAjax.Editor} editor + * @param {object} editor * @returns */ function getEditorWidth(editor) { - const { renderer, session } = editor; - const offset = renderer.$size.scrollerWidth - renderer.characterWidth; - const editorWidth = - session.getScreenWidth() * renderer.characterWidth - offset; - if (appSettings.value.textWrap) { - return editorWidth; - } else { - return editorWidth + appSettings.value.leftMargin; + try { + const view = editor; + if (!view || !view.scrollDOM) return 0; + + const total = view.scrollDOM.scrollWidth || 0; + const viewport = view.scrollDOM.clientWidth || 0; + let width = Math.max(total - viewport, 0); + if (!appSettings.value.textWrap) { + const { leftMargin = 0 } = appSettings.value; + width += leftMargin || 0; + } + return width; + } catch (_) { + return 0; } } } diff --git a/src/lib/keyBindings.js b/src/lib/keyBindings.js index a658f4581..a5f481346 100644 --- a/src/lib/keyBindings.js +++ b/src/lib/keyBindings.js @@ -1,712 +1,656 @@ -export default { - focusEditor: { +import * as cmCommands from "@codemirror/commands"; +import { + defaultKeymap, + emacsStyleKeymap, + historyKeymap, + indentWithTab, + standardKeymap, +} from "@codemirror/commands"; + +const MODIFIER_ORDER = ["Ctrl", "Alt", "Shift", "Cmd"]; +const KEYMAP_SOURCES = [ + ...standardKeymap, + ...defaultKeymap, + ...historyKeymap, + ...emacsStyleKeymap, + indentWithTab, +]; + +const APP_BINDING_CONFIG = [ + { + name: "focusEditor", description: "Focus editor", key: "Ctrl-1", readOnly: false, }, - copy: { - description: "Copy", - key: "Ctrl-C", - readOnly: true, - editorOnly: true, - }, - cut: { - description: "Cut", - key: "Ctrl-X", - readOnly: false, - editorOnly: true, - }, - paste: { - description: "Paste", - key: "Ctrl-V", - readOnly: false, - editorOnly: true, - }, - findFile: { + { + name: "findFile", description: "Find a file", key: "Ctrl-P", action: "find-file", }, - closeCurrentTab: { + { + name: "closeCurrentTab", description: "Close current tab.", key: "Ctrl-Q", - readOnly: false, action: "close-current-tab", + readOnly: false, }, - closeAllTabs: { + { + name: "closeAllTabs", description: "Close all tabs.", key: "Ctrl-Shift-Q", - readOnly: false, action: "close-all-tabs", + readOnly: false, }, - newFile: { + { + name: "newFile", description: "Create new file", key: "Ctrl-N", - readOnly: true, action: "new-file", + readOnly: true, }, - openFile: { + { + name: "openFile", description: "Open a file", key: "Ctrl-O", - readOnly: true, action: "open-file", + readOnly: true, }, - openFolder: { + { + name: "openFolder", description: "Open a folder", key: "Ctrl-Shift-O", - readOnly: true, action: "open-folder", + readOnly: true, }, - saveFile: { + { + name: "saveFile", description: "Save current file", key: "Ctrl-S", - readOnly: true, action: "save", + readOnly: true, editorOnly: true, }, - saveFileAs: { + { + name: "saveFileAs", description: "Save as current file", key: "Ctrl-Shift-S", - readOnly: true, action: "save-as", + readOnly: true, editorOnly: true, }, - nextFile: { + { + name: "saveAllChanges", + description: "Save all changes", + key: null, + action: "save-all-changes", + readOnly: true, + }, + { + name: "nextFile", description: "Open next file tab", key: "Ctrl-Tab", - readOnly: true, action: "next-file", + readOnly: true, }, - prevFile: { + { + name: "prevFile", description: "Open previous file tab", key: "Ctrl-Shift-Tab", - readOnly: true, action: "prev-file", + readOnly: true, }, - renameFile: { + { + name: "showSettingsMenu", + description: "Show settings menu", + key: "Ctrl-,", + readOnly: false, + }, + { + name: "renameFile", description: "Rename current file", key: "F2", - readOnly: true, action: "rename", + readOnly: true, editorOnly: true, }, - run: { + { + name: "run", description: "Run current file", key: "F5", - readOnly: false, action: "run", - editorOnly: true, - }, - selectWord: { - description: "Select current word", - key: "Ctrl-D", readOnly: false, - action: "select-word", editorOnly: true, }, - autoindent: { + { + name: "openInAppBrowser", + description: "Open in-app browser", key: null, - description: "Auto indentation", - readOnly: false, - }, - showSettingsMenu: { - key: "Ctrl-,", - description: "Show settings menu", - readOnly: false, + readOnly: true, }, - toggleFullscreen: { - key: "F11", + { + name: "toggleFullscreen", description: "Toggle full screen mode", - readOnly: false, + key: "F11", action: "toggle-fullscreen", + readOnly: false, }, - toggleSidebar: { - key: "Ctrl-B", + { + name: "toggleSidebar", description: "Toggle sidebar", - readOnly: true, + key: "Ctrl-B", action: "toggle-sidebar", + readOnly: true, }, - toggleMenu: { + { + name: "toggleMenu", + description: "Toggle menu", key: "F3", - description: "Toggle edit menu", - readOnly: true, action: "toggle-menu", + readOnly: true, }, - toggleEditMenu: { - key: "F4", + { + name: "toggleEditMenu", description: "Toggle edit menu", - readOnly: true, + key: "F4", action: "toggle-editmenu", + readOnly: true, }, - goToNextError: { - key: "Alt-E", - description: "Go to next error", - readOnly: false, - editorOnly: true, - }, - goToPreviousError: { - key: "Alt-Shift-E", - description: "Go to previous error", - readOnly: false, - editorOnly: true, - }, - selectall: { + { + name: "selectall", description: "Select all", key: "Ctrl-A", readOnly: true, editorOnly: true, }, - centerselection: { - description: "Center selection", - key: null, - readOnly: false, - }, - gotoline: { - description: "Go to line...", + { + name: "gotoline", + description: "Go to line", key: "Ctrl-G", readOnly: true, editorOnly: true, }, - fold: { - description: "Fold", - key: "Alt-L|Ctrl-F1", - readOnly: false, - editorOnly: true, - }, - unfold: { - description: "Unfold", - key: "Alt-Shift-L|Ctrl-Shift-F1", - readOnly: false, - editorOnly: true, - }, - toggleFoldWidget: { - key: null, - readOnly: false, - editorOnly: true, - }, - toggleParentFoldWidget: { - key: "Alt-F2", - readOnly: false, - editorOnly: true, - }, - foldall: { - description: "Fold all", - key: null, - readOnly: false, - editorOnly: true, - }, - foldOther: { - description: "Fold other", - key: "Alt-0", - readOnly: false, - editorOnly: true, - }, - unfoldall: { - description: "Unfold all", - key: "Alt-Shift-0", - readOnly: false, - editorOnly: true, - }, - findnext: { - description: "Find next", - key: "Ctrl-K", - readOnly: false, - }, - findprevious: { - description: "Find previous", - key: "Ctrl-Shift-X", - readOnly: false, - }, - selectOrFindNext: { - description: "Select or find next", - key: "Alt-K", - readOnly: false, - }, - selectOrFindPrevious: { - description: "Select or find previous", - key: "Alt-Shift-K", - readOnly: false, - }, - find: { + { + name: "find", description: "Find", key: "Ctrl-F", readOnly: true, editorOnly: true, }, - overwrite: { - description: "Overwrite", - key: "Insert", - readOnly: true, - }, - selecttostart: { - description: "Select to start", - key: "Ctrl-Shift-Home", - readOnly: true, - editorOnly: true, - }, - gotostart: { - description: "Go to start", - key: "Ctrl-Home", - readOnly: true, - editorOnly: true, - }, - selectup: { - description: "Select up", - key: "Shift-Up", + { + name: "copy", + description: "Copy", + key: "Ctrl-C", readOnly: true, editorOnly: true, }, - golineup: { - description: "Go line up", - key: "Up", - readOnly: true, + { + name: "cut", + description: "Cut", + key: "Ctrl-X", + readOnly: false, editorOnly: true, }, - selecttoend: { - description: "Select to end", - key: "Ctrl-Shift-End", - readOnly: true, + { + name: "paste", + description: "Paste", + key: "Ctrl-V", + readOnly: false, editorOnly: true, }, - gotoend: { - description: "Go to end", - key: "Ctrl-End", + { + name: "problems", + description: "Show problems", + key: null, readOnly: true, editorOnly: true, }, - selectdown: { - description: "Select down", - key: "Shift-Down", - readOnly: true, + { + name: "replace", + description: "Replace", + key: "Ctrl-R", + readOnly: false, editorOnly: true, }, - golinedown: { - description: "Go line down", - key: "Down", + { + name: "openCommandPalette", + description: "Open command palette", + key: "Ctrl-Shift-P", readOnly: true, - editorOnly: true, }, - selectwordleft: { - description: "Select word left", - key: "Ctrl-Shift-Left", - readOnly: true, + { + name: "modeSelect", + description: "Change language mode", + key: "Ctrl-M", + readOnly: false, editorOnly: true, }, - gotowordleft: { - description: "Go to word left", - key: "Ctrl-Left", + { + name: "toggleQuickTools", + description: "Toggle quick tools", + key: null, readOnly: true, - editorOnly: true, }, - selecttolinestart: { - description: "Select to line start", - key: "Alt-Shift-Left", - readOnly: true, + { + name: "selectWord", + description: "Select current word", + key: "Ctrl-D", + action: "select-word", + readOnly: false, editorOnly: true, }, - gotolinestart: { - description: "Go to line start", - key: "Alt-Left|Home", + { + name: "openLogFile", + description: "Open log file", + key: null, + action: "open-log-file", readOnly: true, - editorOnly: true, }, - selectleft: { - description: "Select left", - key: "Shift-Left", + { + name: "openPluginsPage", + description: "Open plugins page", + key: null, readOnly: true, - editorOnly: true, }, - gotoleft: { - description: "Go to left", - key: "Left", + { + name: "openFileExplorer", + description: "Open file explorer", + key: null, readOnly: true, - editorOnly: true, }, - selectwordright: { - description: "Select word right", - key: "Ctrl-Shift-Right", + { + name: "copyDeviceInfo", + description: "Copy device info", + key: null, + action: "copy-device-info", readOnly: true, - editorOnly: true, }, - gotowordright: { - description: "Go to word right", - key: "Ctrl-Right", + { + name: "changeAppTheme", + description: "Change app theme", + key: null, + action: "change-app-theme", readOnly: true, - editorOnly: true, }, - selecttolineend: { - description: "Select to line end", - key: "Alt-Shift-Right", + { + name: "changeEditorTheme", + description: "Change editor theme", + key: null, + action: "change-editor-theme", readOnly: true, - editorOnly: true, }, - gotolineend: { - description: "Go to line end", - key: "Alt-Right|End", + { + name: "openTerminal", + description: "Open terminal", + key: "Ctrl-`", + action: "new-terminal", readOnly: true, - editorOnly: true, }, - selectright: { - description: "Select right", - key: "Shift-Right", + { + name: "documentSymbols", + description: "Go to symbol in document", + key: null, readOnly: true, editorOnly: true, }, - gotoright: { - description: "Go to right", - key: "Right", - readOnly: true, + { + name: "duplicateSelection", + description: "Duplicate selection", + key: "Ctrl-Shift-D", + readOnly: false, editorOnly: true, }, - selectpagedown: { - description: "Select page down", - key: "Shift-PageDown", - readOnly: true, + { + name: "copylinesdown", + description: "Copy lines down", + key: "Alt-Shift-Down", + readOnly: false, editorOnly: true, }, - pagedown: { - description: "Page down", - key: null, - readOnly: true, + { + name: "copylinesup", + description: "Copy lines up", + key: "Alt-Shift-Up", + readOnly: false, editorOnly: true, }, - gotopagedown: { - description: "Go to page down", - key: "PageDown", + { + name: "movelinesdown", + description: "Move lines down", + key: "Alt-Down", readOnly: false, editorOnly: true, }, - selectpageup: { - description: "Select page up", - key: "Shift-PageUp", - readOnly: true, + { + name: "movelinesup", + description: "Move lines up", + key: "Alt-Up", + readOnly: false, editorOnly: true, }, - pageup: { - description: "Page up", + { + name: "removeline", + description: "Remove line", key: null, readOnly: false, editorOnly: true, }, - problems: { - description: "Show problems", - key: "Ctrl-Shift-K", - readOnly: true, + { + name: "insertlineafter", + description: "Insert line after", + key: null, + readOnly: false, editorOnly: true, }, - gotopageup: { - description: "Go to page up", - key: "PageUp", + { + name: "selectline", + description: "Select line", + key: null, readOnly: true, editorOnly: true, }, - scrollup: { - description: "Scroll up", - key: "Ctrl-Up", + { + name: "selectlinesdown", + description: "Select lines down", + key: null, readOnly: true, editorOnly: true, }, - scrolldown: { - description: "Scroll down", - key: "Ctrl-Down", + { + name: "selectlinesup", + description: "Select lines up", + key: null, readOnly: true, editorOnly: true, }, - selectlinestart: { + { + name: "selectlinestart", description: "Select line start", key: "Shift-Home", readOnly: true, editorOnly: true, }, - selectlineend: { + { + name: "selectlineend", description: "Select line end", key: "Shift-End", readOnly: true, editorOnly: true, }, - togglerecording: { - description: "Toggle recording", - key: "Ctrl-Alt-E", - readOnly: true, - editorOnly: true, - }, - formatcode: { - description: "Format Code", - key: "Ctrl-Alt-F", + { + name: "indent", + description: "Indent", + key: "Tab", readOnly: false, editorOnly: true, - action: "format", }, - replaymacro: { - description: "Replay macro", - key: "Ctrl-Shift-E", - readOnly: true, - editorOnly: true, - }, - jumptomatching: { - description: "Jump to matching", - key: "Ctrl-\\", - readOnly: true, + { + name: "outdent", + description: "Outdent", + key: "Shift-Tab", + readOnly: false, editorOnly: true, }, - selecttomatching: { - description: "Select to matching", - key: "Ctrl-Shift-\\", + { + name: "indentselection", + description: "Indent selection", + key: null, readOnly: false, editorOnly: true, }, - expandToMatching: { - description: "Expand to matching", - key: "Ctrl-Shift-M", + { + name: "newline", + description: "Insert newline", + key: null, readOnly: false, editorOnly: true, }, - removeline: { - description: "Remove line", + { + name: "joinlines", + description: "Join lines", key: null, readOnly: false, editorOnly: true, }, - duplicateSelection: { - description: "Duplicate selection", - key: "Ctrl-Shift-D", + { + name: "deletetolinestart", + description: "Delete to line start", + key: null, readOnly: false, editorOnly: true, }, - sortlines: { - description: "Sort lines", - key: "Ctrl-Alt-S", + { + name: "deletetolineend", + description: "Delete to line end", + key: null, readOnly: false, editorOnly: true, }, - togglecomment: { + { + name: "togglecomment", description: "Toggle comment", key: "Ctrl-/", readOnly: false, editorOnly: true, }, - toggleBlockComment: { - description: "Toggle block comment", - key: "Ctrl-Shift-/", - readOnly: false, - editorOnly: true, - }, - modifyNumberUp: { - description: "Modify number up", - key: "Ctrl-Shift-Up", + { + name: "comment", + description: "Add line comment", + key: null, readOnly: false, editorOnly: true, }, - modifyNumberDown: { - description: "Modify number down", - key: "Ctrl-Shift-Down", + { + name: "uncomment", + description: "Remove line comment", + key: null, readOnly: false, editorOnly: true, }, - replace: { - description: "Replace", - key: "Ctrl-R", + { + name: "toggleBlockComment", + description: "Toggle block comment", + key: "Ctrl-Shift-/", readOnly: false, editorOnly: true, }, - undo: { + { + name: "undo", description: "Undo", key: "Ctrl-Z", readOnly: false, editorOnly: true, }, - redo: { + { + name: "redo", description: "Redo", key: "Ctrl-Shift-Z|Ctrl-Y", readOnly: false, editorOnly: true, }, - copylinesup: { - description: "Copy lines up", - key: "Alt-Shift-Up", - readOnly: false, - editorOnly: true, - }, - movelinesup: { - description: "Move lines up", - key: "Alt-Up", - readOnly: false, - editorOnly: true, - }, - copylinesdown: { - description: "Copy lines down", - key: "Alt-Shift-Down", - readOnly: false, - editorOnly: true, - }, - movelinesdown: { - description: "Move lines down", - key: "Alt-Down", - readOnly: false, - editorOnly: true, - }, - del: { - description: "Delete", - key: "Delete", - readOnly: true, - editorOnly: true, - }, - backspace: { - description: "Backspace", - key: "Shift-Backspace|Backspace", - readOnly: false, - editorOnly: true, - }, - cut_or_delete: { - description: "Cut or delete", - key: "Shift-Delete", - readOnly: false, - editorOnly: true, - }, - removetolinestart: { - description: "Remove to line start", - key: "Alt-Backspace", - readOnly: false, - editorOnly: true, - }, - removetolineend: { - description: "Remove to line end", - key: "Alt-Delete", - readOnly: false, - editorOnly: true, - }, - removetolinestarthard: { - description: "Remove to line start hard", - key: "Ctrl-Shift-Backspace", - readOnly: false, - editorOnly: true, - }, - removetolineendhard: { - description: "Remove to line end hard", - key: "Ctrl-Shift-Delete", - readOnly: false, - editorOnly: true, - }, - removewordleft: { - description: "Remove word left", - key: "Ctrl-Backspace", - readOnly: false, - editorOnly: true, - }, - removewordright: { - description: "Remove word right", - key: "Ctrl-Delete", - readOnly: false, - editorOnly: true, - }, - outdent: { - description: "Outdent", - key: "Shift-Tab", - readOnly: false, - editorOnly: true, - }, - indent: { - description: "Indent", - key: "Tab", - readOnly: true, - editorOnly: true, - }, - blockoutdent: { - description: "Block outdent", - key: "Ctrl-[", - readOnly: false, - editorOnly: true, - }, - blockindent: { - description: "Block indent", - key: "Ctrl-]", - readOnly: false, - editorOnly: true, - }, - splitline: { - description: "Split line", - key: null, - readOnly: false, - editorOnly: true, - }, - transposeletters: { - description: "Transpose letters", - key: "Alt-Shift-X", - readOnly: false, - editorOnly: true, - }, - touppercase: { - description: "To uppercase", - key: "Ctrl-U", - readOnly: false, - editorOnly: true, - }, - tolowercase: { - description: "To lowercase", - key: "Ctrl-Shift-U", - readOnly: false, - editorOnly: true, - }, - expandtoline: { - description: "Expand to line", - key: "Ctrl-Shift-L", - readOnly: true, - editorOnly: true, - }, - joinlines: { - description: "Join lines", - key: null, - readOnly: false, - editorOnly: true, - }, - invertSelection: { - description: "Invert selection", + { + name: "simplifySelection", + description: "Simplify selection", key: null, - readOnly: false, - editorOnly: true, - }, - openCommandPalette: { - description: "Open command palette", - key: "Ctrl-Shift-P", readOnly: true, - }, - modeSelect: { - description: "Change language mode", - key: "Ctrl-M", - readOnly: false, - editorOnly: true, - }, - increaseFontSize: { - description: "Increase font size", - key: "Ctrl-+|Ctrl-=", - editorOnly: true, - }, - decreaseFontSize: { - description: "Decrease font size", - key: "Ctrl+-|Ctrl-_", editorOnly: true, }, - resetFontSize: { - description: "Reset font size", - key: "Ctrl+0|Ctrl-Numpad0", - editorOnly: true, - }, - openTerminal: { - description: "Open Terminal", - key: "Ctrl-`", - readOnly: true, - action: "new-terminal", - }, - "run-tests": { - description: "Run Tests", - key: "Ctrl-Shift-T", - readOnly: true, - action: "run-tests", - }, - "dev:toggleDevTools": { - description: "Toggle DevTools", - key: "Ctrl-Shift-I", - readOnly: true, - action: "toggle-inspector", - }, -}; +]; + +const APP_KEY_BINDINGS = buildAppBindings(APP_BINDING_CONFIG); +const APP_CUSTOM_COMMANDS = new Set( + APP_BINDING_CONFIG.filter((config) => !config.action).map( + (config) => config.name, + ), +); + +const FORCE_READ_ONLY = new Set([ + "toggleTabFocusMode", + "temporarilySetTabFocusMode", +]); +const MUTATING_COMMAND_PATTERN = + /^(delete|insert|indent|move|copy|split|transpose|toggle|undo|redo|line|block)/i; + +const CODEMIRROR_COMMAND_NAMES = new Set( + Object.entries(cmCommands) + .filter(([, value]) => typeof value === "function") + .map(([name]) => name), +); + +const CODEMIRROR_KEY_BINDINGS = buildCodemirrorKeyBindings(APP_KEY_BINDINGS); + +const keyBindings = Object.fromEntries( + Object.entries({ ...CODEMIRROR_KEY_BINDINGS, ...APP_KEY_BINDINGS }) + .filter( + ([name, binding]) => + binding && + (binding.action || + APP_CUSTOM_COMMANDS.has(name) || + CODEMIRROR_COMMAND_NAMES.has(name)), + ) + .sort((a, b) => a[0].localeCompare(b[0])), +); + +export default keyBindings; + +function buildAppBindings(configs) { + return Object.fromEntries( + configs.map( + ({ + name, + description, + key = null, + action, + readOnly = true, + editorOnly, + }) => [ + name, + { + description: description ?? humanizeCommandName(name), + key, + readOnly, + ...(editorOnly !== undefined ? { editorOnly } : {}), + ...(action ? { action } : {}), + }, + ], + ), + ); +} + +function buildCodemirrorKeyBindings(appBindings) { + const commandEntries = Object.entries(cmCommands).filter( + ([, value]) => typeof value === "function", + ); + const commandNameByFunction = new Map( + commandEntries.map(([name, fn]) => [fn, name]), + ); + const comboMap = new Map(); + + for (const binding of KEYMAP_SOURCES) { + const baseCombos = new Set(); + + pushCommandCombo(binding.run, binding.key, "win", baseCombos); + pushCommandCombo(binding.run, binding.win, "win", baseCombos); + pushCommandCombo(binding.run, binding.linux, "win", baseCombos); + pushCommandCombo(binding.run, binding.mac, "mac", baseCombos); + + if (binding.shift) { + const shiftName = commandNameByFunction.get(binding.shift); + if (shiftName && !appBindings[shiftName]) { + const combos = baseCombos.size + ? Array.from(baseCombos) + : [ + normalizeKey(binding.key, "win"), + normalizeKey(binding.win, "win"), + normalizeKey(binding.linux, "win"), + normalizeKey(binding.mac, "mac"), + ].filter(Boolean); + for (const combo of combos) { + addCommandCombo(comboMap, shiftName, ensureModifier(combo, "Shift")); + } + } + } + } + + const result = {}; + for (const [name, combos] of comboMap.entries()) { + if (!combos.size || appBindings[name]) continue; + result[name] = { + description: humanizeCommandName(name), + key: Array.from(combos) + .sort((a, b) => a.localeCompare(b)) + .join("|"), + readOnly: inferReadOnly(name), + editorOnly: true, + }; + } + return result; + + function pushCommandCombo(commandFn, key, platform, baseCombos) { + if (!commandFn) return; + const name = commandNameByFunction.get(commandFn); + if (!name || appBindings[name]) return; + const normalized = normalizeKey(key, platform); + if (!normalized) return; + addCommandCombo(comboMap, name, normalized); + baseCombos.add(normalized); + } +} + +function addCommandCombo(map, name, combo) { + if (!combo) return; + let entry = map.get(name); + if (!entry) { + entry = new Set(); + map.set(name, entry); + } + entry.add(combo); +} + +function normalizeKey(key, platform = "win") { + if (!key) return null; + const replaced = key.replace(/Mod/g, platform === "mac" ? "Cmd" : "Ctrl"); + const { modifiers, baseKey } = parseKeyParts(replaced); + if (!baseKey) return [...modifiers].join("-") || null; + const ordered = MODIFIER_ORDER.filter((mod) => modifiers.has(mod)); + return [...ordered, baseKey].join("-"); +} + +function ensureModifier(combo, modifier) { + if (!combo) return null; + const { modifiers, baseKey } = parseKeyParts(combo); + if (!baseKey) return combo; + modifiers.add(modifier); + const ordered = MODIFIER_ORDER.filter((mod) => modifiers.has(mod)); + return [...ordered, baseKey].join("-"); +} + +function parseKeyParts(combo) { + const modifiers = new Set(); + let baseKey = ""; + if (!combo) return { modifiers, baseKey }; + for (const rawPart of combo.split("-")) { + const part = rawPart.trim(); + if (!part) continue; + const normalized = part.charAt(0).toUpperCase() + part.slice(1); + if (MODIFIER_ORDER.includes(normalized)) { + modifiers.add(normalized); + } else { + baseKey = part; + } + } + return { modifiers, baseKey }; +} + +function humanizeCommandName(name) { + return name + .replace(/([a-z0-9])([A-Z])/g, "$1 $2") + .replace(/_/g, " ") + .replace(/^./, (char) => char.toUpperCase()); +} + +function inferReadOnly(name) { + if (FORCE_READ_ONLY.has(name)) return true; + return !MUTATING_COMMAND_PATTERN.test(name); +} diff --git a/src/lib/openFile.js b/src/lib/openFile.js index 58319a09d..9de895323 100644 --- a/src/lib/openFile.js +++ b/src/lib/openFile.js @@ -39,12 +39,13 @@ export default async function openFile(file, options = {}) { if (existingFile) { // If file is already opened and new text is provided - const existingText = existingFile.session.getValue(); - const existingCursorPos = existingFile.session.selection.getCursor(); + const existingText = existingFile.session.doc.toString() ?? ""; // If file is already opened existingFile.makeActive(); + const { editor } = editorManager; + if (onsave) { existingFile.onsave = onsave; } @@ -57,20 +58,24 @@ export default async function openFile(file, options = {}) { // } // if (confirmation) { // } - existingFile.session.setValue(text); + editor.dispatch({ + changes: { + from: 0, + to: editor.state.doc.length, + insert: String(text), + }, + }); } - if ( - cursorPos && - existingCursorPos && - existingCursorPos.row !== cursorPos.row && - existingCursorPos.column !== cursorPos.column - ) { - existingFile.session.selection.moveCursorTo( - cursorPos.row, - cursorPos.column, - ); - } + // Move cursor if requested and different + try { + if (cursorPos) { + const cur = editor.getCursorPosition(); + if (cur.row !== cursorPos.row || cur.column !== cursorPos.column) { + editor.gotoLine(cursorPos.row, cursorPos.column); + } + } + } catch (_) {} if (encoding && existingFile.encoding !== encoding) { reopenWithNewEncoding(encoding); diff --git a/src/lib/prettierFormatter.js b/src/lib/prettierFormatter.js new file mode 100644 index 000000000..659898230 --- /dev/null +++ b/src/lib/prettierFormatter.js @@ -0,0 +1,365 @@ +import fsOperation from "fileSystem"; +import toast from "components/toast"; +import appSettings from "lib/settings"; +import prettierPluginBabel from "prettier/plugins/babel"; +import prettierPluginEstree from "prettier/plugins/estree"; +import prettierPluginGraphql from "prettier/plugins/graphql"; +import prettierPluginHtml from "prettier/plugins/html"; +import prettierPluginMarkdown from "prettier/plugins/markdown"; +import prettierPluginPostcss from "prettier/plugins/postcss"; +import prettierPluginTypescript from "prettier/plugins/typescript"; +import prettierPluginYaml from "prettier/plugins/yaml"; +import prettier from "prettier/standalone"; +import helpers from "utils/helpers"; +import Url from "utils/Url"; + +const PRETTIER_ID = "prettier"; +const PRETTIER_NAME = "Prettier"; +const CONFIG_FILENAMES = [ + ".prettierrc", + ".prettierrc.json", + ".prettierrc.json5", + ".prettierrc.js", + ".prettierrc.cjs", + ".prettierrc.mjs", + ".prettierrc.config.cjs", + ".prettierrc.config.mjs", + ".prettier.config.js", + ".prettier.config.cjs", + ".prettier.config.mjs", + "prettier.config.json", + "prettier.config.js", + "prettier.config.cjs", + "prettier.config.mjs", +]; +const PRETTIER_PLUGINS = [ + prettierPluginEstree, + prettierPluginBabel, + prettierPluginHtml, + prettierPluginMarkdown, + prettierPluginPostcss, + prettierPluginTypescript, + prettierPluginYaml, + prettierPluginGraphql, +]; + +/** + * Supported parser mapping keyed by CodeMirror mode name + * @type {Record} + */ +const MODE_TO_PARSER = { + angular: "angular", + gfm: "markdown", + css: "css", + graphql: "graphql", + html: "html", + json: "json", + json5: "json", + jsx: "babel", + less: "less", + markdown: "markdown", + md: "markdown", + mdx: "mdx", + scss: "scss", + styled_jsx: "babel", + typescript: "typescript", + tsx: "typescript", + jsonc: "json", + yaml: "yaml", + yml: "yaml", + vue: "vue", + javascript: "babel", +}; + +const SUPPORTED_EXTENSIONS = [ + "js", + "cjs", + "mjs", + "jsx", + "ts", + "tsx", + "json", + "json5", + "css", + "scss", + "less", + "html", + "htm", + "vue", + "md", + "markdown", + "mdx", + "yaml", + "yml", + "graphql", + "gql", +]; + +/** + * Register Prettier formatter with Acode instance + */ +export function registerPrettierFormatter() { + if (!window?.acode) return; + const alreadyRegistered = acode.formatters.some( + ({ id }) => id === PRETTIER_ID, + ); + if (alreadyRegistered) return; + acode.registerFormatter( + PRETTIER_ID, + SUPPORTED_EXTENSIONS, + () => formatActiveFileWithPrettier(), + PRETTIER_NAME, + ); +} + +async function formatActiveFileWithPrettier() { + const file = editorManager?.activeFile; + const editor = editorManager?.editor; + if (!file || file.type !== "editor" || !editor) return false; + + const modeName = (file.currentMode || "text").toLowerCase(); + const parser = getParserForMode(modeName); + if (!parser) { + toast("Prettier does not support this file type yet"); + return false; + } + + const doc = editor.state.doc; + const source = doc.toString(); + const filepath = file.uri || file.filename || ""; + try { + const config = await resolvePrettierConfig(file); + const formatted = await prettier.format(source, { + ...config, + parser, + plugins: PRETTIER_PLUGINS, + filepath, + overrideEditorconfig: true, + }); + + if (formatted === source) return true; + + editor.dispatch({ + changes: { + from: 0, + to: doc.length, + insert: formatted, + }, + }); + return true; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + toast(message); + return false; + } +} + +function getParserForMode(modeName) { + if (MODE_TO_PARSER[modeName]) return MODE_TO_PARSER[modeName]; + if (modeName.includes("javascript")) return "babel"; + if (modeName.includes("typescript")) return "typescript"; + return null; +} + +async function resolvePrettierConfig(file) { + const overrides = appSettings?.value?.prettier || {}; + const projectConfig = await loadProjectConfig(file); + const result = { ...overrides, ...(projectConfig || {}) }; + if (file?.eol && result.endOfLine == null) { + result.endOfLine = file.eol === "windows" ? "crlf" : "lf"; + } + if (result.useTabs == null) { + result.useTabs = !appSettings?.value?.softTab; + } + if ( + result.tabWidth == null && + typeof appSettings?.value?.tabSize === "number" + ) { + result.tabWidth = appSettings.value.tabSize; + } + return result; +} + +async function loadProjectConfig(file) { + const uri = file?.uri; + if (!uri) return null; + + const projectRoot = findProjectRoot(uri); + const directories = collectCandidateDirectories(uri, projectRoot); + + for (const directory of directories) { + const config = await readConfigFromDirectory(directory); + if (config) return config; + } + + return null; +} + +function findProjectRoot(uri) { + const folders = Array.isArray(globalThis.addedFolder) + ? globalThis.addedFolder + : []; + const target = normalizePath(uri); + let match = null; + let matchLength = -1; + + for (const folder of folders) { + const folderUrl = folder?.url; + if (!folderUrl) continue; + const normalized = normalizePath(folderUrl); + if (!normalized) continue; + if (target === normalized || target.startsWith(`${normalized}/`)) { + if (normalized.length > matchLength) { + match = folderUrl; + matchLength = normalized.length; + } + } + } + + return match; +} + +function collectCandidateDirectories(fileUri, projectRoot) { + const directories = []; + const visited = new Set(); + let currentDir = safeDirname(fileUri); + + while (currentDir) { + const normalized = normalizePath(currentDir); + if (visited.has(normalized)) break; + directories.push(currentDir); + visited.add(normalized); + if (projectRoot && pathsAreSame(currentDir, projectRoot)) break; + const parent = safeDirname(currentDir); + if (!parent || parent === currentDir) break; + currentDir = parent; + } + + if ( + projectRoot && + !directories.some((dir) => pathsAreSame(dir, projectRoot)) + ) { + directories.push(projectRoot); + } + + return directories; +} + +function safeDirname(path) { + try { + return Url.dirname(path); + } catch (_) { + return null; + } +} + +async function readConfigFromDirectory(directory) { + if (!directory) return null; + + for (const name of CONFIG_FILENAMES) { + const config = await loadConfigFile(directory, name); + if (config) return config; + } + + return loadPrettierFromPackageJson(directory); +} + +async function loadConfigFile(directory, basename) { + try { + const filePath = Url.join(directory, basename); + const fs = fsOperation(filePath); + if (!(await fs.exists())) return null; + const text = await fs.readFile("utf8"); + + switch (basename) { + case ".prettierrc": + case ".prettierrc.json": + case ".prettierrc.json5": + case "prettier.config.json": + return parseJsonLike(text); + case ".prettierrc.js": + case ".prettier.config.js": + case "prettier.config.js": + return parseJsConfig(directory, text, filePath); + case ".prettierrc.mjs": + case ".prettierrc.config.mjs": + case ".prettier.config.mjs": + case "prettier.config.mjs": + return parseJsConfig(directory, text, filePath); + case ".prettierrc.cjs": + case ".prettierrc.config.cjs": + case ".prettier.config.cjs": + case "prettier.config.cjs": + return parseJsConfig(directory, text, filePath); + default: + return null; + } + } catch (_) { + return null; + } +} + +async function loadPrettierFromPackageJson(directory) { + try { + const pkgPath = Url.join(directory, "package.json"); + const fs = fsOperation(pkgPath); + if (!(await fs.exists())) return null; + const pkg = await fs.readFile("json"); + const config = pkg?.prettier; + if (config && typeof config === "object") return config; + } catch (_) { + return null; + } + return null; +} + +function parseJsonLike(text) { + const trimmed = text?.trim(); + if (!trimmed) return null; + const parsed = helpers.parseJSON(trimmed); + if (parsed) return parsed; + try { + return new Function(`return (${trimmed});`)(); + } catch (_) { + return null; + } +} + +function parseJsConfig(directory, source, absolutePath) { + if (!source) return null; + void directory; + void absolutePath; + let transformed = source; + if (/export\s+default/.test(transformed)) { + transformed = transformed.replace(/export\s+default/, "module.exports ="); + } + const module = { exports: {} }; + const exports = module.exports; + function requireStub(request) { + throw new Error( + `require(\"${request}\") is not supported in Prettier configs inside Acode`, + ); + } + try { + const fn = new Function("module", "exports", "require", transformed); + fn(module, exports, requireStub); + return module.exports ?? exports; + } catch (_) { + return null; + } +} + +function normalizePath(path) { + let result = String(path || "").replace(/\\/g, "/"); + while (result.length > 1 && result.endsWith("/")) { + const prefix = result.slice(0, -1); + if (/^[a-z]+:\/{0,2}$/i.test(prefix)) break; + result = prefix; + } + return result; +} + +function pathsAreSame(a, b) { + if (!a || !b) return false; + return normalizePath(a) === normalizePath(b); +} diff --git a/src/lib/run.js b/src/lib/run.js index 85df583c8..1b4c5b84c 100644 --- a/src/lib/run.js +++ b/src/lib/run.js @@ -197,7 +197,7 @@ async function run( break; case EXECUTING_SCRIPT: { - const text = activeFile?.session.getValue() || ""; + const text = activeFile?.session?.doc?.toString() || ""; sendText(text, reqId, "application/javascript"); break; } @@ -236,7 +236,7 @@ async function run( if (activeFile.mode === "single") { if (filename === reqPath) { sendText( - activeFile.session.getValue(), + activeFile.session?.doc?.toString(), reqId, mimeType.lookup(filename), ); @@ -270,7 +270,7 @@ async function run( const htmlUrl = Url.join(pathName, reqPath + ".html"); const htmlFile = editorManager.getFile(htmlUrl, "uri"); if (htmlFile?.loaded && htmlFile.isUnsaved) { - sendHTML(htmlFile.session?.getValue(), reqId); + sendHTML(htmlFile.session?.doc?.toString(), reqId); return; } const htmlFs = fsOperation(htmlUrl); @@ -295,7 +295,7 @@ async function run( case ".htm": case ".html": if (file && file.loaded && file.isUnsaved) { - sendHTML(file.session.getValue(), reqId); + sendHTML(file.session?.doc?.toString(), reqId); } else { sendFileContent(url, reqId, MIMETYPE_HTML); } @@ -312,7 +312,7 @@ async function run( .toLowerCase() .replace(/[^a-z0-9]+/g, "-"), }) - .render(file.session.getValue()); + .render(file.session?.doc?.toString()); const doc = mustache.render($_markdown, { html, filename, @@ -325,7 +325,7 @@ async function run( default: if (file && file.loaded && file.isUnsaved) { sendText( - file.session.getValue(), + file.session?.doc?.toString(), reqId, mimeType.lookup(file.filename), ); diff --git a/src/lib/saveFile.js b/src/lib/saveFile.js index a80813ca8..01c8d01db 100644 --- a/src/lib/saveFile.js +++ b/src/lib/saveFile.js @@ -53,7 +53,7 @@ async function saveFile(file, isSaveAs = false) { * File data * @type {string} */ - const data = file.session.getValue(); + const data = file.session ? file.session.doc.toString() : ""; /** * File tab bar text element, used to show saving status * @type {HTMLElement} diff --git a/src/lib/saveState.js b/src/lib/saveState.js index fa825d3b3..9aaa6d7d7 100644 --- a/src/lib/saveState.js +++ b/src/lib/saveState.js @@ -1,3 +1,4 @@ +import { getAllFolds, getScrollPosition, getSelection } from "cm/editorUtils"; import constants from "./constants"; import { addedFolder } from "./openFolder"; import appSettings from "./settings"; @@ -15,6 +16,39 @@ export default () => { if (file.id === constants.DEFAULT_FILE_SESSION) return; if (file.SAFMode === "single") return; + // Selection per file: + // - Active file uses live EditorView selection + // - Inactive files use their persisted EditorState selection + let cursorPos; + if (activeFile?.id === file.id) { + cursorPos = getSelection(editor); + } else { + const sel = file.session?.selection; + if (sel) { + cursorPos = { + ranges: sel.ranges.map((r) => ({ from: r.from, to: r.to })), + mainIndex: sel.mainIndex ?? 0, + }; + } else { + cursorPos = null; + } + } + + // Scroll per file: + // - Active file uses live scroll from EditorView + // - Inactive files use lastScrollTop/Left captured on tab switch + let scrollTop, scrollLeft; + if (activeFile?.id === file.id) { + const sp = getScrollPosition(editor); + scrollTop = sp.scrollTop; + scrollLeft = sp.scrollLeft; + } else { + scrollTop = + typeof file.lastScrollTop === "number" ? file.lastScrollTop : 0; + scrollLeft = + typeof file.lastScrollLeft === "number" ? file.lastScrollLeft : 0; + } + const fileJson = { id: file.id, uri: file.uri, @@ -24,13 +58,13 @@ export default () => { readOnly: file.readOnly, SAFMode: file.SAFMode, deletedFile: file.deletedFile, - cursorPos: editor.getCursorPosition(), - scrollTop: editor.session.getScrollTop(), - scrollLeft: editor.session.getScrollLeft(), + cursorPos, + scrollTop, + scrollLeft, editable: file.editable, encoding: file.encoding, - render: activeFile.id === file.id, - folds: parseFolds(file.session.getAllFolds()), + render: activeFile?.id === file.id, + folds: getAllFolds(file.session), }; if (settings.rememberFiles || fileJson.isUnsaved) @@ -55,20 +89,3 @@ export default () => { localStorage.files = JSON.stringify(filesToSave); localStorage.folders = JSON.stringify(folders); }; - -function parseFolds(folds) { - if (!Array.isArray(folds)) return []; - - return folds - .map((fold) => { - if (!fold || !fold.range) return null; - - const { range, ranges, placeholder } = fold; - return { - range, - ranges: parseFolds(ranges || []), - placeholder, - }; - }) - .filter(Boolean); -} diff --git a/src/lib/selectionMenu.js b/src/lib/selectionMenu.js index 8e7fea58b..daa64e6cc 100644 --- a/src/lib/selectionMenu.js +++ b/src/lib/selectionMenu.js @@ -10,6 +10,20 @@ const exec = (command) => { editor.focus(); }; +const showCodeActions = async () => { + const { editor } = editorManager; + if (!editor) return; + + try { + const { showCodeActionsMenu, supportsCodeActions } = await import("cm/lsp"); + if (supportsCodeActions(editor)) { + await showCodeActionsMenu(editor); + } + } catch (error) { + console.warn("[SelectionMenu] Code actions not available:", error); + } +}; + const items = []; export default function selectionMenu() { @@ -33,6 +47,12 @@ export default function selectionMenu() { , "all", ), + item( + () => showCodeActions(), + , + "all", + true, + ), ...items, ]; } diff --git a/src/lib/settings.js b/src/lib/settings.js index 4d6424c84..507f943ef 100644 --- a/src/lib/settings.js +++ b/src/lib/settings.js @@ -113,6 +113,7 @@ class Settings { autosave: 0, fileBrowser: this.#fileBrowserSettings, formatter: {}, + prettier: {}, maxFileSize: 12, serverPort: constants.SERVER_PORT, previewPort: constants.PREVIEW_PORT, @@ -124,7 +125,7 @@ class Settings { search: this.#searchSettings, lang: "en-us", fontSize: "12px", - editorTheme: "ace/theme/nord_dark", + editorTheme: "one_dark", textWrap: true, softTab: true, tabSize: 2, @@ -176,7 +177,12 @@ class Settings { showRetryToast: false, showSideButtons: true, showAnnotations: false, + lintGutter: true, + rainbowBrackets: true, pluginsDisabled: {}, // pluginId: true/false + lsp: { + servers: {}, + }, developerMode: false, }; this.value = structuredClone(this.#defaultSettings); diff --git a/src/main.js b/src/main.js index dea2e1cb9..9d493ee54 100644 --- a/src/main.js +++ b/src/main.js @@ -8,15 +8,16 @@ import "styles/overrideAceStyle.scss"; import "styles/wideScreen.scss"; import "lib/polyfill"; -import "ace/supportedModes"; +import "cm/supportedModes"; import "components/WebComponents"; import fsOperation from "fileSystem"; import sidebarApps from "sidebarApps"; import ajax from "@deadlyjack/ajax"; -import { setKeyBindings } from "ace/commands"; -import { initModes } from "ace/modelist"; +import { setKeyBindings } from "cm/commandRegistry"; +import { initModes } from "cm/modelist"; import Contextmenu from "components/contextmenu"; +import { hasConnectedServers } from "components/lspInfoDialog"; import Sidebar from "components/sidebar"; import { TerminalManager } from "components/terminal"; import tile from "components/tile"; @@ -40,6 +41,7 @@ import loadPlugins from "lib/loadPlugins"; import Logger from "lib/logger"; import NotificationManager from "lib/notificationManager"; import openFolder, { addedFolder } from "lib/openFolder"; +import { registerPrettierFormatter } from "lib/prettierFormatter"; import restoreFiles from "lib/restoreFiles"; import settings from "lib/settings"; import startAd from "lib/startAd"; @@ -48,6 +50,7 @@ import plugins from "pages/plugins"; import openWelcomeTab from "pages/welcome"; import otherSettings from "settings/appSettings"; import themes from "theme/list"; +import { initHighlighting } from "utils/codeHighlight"; import { getEncoding, initEncodings } from "utils/encodings"; import helpers from "utils/helpers"; import loadPolyFill from "utils/polyfill"; @@ -215,6 +218,9 @@ async function onDeviceReady() { acode.setLoadingMessage("Loading settings..."); await settings.init(); themes.init(); + initHighlighting(); + + registerPrettierFormatter(); acode.setLoadingMessage("Loading language..."); await lang.set(settings.value.lang); @@ -471,7 +477,7 @@ async function loadApp() { $sidebar.onshow = () => { const activeFile = editorManager.activeFile; - if (activeFile) editorManager.editor.blur(); + if (activeFile) editorManager.editor.contentDOM.blur(); }; sdcard.watchFile(KEYBINDING_FILE, async () => { await setKeyBindings(editorManager.editor); @@ -621,7 +627,8 @@ function onClickApp(e) { function mainPageOnShow() { const { editor } = editorManager; - editor.resize(true); + // TODO : Codemirror + //editor.resize(true); } function createMainMenu({ top, bottom, toggler }) { @@ -658,17 +665,19 @@ function createFileMenu({ top, bottom, toggler }) { const { label: encoding } = getEncoding(file.encoding); const isEditorFile = file.type === "editor"; + const cmEditor = window.editorManager?.editor; + const hasSelection = !!cmEditor && !cmEditor.state.selection.main.empty; return mustache.render($_fileMenu, { ...strings, - file_mode: isEditorFile - ? (file.session?.getMode()?.$id || "").split("/").pop() - : "", + // Use CodeMirror mode stored on EditorFile (set in setMode) + file_mode: isEditorFile ? file.currentMode || "" : "", file_encoding: isEditorFile ? encoding : "", file_read_only: !file.editable, file_on_disk: !!file.uri, file_eol: isEditorFile ? file.eol : "", - copy_text: !!window.editorManager.editor.getCopyText(), + copy_text: isEditorFile ? hasSelection : false, is_editor: isEditorFile, + has_lsp_servers: isEditorFile && hasConnectedServers(), }); }, }); diff --git a/src/main.scss b/src/main.scss index 8d0f5fa39..1f21cfeb2 100644 --- a/src/main.scss +++ b/src/main.scss @@ -4,6 +4,7 @@ @use "./styles/keyframes.scss"; @use "./styles/fileInfo.scss"; @use "./styles/markdown.scss"; +@use "./styles/codemirror.scss"; :root { --scrollbar-width: 4px; diff --git a/src/pages/plugin/plugin.js b/src/pages/plugin/plugin.js index f4fb544f5..8407423ea 100644 --- a/src/pages/plugin/plugin.js +++ b/src/pages/plugin/plugin.js @@ -15,6 +15,7 @@ import anchor from "markdown-it-anchor"; import markdownItFootnote from "markdown-it-footnote"; import MarkdownItGitHubAlerts from "markdown-it-github-alerts"; import markdownItTaskLists from "markdown-it-task-lists"; +import { highlightCodeBlock, initHighlighting } from "utils/codeHighlight"; import helpers from "utils/helpers"; import Url from "utils/Url"; import view from "./plugin.view.js"; @@ -405,7 +406,10 @@ export default async function PluginInclude( ); }); - // add copy button to code blocks + // Initialize theme-aware highlight styles + initHighlighting(); + + // Add copy button and syntax highlighting to code blocks const codeBlocks = $page.body.querySelectorAll("pre"); codeBlocks.forEach((pre) => { pre.style.position = "relative"; @@ -415,22 +419,16 @@ export default async function PluginInclude( const codeElement = pre.querySelector("code"); if (codeElement) { - const langMatch = codeElement.className.match( - /language-(\w+)|(javascript)/, - ); + const langMatch = codeElement.className.match(/language-(\w+)/); if (langMatch) { - const langMap = { - bash: "sh", - shell: "sh", - }; - const lang = langMatch[1] || langMatch[2]; - const mappedLang = langMap[lang] || lang; - const highlight = ace.require("ace/ext/static_highlight"); - highlight(codeElement, { - mode: `ace/mode/${mappedLang}`, - theme: settings.value.editorTheme.startsWith("ace/theme/") - ? settings.value.editorTheme - : "ace/theme/" + settings.value.editorTheme, + const lang = langMatch[1]; + const originalCode = codeElement.textContent || ""; + codeElement.classList.add("cm-highlighted"); + + highlightCodeBlock(originalCode, lang).then((highlighted) => { + if (highlighted && highlighted !== originalCode) { + codeElement.innerHTML = highlighted; + } }); } } diff --git a/src/pages/plugin/plugin.scss b/src/pages/plugin/plugin.scss index cc2284d0e..b99ace95f 100644 --- a/src/pages/plugin/plugin.scss +++ b/src/pages/plugin/plugin.scss @@ -238,24 +238,24 @@ padding: 0 0 24px; #overview { - [class*="language-"] { - word-wrap: normal; - white-space: pre; - font-size: 0.8rem; - border-radius: 4px; - padding: 1em; - margin: 5px 0; - background: var(--primary-color); - color: var(--primary-text-color); - /* border-left: solid 5px var(--active-color); */ - overflow: auto; - width: calc(100% - 10px); + pre { + margin: 16px 0; + border-radius: 8px; + overflow: hidden; + } + + code[class*="language-"] { display: block; + font-size: 13px; + line-height: 1.5; + padding: 16px; + margin: 0; + overflow-x: auto; + white-space: pre; + word-wrap: normal; + tab-size: 2; user-select: text; - - div { - background: var(--primary-color); - } + -webkit-overflow-scrolling: touch; } } } diff --git a/src/pages/problems/problems.js b/src/pages/problems/problems.js index b3d9d5a3c..e79e6289d 100644 --- a/src/pages/problems/problems.js +++ b/src/pages/problems/problems.js @@ -1,4 +1,5 @@ import "./style.scss"; +import { getLspDiagnostics } from "cm/lsp/diagnostics"; import Page from "components/page"; import actionStack from "lib/actionStack"; import EditorFile from "lib/editorFile"; @@ -12,29 +13,17 @@ export default function Problems() { files.forEach((file) => { if (file.type !== "editor") return; - /**@type {[]} */ - const annotations = file.session?.getAnnotations(); + const annotations = collectAnnotations(file); if (!annotations.length) return; + const title = `${file.name} (${annotations.length})`; $content.append(
    - {`${file.name} (${annotations.length})`} + {title}
    {annotations.map((annotation) => { - let icon = "info"; - - switch (annotation.type) { - case "error": - icon = "cancel"; - break; - - case "warning": - icon = "warningreport_problem"; - break; - - default: - break; - } + const { type, text, row, column } = annotation; + const icon = getIconForType(type); return (
    - - {annotation.text} + + {text} - {annotation.row + 1}:{annotation.column + 1} + {row + 1}:{column + 1}
    ); @@ -78,15 +67,19 @@ export default function Problems() { * @param {MouseEvent} e */ function clickHandler(e) { - const $target = e.target; + const $target = e.target.closest("[data-action='goto']"); + if (!$target) return; const { action } = $target.dataset; if (action === "goto") { const { fileId } = $target.dataset; const annotation = $target.annotation; + if (!annotation) return; + const row = normalizeIndex(annotation.row); + const column = normalizeIndex(annotation.column); editorManager.switchFile(fileId); - editorManager.editor.gotoLine(annotation.row + 1, annotation.column); + editorManager.editor.gotoLine(row + 1, column); $page.hide(); setTimeout(() => { @@ -94,4 +87,110 @@ export default function Problems() { }, 100); } } + + function collectAnnotations(file) { + const annotations = []; + const { session } = file; + const isActiveFile = editorManager.activeFile?.id === file.id; + const state = + isActiveFile && editorManager.editor + ? editorManager.editor.state + : session; + + if (session && typeof session.getAnnotations === "function") { + const aceAnnotations = session.getAnnotations() || []; + for (const item of aceAnnotations) { + if (!item) continue; + const row = normalizeIndex(item.row); + const column = normalizeIndex(item.column); + annotations.push({ + row, + column, + text: item.text || "", + type: normalizeSeverity(item.type), + }); + } + } + + if (state && typeof state.field === "function") { + annotations.push(...readLspAnnotations(state)); + } + + return annotations; + } + + function readLspAnnotations(state) { + const diagnostics = getLspDiagnostics(state); + if (!diagnostics.length) return []; + + const doc = state.doc; + if (!doc || typeof doc.lineAt !== "function") return []; + + return diagnostics + .map((diagnostic) => { + const start = clampPosition(diagnostic.from, doc.length); + let row = 0; + let column = 0; + try { + const line = doc.lineAt(start); + row = Math.max(0, line.number - 1); + column = Math.max(0, start - line.from); + } catch (_) {} + + let message = diagnostic.message || ""; + if (diagnostic.source) { + message = message + ? `${message} (${diagnostic.source})` + : diagnostic.source; + } + + return { + row: normalizeIndex(row), + column: normalizeIndex(column), + text: message, + type: normalizeSeverity(diagnostic.severity), + }; + }) + .filter((annotation) => annotation.text); + } + + function clampPosition(pos, length) { + if (typeof pos !== "number" || Number.isNaN(pos)) return 0; + return Math.max(0, Math.min(pos, Math.max(0, length))); + } + + function normalizeIndex(value) { + if (typeof value === "number" && Number.isFinite(value)) { + return Math.max(0, value); + } + const parsed = Number(value); + if (Number.isFinite(parsed)) { + return Math.max(0, parsed); + } + return 0; + } + + function normalizeSeverity(severity) { + switch (severity) { + case "error": + case "fatal": + return "error"; + case "warn": + case "warning": + return "warning"; + default: + return "info"; + } + } + + function getIconForType(type) { + switch (type) { + case "error": + return "cancel"; + case "warning": + return "warningreport_problem"; + default: + return "info"; + } + } } diff --git a/src/pages/themeSetting/themeSetting.js b/src/pages/themeSetting/themeSetting.js index 671f023d3..836a3bf5b 100644 --- a/src/pages/themeSetting/themeSetting.js +++ b/src/pages/themeSetting/themeSetting.js @@ -1,4 +1,10 @@ import "./themeSetting.scss"; +import { javascript } from "@codemirror/lang-javascript"; +// For CodeMirror preview +import { EditorState } from "@codemirror/state"; +import { oneDark } from "@codemirror/theme-one-dark"; +import { getThemeExtensions, getThemes } from "cm/themes"; +import { basicSetup, EditorView } from "codemirror"; import Page from "components/page"; import searchBar from "components/searchbar"; import TabView from "components/tabView"; @@ -15,33 +21,39 @@ import helpers from "utils/helpers"; export default function () { const $page = Page(strings.theme.capitalize()); const $search = ; - const $themePreview =
    ; + const $themePreview = ( +
    + ); const list = new Ref(); - const editor = ace.edit($themePreview); - - const session = ace.createEditSession(""); - const activeFile = editorManager.activeFile; - - if (activeFile && activeFile.type === "editor") { - const currentSession = activeFile.session; - session.setMode(currentSession.getMode()); - session.setValue(currentSession.getValue()); - } else { - // Fallback content for preview - session.setMode("ace/mode/javascript"); - session.setValue(`// Acode is awesome! -const message = "Welcome to Acode"; -console.log(message);`); + let cmPreview = null; + const previewDoc = `// Acode is awesome!\nconst message = "Welcome to Acode";\nconsole.log(message);`; + function createPreview(themeId) { + if (cmPreview) { + cmPreview.destroy(); + cmPreview = null; + } + const theme = getThemeExtensions(themeId, [oneDark]); + const fixedHeightTheme = EditorView.theme({ + "&": { height: "100%", flex: "1 1 auto" }, + ".cm-scroller": { height: "100%", overflow: "auto" }, + }); + const state = EditorState.create({ + doc: previewDoc, + extensions: [basicSetup, javascript(), fixedHeightTheme, ...theme], + }); + cmPreview = new EditorView({ state, parent: $themePreview }); + cmPreview.contentDOM.setAttribute("aria-readonly", "true"); } - editor.setReadOnly(true); - editor.setSession(session); - editor.renderer.setMargin(0, 0, -16, 0); - actionStack.push({ id: "appTheme", action: () => { - editor.destroy(); + try { + cmPreview?.destroy(); + } catch (_) {} $page.hide(); $page.removeEventListener("click", clickHandler); }, @@ -74,6 +86,10 @@ console.log(message);`); $page.addEventListener("click", clickHandler); function renderAppThemes() { + // Remove and destroy CodeMirror preview when showing app themes + try { + cmPreview?.destroy(); + } catch (_) {} $themePreview.remove(); const content = []; @@ -111,30 +127,26 @@ console.log(message);`); } function renderEditorThemes() { - const currentTheme = appSettings.value.editorTheme; - const themePrefix = "ace/theme/"; - const fullThemePath = currentTheme.startsWith(themePrefix) - ? currentTheme - : themePrefix + currentTheme; - - editor.setTheme(fullThemePath); + const currentTheme = ( + appSettings.value.editorTheme || "one_dark" + ).toLowerCase(); if (innerHeight * 0.3 >= 120) { $page.body.append($themePreview); - editor.resize(); + createPreview(currentTheme); } else { $themePreview.remove(); } - const themeList = ace.require("ace/ext/themelist"); + const themeList = getThemes(); let $currentItem; - list.el.content = themeList.themes.map((theme) => { - const isCurrent = theme.theme === fullThemePath; + list.el.content = themeList.map((t) => { + const isCurrent = t.id === currentTheme; const $item = ( setEditorTheme(theme)} + isDark={t.isDark} + onclick={() => setEditorTheme({ caption: t.caption, theme: t.id })} /> ); if (isCurrent) $currentItem = $item; @@ -201,8 +213,15 @@ console.log(message);`); ); return; } - editorManager.editor.setTheme(theme); - editor.setTheme(theme); // preview + const ok = editorManager.editor.setTheme(theme); + if (!ok) { + alert( + "Invalid theme", + "This editor theme is not compatible with Acode's CodeMirror runtime.", + ); + return; + } + if (cmPreview) createPreview(theme); appSettings.update( { editorTheme: theme, @@ -222,8 +241,8 @@ console.log(message);`); } function Item({ name, color, isDark, onclick, isCurrent, isPremium }) { - const check = ; - const star = ; + const check = ; + const star = ; let style = {}; let className = "icon color"; diff --git a/src/palettes/changeEditorTheme/index.js b/src/palettes/changeEditorTheme/index.js new file mode 100644 index 000000000..3f2b71b1c --- /dev/null +++ b/src/palettes/changeEditorTheme/index.js @@ -0,0 +1,28 @@ +import { getThemes } from "cm/themes"; +import palette from "components/palette"; +import appSettings from "lib/settings"; + +export default function changeEditorTheme() { + palette(generateHints, onselect, strings["editor theme"]); +} + +function generateHints() { + const themes = getThemes(); + const current = String( + appSettings.value.editorTheme || "one_dark", + ).toLowerCase(); + return themes.map((t) => { + const isCurrent = current === t.id; + return { + value: t.id, + text: `
    ${t.caption}${isCurrent ? 'current' : ""}
    `, + }; + }); +} + +function onselect(themeId) { + if (!themeId) return; + const ok = editorManager.editor.setTheme(themeId); + if (!ok) return; + appSettings.update({ editorTheme: themeId }, false); +} diff --git a/src/palettes/changeMode/index.js b/src/palettes/changeMode/index.js index c2e3e2d96..cd299fa61 100644 --- a/src/palettes/changeMode/index.js +++ b/src/palettes/changeMode/index.js @@ -1,3 +1,4 @@ +import { getModes } from "cm/modelist"; import palette from "components/palette"; import Path from "utils/Path"; @@ -6,7 +7,7 @@ export default function changeMode() { } function generateHints() { - const { modes } = ace.require("ace/ext/modelist"); + const modes = getModes(); return modes.map(({ caption, mode, extensions }) => { return { diff --git a/src/palettes/changeTheme/index.js b/src/palettes/changeTheme/index.js index be76c6fa7..d42294c4e 100644 --- a/src/palettes/changeTheme/index.js +++ b/src/palettes/changeTheme/index.js @@ -4,37 +4,19 @@ import appSettings from "lib/settings"; import { isDeviceDarkTheme } from "lib/systemConfiguration"; import themes from "theme/list"; import { updateSystemTheme } from "theme/preInstalled"; +import changeEditorTheme from "../changeEditorTheme"; export default function changeTheme(type = "editor") { + if (type === "editor") return changeEditorTheme(); palette( () => generateHints(type), (value) => onselect(value), - strings[type === "editor" ? "editor theme" : "app theme"], + strings["app theme"], ); } function generateHints(type) { - if (type === "editor") { - const themeList = ace.require("ace/ext/themelist"); - const currentTheme = appSettings.value.editorTheme; - const themePrefix = "ace/theme/"; - - return themeList.themes.map((theme) => { - const isCurrent = - theme.theme === - (currentTheme.startsWith(themePrefix) - ? currentTheme - : themePrefix + currentTheme); - - return { - value: JSON.stringify({ type: "editor", theme: theme.theme }), - text: `
    - ${theme.caption} - ${isCurrent ? 'current' : ""} -
    `, - }; - }); - } + // Editor handled by changeEditorTheme // App themes const currentTheme = appSettings.value.appTheme; diff --git a/src/palettes/commandPalette/index.js b/src/palettes/commandPalette/index.js index e3cb90e46..92ae750f5 100644 --- a/src/palettes/commandPalette/index.js +++ b/src/palettes/commandPalette/index.js @@ -1,44 +1,39 @@ +import { executeCommand, getRegisteredCommands } from "cm/commandRegistry"; import palette from "components/palette"; import helpers from "utils/helpers"; export default async function commandPalette() { const recentCommands = RecentlyUsedCommands(); const { editor } = editorManager; - const commands = Object.values(editor.commands.commands); - - const isEditorFocused = editor.isFocused(); + const wasFocused = editor?.hasFocus ?? false; palette(generateHints, onselect, strings["type command"], () => { - if (isEditorFocused) editor.focus(); + if (wasFocused) editor?.focus(); }); function generateHints() { + const registeredCommands = getRegisteredCommands(); const hints = []; - commands.forEach(({ name, description, bindKey }) => { - /** - * @param {boolean} recentlyUsed Is the command recently used - * @returns {{value: string, text: string}} - */ + registeredCommands.forEach(({ name, description, key }) => { + const keyLabel = key ? key.split("|")[0] : ""; const item = (recentlyUsed) => ({ value: name, - text: `${description ?? name}${bindKey?.win ?? ""}`, + text: `${description ?? name}${keyLabel}`, }); if (recentCommands.commands.includes(name)) { hints.unshift(item(true)); return; } - hints.push(item()); + hints.push(item(false)); }); return hints; } function onselect(value) { - const command = commands.find(({ name }) => name === value); - if (!command) return; - recentCommands.push(value); - command.exec(editorManager.editor); + const executed = executeCommand(value, editorManager.editor); + if (executed) recentCommands.push(value); } } diff --git a/src/plugins/system/android/com/foxdebug/system/System.java b/src/plugins/system/android/com/foxdebug/system/System.java index 7ddf6c547..dd69542b8 100644 --- a/src/plugins/system/android/com/foxdebug/system/System.java +++ b/src/plugins/system/android/com/foxdebug/system/System.java @@ -114,6 +114,14 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { this.context = cordova.getContext(); this.activity = cordova.getActivity(); this.webView = webView; + this.activity.runOnUiThread( + new Runnable() { + @Override + public void run() { + setNativeContextMenuDisabled(true); + } + } + ); // Set up global exception handler Thread.setDefaultUncaughtExceptionHandler( @@ -182,6 +190,18 @@ public boolean execute( setInputType(arg1); callbackContext.success(); return true; + case "set-native-context-menu-disabled": + this.cordova.getActivity() + .runOnUiThread( + new Runnable() { + @Override + public void run() { + setNativeContextMenuDisabled(Boolean.parseBoolean(arg1)); + callbackContext.success(); + } + } + ); + return true; case "get-cordova-intent": getCordovaIntent(callbackContext); return true; @@ -1695,4 +1715,30 @@ private void setInputType(String type) { } webView.setInputType(mode); } + + private void setNativeContextMenuDisabled(boolean disabled) { + View webViewView = webView == null ? null : webView.getView(); + if (webViewView == null) { + return; + } + + webViewView.setLongClickable(!disabled); + webViewView.setHapticFeedbackEnabled(!disabled); + if (disabled) { + webViewView.setOnLongClickListener(v -> true); + } else { + webViewView.setOnLongClickListener(null); + } + + try { + Method method = webViewView + .getClass() + .getMethod("setNativeContextMenuDisabled", boolean.class); + method.invoke(webViewView, disabled); + } catch (NoSuchMethodException ignored) { + // Fallback above keeps long-press context disabled even without CordovaLib patch. + } catch (IllegalAccessException | InvocationTargetException e) { + Log.w("System", "Failed to toggle native context menu state", e); + } + } } diff --git a/src/plugins/system/system.d.ts b/src/plugins/system/system.d.ts index 05b1a9888..69b63412d 100644 --- a/src/plugins/system/system.d.ts +++ b/src/plugins/system/system.d.ts @@ -234,8 +234,20 @@ interface System { * @param onSuccess * @param onFail */ - getCordovaIntent(onSuccess: (intent: Intent) => void, onFail: OnFail): void; -} + getCordovaIntent(onSuccess: (intent: Intent) => void, onFail: OnFail): void; + /** + * Enable/disable native WebView long-press context behavior. + * Use this when rendering a custom editor context menu. + * @param disabled + * @param onSuccess + * @param onFail + */ + setNativeContextMenuDisabled( + disabled: boolean, + onSuccess?: () => void, + onFail?: OnFail, + ): void; +} interface Window{ system: System; diff --git a/src/plugins/system/www/plugin.js b/src/plugins/system/www/plugin.js index 7831b3b09..42389c8a7 100644 --- a/src/plugins/system/www/plugin.js +++ b/src/plugins/system/www/plugin.js @@ -150,12 +150,21 @@ module.exports = { getCordovaIntent: function (onSuccess, onFail) { cordova.exec(onSuccess, onFail, 'System', 'get-cordova-intent', []); }, - setInputType: function (type, onSuccess, onFail) { - cordova.exec(onSuccess, onFail, 'System', 'set-input-type', [type]); - }, - getGlobalSetting: function (key, onSuccess, onFail) { - cordova.exec(onSuccess, onFail, 'System', 'get-global-setting', [key]); - }, + setInputType: function (type, onSuccess, onFail) { + cordova.exec(onSuccess, onFail, 'System', 'set-input-type', [type]); + }, + setNativeContextMenuDisabled: function (disabled, onSuccess, onFail) { + cordova.exec( + onSuccess, + onFail, + 'System', + 'set-native-context-menu-disabled', + [String(!!disabled)], + ); + }, + getGlobalSetting: function (key, onSuccess, onFail) { + cordova.exec(onSuccess, onFail, 'System', 'get-global-setting', [key]); + }, /** * Compare file content with provided text in a background thread. * @param {string} fileUri - The URI of the file to read @@ -195,4 +204,4 @@ module.exports = { ); }); } -}; \ No newline at end of file +}; diff --git a/src/res/icons/li-icon.ttf b/src/res/icons/li-icon.ttf index 6627c9325..5b218bf3c 100644 Binary files a/src/res/icons/li-icon.ttf and b/src/res/icons/li-icon.ttf differ diff --git a/src/res/icons/style.css b/src/res/icons/style.css index cae1ff314..c48079160 100644 --- a/src/res/icons/style.css +++ b/src/res/icons/style.css @@ -43,6 +43,10 @@ -moz-osx-font-smoothing: grayscale; } +.licons.lightbulb:before { + content: "\f004"; +} + .licons.scale:before { content: "\f006"; } @@ -1217,4 +1221,4 @@ .icon.all_inclusive:before { content: "\ea18"; -} \ No newline at end of file +} diff --git a/src/settings/appSettings.js b/src/settings/appSettings.js index 2dea46a51..d1c74294b 100644 --- a/src/settings/appSettings.js +++ b/src/settings/appSettings.js @@ -1,6 +1,6 @@ import fsOperation from "fileSystem"; import ajax from "@deadlyjack/ajax"; -import { resetKeyBindings } from "ace/commands"; +import { resetKeyBindings } from "cm/commandRegistry"; import settingsPage from "components/settingsPage"; import loader from "dialogs/loader"; import actions from "handlers/quickTools"; diff --git a/src/settings/editorSettings.js b/src/settings/editorSettings.js index 966efe57e..cc2d436ff 100644 --- a/src/settings/editorSettings.js +++ b/src/settings/editorSettings.js @@ -55,6 +55,11 @@ export default function editorSettings() { text: strings["show line numbers"], checkbox: values.linenumbers, }, + { + key: "lintGutter", + text: strings["lint gutter"] || "Show lint gutter", + checkbox: values.lintGutter ?? true, + }, { key: "lineHeight", text: strings["line height"], @@ -91,29 +96,29 @@ export default function editorSettings() { text: strings["live autocompletion"], checkbox: values.liveAutoCompletion, }, - { - key: "showPrintMargin", - text: strings["show print margin"], - checkbox: values.showPrintMargin, - }, + // { + // key: "showPrintMargin", + // text: strings["show print margin"].capitalize(), + // checkbox: values.showPrintMargin, + // }, + // { + // key: "printMargin", + // text: strings["print margin"], + // value: values.printMargin, + // prompt: strings["print margin"], + // promptType: "number", + // promptOptions: { + // test(value) { + // value = Number.parseInt(value); + // return value >= 10 && value <= 200; + // }, + // }, + // }, { key: "textWrap", text: strings["text wrap"], checkbox: values.textWrap, }, - { - key: "printMargin", - text: strings["print margin"], - value: values.printMargin, - prompt: strings["print margin"], - promptType: "number", - promptOptions: { - test(value) { - value = Number.parseInt(value); - return value >= 10 && value <= 200; - }, - }, - }, { key: "teardropSize", text: strings["cursor controller size"], @@ -133,11 +138,11 @@ export default function editorSettings() { text: strings["relative line numbers"], checkbox: values.relativeLineNumbers, }, - { - key: "elasticTabstops", - text: strings["elastic tabstops"], - checkbox: values.elasticTabstops, - }, + // { + // key: "elasticTabstops", + // text: strings["elastic tabstops"], + // checkbox: values.elasticTabstops, + // }, { key: "rtlText", text: strings["line based rtl switching"], @@ -148,16 +153,26 @@ export default function editorSettings() { text: strings["hard wrap"], checkbox: values.hardWrap, }, - { - key: "useTextareaForIME", - text: strings["use textarea for ime"], - checkbox: values.useTextareaForIME, - }, + // { + // key: "useTextareaForIME", + // text: strings["use textarea for ime"], + // checkbox: values.useTextareaForIME, + // }, { key: "fadeFoldWidgets", text: strings["fade fold widgets"], checkbox: values.fadeFoldWidgets, }, + { + key: "rainbowBrackets", + text: strings["rainbow brackets"] || "Rainbow brackets", + checkbox: values.rainbowBrackets ?? true, + }, + { + key: "indentGuides", + text: strings["indent guides"] || "Indent guides", + checkbox: values.indentGuides ?? true, + }, { index: 0, key: "scroll-settings", diff --git a/src/settings/formatterSettings.js b/src/settings/formatterSettings.js index 25dae3911..d59dc2c29 100644 --- a/src/settings/formatterSettings.js +++ b/src/settings/formatterSettings.js @@ -1,3 +1,4 @@ +import { getModes } from "cm/modelist"; import settingsPage from "components/settingsPage"; import appSettings from "lib/settings"; @@ -5,13 +6,16 @@ export default function formatterSettings(languageName) { const title = strings.formatter; const values = appSettings.value; const { formatters } = acode; - const { modes } = ace.require("ace/ext/modelist"); - const items = modes.map((mode) => { - const { name, caption } = mode; + // Build items from CodeMirror modelist + const items = getModes().map((mode) => { + const { name, caption, extensions } = mode; const formatterID = values.formatter[name] || null; - const extensions = mode.extensions.split("|"); - const options = acode.getFormatterFor(extensions); + // Only pass real extensions (skip anchored filename patterns like ^Dockerfile) + const extList = String(extensions) + .split("|") + .filter((e) => e && !e.startsWith("^")); + const options = acode.getFormatterFor(extList); return { key: name, diff --git a/src/settings/lspServerDetail.js b/src/settings/lspServerDetail.js new file mode 100644 index 000000000..05c161863 --- /dev/null +++ b/src/settings/lspServerDetail.js @@ -0,0 +1,319 @@ +import serverRegistry from "cm/lsp/serverRegistry"; +import settingsPage from "components/settingsPage"; +import toast from "components/toast"; +import alert from "dialogs/alert"; +import prompt from "dialogs/prompt"; +import appSettings from "lib/settings"; + +/** + * Get the current override settings for a server + * @param {string} id Server ID + * @returns {object} Override settings object + */ +function getServerOverride(id) { + return appSettings.value?.lsp?.servers?.[id] || {}; +} + +/** + * Merge server definition with user overrides + * @param {object} server Server definition from registry + * @returns {object} Merged server configuration + */ +function getMergedConfig(server) { + const override = getServerOverride(server.id); + return { + ...server, + enabled: override.enabled ?? server.enabled, + startupTimeout: override.startupTimeout ?? server.startupTimeout, + initializationOptions: { + ...(server.initializationOptions || {}), + ...(override.initializationOptions || {}), + }, + clientConfig: { + ...(server.clientConfig || {}), + ...(override.clientConfig || {}), + builtinExtensions: { + ...(server.clientConfig?.builtinExtensions || {}), + ...(override.clientConfig?.builtinExtensions || {}), + }, + }, + }; +} + +/** + * Update LSP server configuration in app settings + * @param {string} serverId Server ID + * @param {object} partial Partial configuration to update + */ +async function updateServerConfig(serverId, partial) { + const current = JSON.parse(JSON.stringify(appSettings.value.lsp || {})); + current.servers = current.servers || {}; + const nextServer = { + ...(current.servers[serverId] || {}), + }; + + Object.entries(partial || {}).forEach(([key, value]) => { + if (value === undefined) { + delete nextServer[key]; + return; + } + nextServer[key] = value; + }); + + if (Object.keys(nextServer).length) { + current.servers[serverId] = nextServer; + } else { + delete current.servers[serverId]; + } + + await appSettings.update({ lsp: current }, false); +} + +/** + * LSP Server detail settings page + * @param {string} serverId - The server ID to show settings for + * @returns {import('components/settingsPage').SettingsPage} + */ +export default function lspServerDetail(serverId) { + const server = serverRegistry.getServer(serverId); + if (!server) { + toast("Server not found"); + return null; + } + + const merged = getMergedConfig(server); + const title = server.label || server.id; + + const items = []; + const builtinExts = merged.clientConfig?.builtinExtensions || {}; + + // Server enable/disable + items.push({ + key: "enabled", + text: "Enabled", + checkbox: merged.enabled, + info: "Enable or disable this language server", + }); + + // Feature toggles + items.push({ + key: "ext_hover", + text: "Hover Information", + checkbox: builtinExts.hover !== false, + info: "Show type information and documentation on hover", + }); + + items.push({ + key: "ext_completion", + text: "Code Completion", + checkbox: builtinExts.completion !== false, + info: "Enable autocomplete suggestions from the server", + }); + + items.push({ + key: "ext_signature", + text: "Signature Help", + checkbox: builtinExts.signature !== false, + info: "Show function parameter hints while typing", + }); + + items.push({ + key: "ext_diagnostics", + text: "Diagnostics", + checkbox: builtinExts.diagnostics !== false, + info: "Show errors and warnings from the language server", + }); + + items.push({ + key: "ext_inlayHints", + text: "Inlay Hints", + checkbox: builtinExts.inlayHints !== false, + info: "Show inline type hints in the editor", + }); + + items.push({ + key: "ext_documentHighlights", + text: "Document Highlights", + checkbox: builtinExts.documentHighlights !== false, + info: "Highlight all occurrences of the word under cursor", + }); + + items.push({ + key: "ext_formatting", + text: "Formatting", + checkbox: builtinExts.formatting !== false, + info: "Enable code formatting from the language server", + }); + + if (server.launcher?.install?.command) { + items.push({ + key: "view_install", + text: "View Install Command", + info: "View the command to install this language server", + }); + } + + // Advanced options + items.push({ + key: "view_init_options", + text: "View Initialization Options", + info: "View the server initialization options as JSON", + }); + + items.push({ + key: "edit_startup_timeout", + text: "Startup Timeout", + info: + typeof merged.startupTimeout === "number" + ? `${merged.startupTimeout} ms` + : "Default (5000 ms)", + }); + + items.push({ + key: "edit_init_options", + text: "Edit Initialization Options", + info: "Edit custom initialization options (JSON)", + }); + + return settingsPage(title, items, callback, undefined, { + preserveOrder: true, + }); + + async function callback(key, value) { + const override = getServerOverride(serverId); + + switch (key) { + case "enabled": + await updateServerConfig(serverId, { enabled: value }); + // Update the registry so client manager picks it up + serverRegistry.updateServer(serverId, (current) => ({ + ...current, + enabled: value, + })); + toast(value ? "Server enabled" : "Server disabled"); + break; + + case "ext_hover": + case "ext_completion": + case "ext_signature": + case "ext_diagnostics": + case "ext_inlayHints": + case "ext_documentHighlights": + case "ext_formatting": { + const extKey = key.replace("ext_", ""); + const currentClientConfig = override.clientConfig || {}; + const currentBuiltins = currentClientConfig.builtinExtensions || {}; + + await updateServerConfig(serverId, { + clientConfig: { + ...currentClientConfig, + builtinExtensions: { + ...currentBuiltins, + [extKey]: value, + }, + }, + }); + toast(`${extKey} ${value ? "enabled" : "disabled"}`); + break; + } + + case "view_install": + if (server.launcher?.install?.command) { + alert("Install Command", server.launcher.install.command); + } + break; + + case "view_init_options": { + const initOpts = merged.initializationOptions || {}; + const json = JSON.stringify(initOpts, null, 2); + alert( + "Initialization Options", + `
    ${escapeHtml(json)}
    `, + ); + break; + } + + case "edit_startup_timeout": { + const currentTimeout = + override.startupTimeout ?? server.startupTimeout ?? 5000; + const result = await prompt( + "Startup Timeout (milliseconds)", + String(currentTimeout), + "number", + { + test: (val) => { + const timeout = Number.parseInt(String(val), 10); + return Number.isFinite(timeout) && timeout >= 1000; + }, + }, + ); + + if (result !== null) { + const timeout = Number.parseInt(String(result), 10); + if (!Number.isFinite(timeout) || timeout < 1000) { + toast("Invalid timeout value"); + break; + } + + await updateServerConfig(serverId, { + startupTimeout: timeout, + }); + serverRegistry.updateServer(serverId, (current) => ({ + ...current, + startupTimeout: timeout, + })); + toast(`Startup timeout set to ${timeout} ms`); + } + break; + } + + case "edit_init_options": { + const currentInitOpts = override.initializationOptions || {}; + const currentJson = JSON.stringify(currentInitOpts, null, 2); + + try { + const result = await prompt( + "Initialization Options (JSON)", + currentJson || "{}", + "textarea", + { + test: (val) => { + try { + JSON.parse(val); + return true; + } catch { + return false; + } + }, + }, + ); + + if (result !== null) { + const parsed = JSON.parse(result); + await updateServerConfig(serverId, { + initializationOptions: parsed, + }); + toast("Initialization options updated"); + } + } catch (error) { + toast("Invalid JSON"); + } + break; + } + + default: + break; + } + } +} + +/** + * Escape HTML entities + * @param {string} text + * @returns {string} + */ +function escapeHtml(text) { + const div = document.createElement("div"); + div.textContent = text; + return div.innerHTML; +} diff --git a/src/settings/lspSettings.js b/src/settings/lspSettings.js new file mode 100644 index 000000000..d542ad7e8 --- /dev/null +++ b/src/settings/lspSettings.js @@ -0,0 +1,66 @@ +import serverRegistry from "cm/lsp/serverRegistry"; +import settingsPage from "components/settingsPage"; +import appSettings from "lib/settings"; +import lspServerDetail from "./lspServerDetail"; + +/** + * Get the current override settings for a server + * @param {string} id Server ID + * @returns {object} Override settings object + */ +function getServerOverride(id) { + return appSettings.value?.lsp?.servers?.[id] || {}; +} + +/** + * LSP Settings page - shows list of all language servers + * @returns {object} Settings page interface + */ +export default function lspSettings() { + const title = strings?.lsp_settings || "Language Servers"; + const servers = serverRegistry.listServers(); + + // Sort: enabled servers first, then alphabetically + const sortedServers = servers.sort((a, b) => { + const aEnabled = getServerOverride(a.id).enabled ?? a.enabled; + const bEnabled = getServerOverride(b.id).enabled ?? b.enabled; + + if (aEnabled !== bEnabled) { + return bEnabled ? 1 : -1; + } + return a.label.localeCompare(b.label); + }); + + const items = []; + + for (const server of sortedServers) { + // Languages info + const languagesList = + Array.isArray(server.languages) && server.languages.length + ? server.languages.join(", ") + : ""; + + items.push({ + key: `server:${server.id}`, + text: server.label, + info: languagesList || undefined, + }); + } + + // Add note + items.push({ + note: "Language servers provide IDE features like autocomplete, diagnostics, and hover information. Enable a server for the languages you work with. Make sure the terminal is installed and the server is installed in the proot environment.", + }); + + return settingsPage(title, items, callback); + + function callback(key) { + if (key.startsWith("server:")) { + const id = key.split(":")[1]; + const detailPage = lspServerDetail(id); + if (detailPage) { + detailPage.show(); + } + } + } +} diff --git a/src/settings/mainSettings.js b/src/settings/mainSettings.js index 3df4c3dfc..859e7cef9 100644 --- a/src/settings/mainSettings.js +++ b/src/settings/mainSettings.js @@ -17,6 +17,7 @@ import backupRestore from "./backupRestore"; import editorSettings from "./editorSettings"; import filesSettings from "./filesSettings"; import formatterSettings from "./formatterSettings"; +import lspSettings from "./lspSettings"; import previewSettings from "./previewSettings"; import scrollSettings from "./scrollSettings"; import searchSettings from "./searchSettings"; @@ -93,6 +94,12 @@ export default function mainSettings() { icon: "licons terminal", index: 5, }, + { + key: "lsp-settings", + text: strings?.lsp_settings || "Language servers", + icon: "licons zap", + index: 7, + }, { key: "editSettings", text: `${strings["edit"]} settings.json`, @@ -125,6 +132,7 @@ export default function mainSettings() { case "editor-settings": case "preview-settings": case "terminal-settings": + case "lsp-settings": appSettings.uiSettings[key].show(); break; @@ -199,4 +207,5 @@ export default function mainSettings() { appSettings.uiSettings["search-settings"] = searchSettings(); appSettings.uiSettings["preview-settings"] = previewSettings(); appSettings.uiSettings["terminal-settings"] = terminalSettings(); + appSettings.uiSettings["lsp-settings"] = lspSettings(); } diff --git a/src/settings/scrollSettings.js b/src/settings/scrollSettings.js index ca3ab78b9..1edaa489f 100644 --- a/src/settings/scrollSettings.js +++ b/src/settings/scrollSettings.js @@ -7,7 +7,7 @@ export default function scrollSettings() { const title = strings["scroll settings"]; const items = [ - { + /*{ key: "scrollSpeed", text: strings["scroll speed"], value: values.scrollSpeed, @@ -18,17 +18,17 @@ export default function scrollSettings() { [constants.SCROLL_SPEED_NORMAL, strings.normal], [constants.SCROLL_SPEED_SLOW, strings.slow], ], - }, - { + },*/ + /*{ key: "reverseScrolling", text: strings["reverse scrolling"], checkbox: values.reverseScrolling, - }, - { + },*/ + /*{ key: "diagonalScrolling", text: strings["diagonal scrolling"], checkbox: values.diagonalScrolling, - }, + },*/ { key: "scrollbarSize", text: strings["scrollbar size"], diff --git a/src/sidebarApps/searchInFiles/cmResultView.js b/src/sidebarApps/searchInFiles/cmResultView.js new file mode 100644 index 000000000..9309c4d89 --- /dev/null +++ b/src/sidebarApps/searchInFiles/cmResultView.js @@ -0,0 +1,389 @@ +import { EditorState, StateEffect, StateField } from "@codemirror/state"; +import { + Decoration, + EditorView, + ViewPlugin, + WidgetType, +} from "@codemirror/view"; +import appSettings from "lib/settings"; +import helpers from "utils/helpers"; + +/** + * CodeMirror view to render search results + * + * @param {HTMLElement} container + * @param {object} opts + * @param {(lineIndex:number)=>void} opts.onLineClick + * @param {()=>string[]} opts.getWords - returns list of words to highlight + * @param {()=>string[]} opts.getFileNames - returns list of filenames (used to style header lines) + */ +export function createSearchResultView( + container, + { onLineClick, getWords, getFileNames, getRegex }, +) { + let view; + + // Effect and field to maintain collapsed headers (by line number) + const toggleFold = StateEffect.define(); + const foldState = StateField.define({ + create() { + return new Set(); + }, + update(value, tr) { + let next = value; + for (const e of tr.effects) { + if (e.is(toggleFold)) { + if (next === value) next = new Set(value); + const ln = e.value; + if (next.has(ln)) next.delete(ln); + else next.add(ln); + } + } + // Reset folds on full document reset + if (tr.docChanged && tr.startState.doc.length === 0) return new Set(); + return next; + }, + }); + + function eachGroup(doc, fn) { + // Groups start at lines not beginning with a tab + const total = doc.lines; + let start = 1; + while (start <= total) { + const header = doc.line(start); + // If header starts with tab, advance until a non-tab header + if (header.text.startsWith("\t")) { + start++; + continue; + } + let end = start; + for (let i = start + 1; i <= total; i++) { + const line = doc.line(i); + if (!line.text.startsWith("\t")) break; + end = i; + } + fn({ start, end }); + start = end + 1; + } + } + + class ChevronWidget extends WidgetType { + constructor(collapsed) { + super(); + this.collapsed = collapsed; + } + eq(other) { + return other.collapsed === this.collapsed; + } + toDOM() { + const span = document.createElement("span"); + span.className = `cm-foldChevron icon keyboard_arrow_${this.collapsed ? "right" : "down"}`; + return span; + } + ignoreEvent() { + return false; + } + } + + class SummaryWidget extends WidgetType { + constructor(text) { + super(); + this.text = text; + } + eq(other) { + return other.text === this.text; + } + toDOM() { + const div = document.createElement("div"); + div.className = "cm-collapsedSummary"; + div.textContent = this.text; + return div; + } + ignoreEvent() { + return false; + } + } + + class CountWidget extends WidgetType { + constructor(count) { + super(); + this.count = count; + } + eq(other) { + return other.count === this.count; + } + toDOM() { + const span = document.createElement("span"); + span.className = "cm-fileCount"; + span.textContent = `(${this.count})`; + return span; + } + ignoreEvent() { + return true; + } + } + + class FileIconWidget extends WidgetType { + constructor(className) { + super(); + this.className = className; + } + eq(other) { + return other.className === this.className; + } + toDOM() { + const span = document.createElement("span"); + span.className = `${this.className} cm-fileIcon`; + return span; + } + ignoreEvent() { + return false; + } + } + + function buildGroupDecos(state) { + const doc = state.doc; + const folded = state.field(foldState, false) || new Set(); + // No removed groups + const fns = + (typeof getFileNames === "function" ? getFileNames() : []) || []; + if (!fns.length || doc.length === 0 || doc.lines === 0) + return Decoration.none; + + const builder = []; + // Build header chevrons and collapses per group + let groupIndex = 0; + eachGroup(doc, ({ start, end }) => { + const header = doc.line(start); + const key = start - 1; + const collapsed = folded.has(key); // zero-based line index + // Header line class and chevron widget + builder.push( + Decoration.line({ class: "cm-fileName" }).range(header.from), + ); + builder.push( + Decoration.widget({ + widget: new ChevronWidget(collapsed), + side: -1, + }).range(header.from), + ); + // File icon + const fileNames = + (typeof getFileNames === "function" ? getFileNames() : []) || []; + const fname = fileNames[groupIndex] || ""; + const iconClass = helpers.getIconForFile(fname); + builder.push( + Decoration.widget({ + widget: new FileIconWidget(iconClass), + side: -1, + }).range(header.from), + ); + // Count badge on right + const count = Math.max(0, end - start); + builder.push( + Decoration.widget({ widget: new CountWidget(count), side: 1 }).range( + header.to, + ), + ); + + if (collapsed && end > start) { + // Hide content lines and show a summary placeholder + const first = doc.line(start + 1); + const last = doc.line(end); + builder.push( + Decoration.replace({ block: true }).range(first.from, last.to), + ); + const count2 = end - start; + builder.push( + Decoration.widget({ + widget: new SummaryWidget( + `${count2} result${count2 > 1 ? "s" : ""}`, + ), + side: 1, + block: true, + }).range(first.from), + ); + } + groupIndex++; + }); + + return Decoration.set(builder, true); + } + + const groupDecoField = StateField.define({ + create(state) { + return buildGroupDecos(state); + }, + update(decos, tr) { + if ( + tr.docChanged || + tr.startState.field(foldState, false) !== + tr.state.field(foldState, false) + ) { + return buildGroupDecos(tr.state); + } + return decos.map(tr.changes); + }, + provide: (f) => EditorView.decorations.from(f), + }); + + const decorationsPlugin = ViewPlugin.fromClass( + class { + constructor(view) { + this.decorations = this.buildDecos(view); + } + + update(update) { + if ( + update.docChanged || + update.viewportChanged || + update.startState.field(foldState) !== update.state.field(foldState) + ) { + this.decorations = this.buildDecos(update.view); + } + } + + buildDecos(view) { + const builder = []; + let searchRegex = null; + if (typeof getRegex === "function") { + const r = getRegex(); + if (r && r.source) { + const flags = (r.ignoreCase ? "i" : "") + "g"; + try { + searchRegex = new RegExp(r.source, flags); + } catch {} + } + } + const words = searchRegex ? [] : (getWords?.() || []).filter(Boolean); + + let wordRegex = null; + if (!searchRegex && words.length) { + const escaped = words + .map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) + .join("|"); + try { + wordRegex = new RegExp(escaped, "g"); + } catch {} + } + // Add match highlights only on visible lines to keep it fast + const matcher = searchRegex || wordRegex; + if (matcher) { + for (const { from, to } of view.visibleRanges) { + let pos = from; + while (pos <= to) { + const line = view.state.doc.lineAt(pos); + const text = line.text; + if (text && text.charCodeAt(0) === 9) { + matcher.lastIndex = 0; + let m; + while ((m = matcher.exec(text))) { + const fromPos = line.from + m.index; + const toPos = fromPos + m[0].length; + builder.push( + Decoration.mark({ class: "cm-match" }).range( + fromPos, + toPos, + ), + ); + if (m.index === matcher.lastIndex) matcher.lastIndex++; + } + } + if (line.to >= to) break; + pos = line.to + 1; + } + } + } + + return Decoration.set(builder, true); + } + }, + { + decorations: (v) => v.decorations, + eventHandlers: { + mousedown(event, view) { + // Map click to line number and notify (use client coords) + const pos = view.posAtCoords({ x: event.clientX, y: event.clientY }); + if (pos == null) return; + // Only react when clicking on a line element, not empty space + const lineEl = + event.target && event.target.closest + ? event.target.closest(".cm-line") + : null; + if (!lineEl) return; + const ln = view.state.doc.lineAt(pos).number - 1; // zero-based + const lineText = view.state.doc.line(ln + 1).text; + const isHeader = lineText.length > 0 && lineText.charCodeAt(0) !== 9; + if (isHeader) { + // Toggle collapse on header click + view.dispatch({ effects: toggleFold.of(ln) }); + return; + } + // Only trigger navigation for match lines (start with tab) + if (!(lineText && lineText.charCodeAt(0) === 9)) return; + onLineClick?.(ln); + }, + }, + }, + ); + + const readOnly = EditorState.readOnly.of(true); + const lineWrap = EditorView.lineWrapping; + const noCursor = EditorView.editable.of(false); + + function getEditorFontFamily() { + const font = appSettings?.value?.editorFont || "Roboto Mono"; + return `${font}, Noto Mono, Monaco, monospace`; + } + + const theme = EditorView.theme({ + "&": { + fontSize: String(appSettings?.value?.fontSize || "12px"), + lineHeight: String(appSettings?.value?.lineHeight || 1.5), + }, + ".cm-content": { + padding: 0, + fontFamily: getEditorFontFamily(), + }, + ".cm-line": { + color: "var(--primary-text-color)", + }, + }); + + const state = EditorState.create({ + doc: "", + extensions: [ + EditorState.tabSize.of(1), + readOnly, + noCursor, + lineWrap, + theme, + foldState, + groupDecoField, + decorationsPlugin, + ], + }); + + view = new EditorView({ state, parent: container }); + + return { + setValue(text) { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: text || "" }, + }); + }, + insert(text) { + if (!text) return; + view.dispatch({ changes: { from: view.state.doc.length, insert: text } }); + }, + setGhostText(text) { + this.setValue(text || ""); + }, + removeGhostText() { + this.setValue(""); + }, + get view() { + return view; + }, + }; +} diff --git a/src/sidebarApps/searchInFiles/index.js b/src/sidebarApps/searchInFiles/index.js index 5fc682911..3014700a8 100644 --- a/src/sidebarApps/searchInFiles/index.js +++ b/src/sidebarApps/searchInFiles/index.js @@ -1,6 +1,6 @@ import "./styles.scss"; import fsOperation from "fileSystem"; -import addTouchListeners from "ace/touchHandler"; +import { EditorView } from "@codemirror/view"; import autosize from "autosize"; import Checkbox from "components/checkbox"; import Sidebar, { preventSlide } from "components/sidebar"; @@ -11,7 +11,12 @@ import files, { Tree } from "lib/fileList"; import openFile from "lib/openFile"; import settings from "lib/settings"; import helpers from "utils/helpers"; -import { fileNames, words } from "./searchResultMode"; +import { createSearchResultView } from "./cmResultView"; + +// Local highlight sources +const words = []; +const fileNames = []; +const MAX_HL_WORDS = 400; // cap to avoid massive regex in result view const workers = []; const results = []; @@ -84,8 +89,8 @@ const store = { const debounceSearch = helpers.debounce(searchAll, 500); let useIncludeAndExclude = false; -/**@type {AceAjax.Editor} */ -let searchResult = null; +let searchResult = null; // CM6 wrapper from createSearchResultView +let currentSearchRegex = null; let replacing = false; let newFiles = 0; let searching = false; @@ -104,19 +109,13 @@ files.on("push-file", () => { }); $container.onref = ($el) => { - searchResult = ace.edit($el, { - readOnly: true, - useWorker: false, - showLineNumbers: false, - fontSize: "14px", - mode: "ace/mode/search_result", + searchResult = createSearchResultView($el, { + onLineClick: onCursorChange, + getWords: () => words, + getFileNames: () => fileNames, + getRegex: () => currentSearchRegex, }); - searchResult.focus = () => {}; $container.style.lineHeight = "1.5"; - searchResult.session.setTabSize(1); - searchResult.renderer.setMargin(0, 0, -20, 0); - addTouchListeners(searchResult, true, onCursorChange); - searchResult.session.setUseWrapMode(true); }; preventSlide((target) => { @@ -215,9 +214,7 @@ export default [ ); }, false, // show as first item - () => { - searchResult?.resize(true); - }, + () => {}, ]; /** @@ -238,8 +235,12 @@ async function onWorkerMessage(e) { let readError; const editorFile = editorManager.getFile(data, "uri"); - if (editorFile) { - content = editorFile.session?.getValue() || ""; + if (editorFile?.session?.doc) { + try { + content = editorFile.session.doc.toString() || ""; + } catch (_) { + content = ""; + } } else { try { content = await fsOperation(data).readFile( @@ -266,6 +267,10 @@ async function onWorkerMessage(e) { if (filesSearched.includes(file)) return; filesSearched.push(Tree.fromJSON(file)); + // Clear any ghost text on first result + if (filesSearched.length === 1) { + searchResult.setValue(""); + } resultOverview.filesCount += 1; resultOverview.matchesCount += matches.length; $resultOverview.innerHTML = searchResultText( @@ -280,18 +285,16 @@ async function onWorkerMessage(e) { position: null, }); - fileNames.push(escapeStringRegexp(file.name)); - forceTokenizer(); + fileNames.push(file.name); for (const result of matches) { result.file = index; results.push(result); - if (!words.includes(result.renderText)) { - words.push(escapeStringRegexp(result.renderText)); - forceTokenizer(); + if (words.length < MAX_HL_WORDS) { + const token = escapeStringRegexp(result.renderText); + if (!words.includes(token)) words.push(token); } } - searchResult.navigateFileEnd(); if (fileNames.length > 1) { searchResult.insert(`\n${text}`); } else { @@ -367,6 +370,7 @@ async function onWorkerMessage(e) { * On input event handler * @param {InputEvent} e */ + function onInput(e) { if (!searchResult || replacing) return; @@ -439,6 +443,7 @@ async function searchAll() { searching = true; words.length = 0; fileNames.length = 0; + currentSearchRegex = regex; searchResult.setGhostText(strings["searching..."], { row: 0, column: 0 }); sendMessage("search-files", allFiles, regex, options); } @@ -712,14 +717,12 @@ function toRegex(search, options) { /** * On cursor change event handler */ -async function onCursorChange() { - const line = searchResult.selection.getCursor().row; +async function onCursorChange(line) { const result = results[line]; if (!result) return; const { file, position } = result; if (!position) { - // fold the file - searchResult.execCommand("toggleFoldWidget"); + // header line clicked; CM view folding not implemented yet return; } @@ -727,10 +730,18 @@ async function onCursorChange() { const { url } = filesSearched[file]; await openFile(url, { render: true }); const { editor } = editorManager; - editor.moveCursorTo(position.start.row, position.start.column, false); - editor.selection.setRange(position); - editor.centerSelection(); - editor.focus(); + try { + // Compute offsets from row/column (rows from worker are 0-based) + const doc = editor.state.doc; + const startLine = doc.line(position.start.row + 1); + const endLine = doc.line(position.end.row + 1); + const from = Math.min(startLine.from + position.start.column, startLine.to); + const to = Math.min(endLine.from + position.end.column, endLine.to); + editor.dispatch({ + selection: { anchor: from, head: to }, + effects: EditorView.scrollIntoView(from, { y: "center" }), + }); + } catch (_) {} } /** @@ -767,13 +778,3 @@ function removeEvents() { editorManager.off("rename-file", onInput); editorManager.off("file-content-changed", onInput); } - -function forceTokenizer() { - const { session } = searchResult; - // force recreation of tokenizer - session.$mode.$tokenizer = null; - session.bgTokenizer.setTokenizer(session.$mode.getTokenizer()); - // force re-highlight whole document - const row = session.getLength() - 1; - session.bgTokenizer.start(row); -} diff --git a/src/sidebarApps/searchInFiles/searchResultMode.js b/src/sidebarApps/searchInFiles/searchResultMode.js deleted file mode 100644 index 2260c502f..000000000 --- a/src/sidebarApps/searchInFiles/searchResultMode.js +++ /dev/null @@ -1,223 +0,0 @@ -export const words = []; -export const fileNames = []; - -ace.define( - "ace/mode/search_result_highlight_rules", - [ - "require", - "exports", - "module", - "ace/lib/oop", - "ace/mode/text_highlight_rules", - ], - function (require, exports, module) { - const oop = require("../lib/oop"); - const { TextHighlightRules } = require("./text_highlight_rules"); - - function SearchHighlightRules() { - this.$rules = { - start: [ - { - token: "file_name", - get regex() { - return fileNames.join("|"); - }, - }, - { - token: "highlight", - get regex() { - return words.join("|"); - }, - }, - { - token: "string", // multi line string start - regex: /[|>][-+\d]*(?:$|\s+(?:$|#))/, - onMatch: function (val, state, stack, line) { - line = line.replace(/ #.*/, ""); - var indent = /^ *((:\s*)?-(\s*[^|>])?)?/ - .exec(line)[0] - .replace(/\S\s*$/, "").length; - var indentationIndicator = Number.parseInt( - /\d+[\s+-]*$/.exec(line), - ); - - if (indentationIndicator) { - indent += indentationIndicator - 1; - this.next = "mlString"; - } else { - this.next = "mlStringPre"; - } - if (!stack.length) { - stack.push(this.next); - stack.push(indent); - } else { - stack[0] = this.next; - stack[1] = indent; - } - return this.token; - }, - next: "mlString", - }, - ], - mlStringPre: [ - { - token: "indent", - regex: /^ *$/, - }, - { - token: "indent", - regex: /^ */, - onMatch: function (val, state, stack) { - var curIndent = stack[1]; - - if (curIndent >= val.length) { - this.next = "start"; - stack.shift(); - stack.shift(); - } else { - stack[1] = val.length - 1; - this.next = stack[0] = "mlString"; - } - return this.token; - }, - next: "mlString", - }, - ], - mlString: [ - { - token: "indent", - regex: /^ *$/, - }, - { - token: "indent", - regex: /^ */, - onMatch: function (val, state, stack) { - var curIndent = stack[1]; - - if (curIndent >= val.length) { - this.next = "start"; - stack.splice(0); - } else { - this.next = "mlString"; - } - return this.token; - }, - next: "mlString", - }, - ], - }; - this.normalizeRules(); - } - oop.inherits(SearchHighlightRules, TextHighlightRules); - exports.SearchHighlightRules = SearchHighlightRules; - }, -); - -define("ace/mode/folding/search_result_fold", [ - "require", - "exports", - "module", - "ace/lib/oop", - "ace/mode/folding/fold_mode", - "ace/range", -], function (require, exports, module) { - const oop = require("ace/lib/oop"); - const { FoldMode: BaseFoldMode } = require("./fold_mode"); - const { Range } = require("ace/range"); - - function FoldMode() {} - oop.inherits(FoldMode, BaseFoldMode); - exports.FoldMode = FoldMode; - - (function () { - this.getFoldWidgetRange = function (session, foldStyle, row) { - var range = this.indentationBlock(session, row); - if (range) return range; - var re = /\S/; - var line = session.getLine(row); - var startLevel = line.search(re); - if (startLevel === -1 || line[startLevel] !== "#") return; - var startColumn = line.length; - var maxRow = session.getLength(); - var startRow = row; - var endRow = row; - while (++row < maxRow) { - line = session.getLine(row); - var level = line.search(re); - if (level === -1) continue; - if (line[level] !== "#") break; - endRow = row; - } - if (endRow > startRow) { - var endColumn = session.getLine(endRow).length; - return new Range(startRow, startColumn, endRow, endColumn); - } - }; - this.getFoldWidget = function (session, foldStyle, row) { - var line = session.getLine(row); - var indent = line.search(/\S/); - var next = session.getLine(row + 1); - var prev = session.getLine(row - 1); - var prevIndent = prev.search(/\S/); - var nextIndent = next.search(/\S/); - if (indent === -1) { - session.foldWidgets[row - 1] = - prevIndent !== -1 && prevIndent < nextIndent ? "start" : ""; - return ""; - } - if (prevIndent === -1) { - if ( - indent === nextIndent && - line[indent] === "#" && - next[indent] === "#" - ) { - session.foldWidgets[row - 1] = ""; - session.foldWidgets[row + 1] = ""; - return "start"; - } - } else if ( - prevIndent === indent && - line[indent] === "#" && - prev[indent] === "#" - ) { - if (session.getLine(row - 2).search(/\S/) === -1) { - session.foldWidgets[row - 1] = "start"; - session.foldWidgets[row + 1] = ""; - return ""; - } - } - if (prevIndent !== -1 && prevIndent < indent) - session.foldWidgets[row - 1] = "start"; - else session.foldWidgets[row - 1] = ""; - if (indent < nextIndent) return "start"; - else return ""; - }; - }).call(FoldMode.prototype); -}); - -ace.define( - "ace/mode/search_result", - [ - "require", - "exports", - "module", - "ace/lib/oop", - "ace/mode/text", - "ace/mode/folding/search_result_fold", - "ace/search_result_highlight_rules", - ], - function (require, exports, module) { - const oop = require("ace/lib/oop"); - const { Mode: TextMode } = require("./text"); - const { SearchHighlightRules } = require("./search_result_highlight_rules"); - const { FoldMode } = require("./folding/search_result_fold"); - - function Mode() { - this.$id = "ace/mode/search_result"; - this.HighlightRules = SearchHighlightRules; - this.foldingRules = new FoldMode(); - } - oop.inherits(Mode, TextMode); - exports.Mode = Mode; - }, -); diff --git a/src/sidebarApps/searchInFiles/styles.scss b/src/sidebarApps/searchInFiles/styles.scss index f4d704728..c0a1ae048 100644 --- a/src/sidebarApps/searchInFiles/styles.scss +++ b/src/sidebarApps/searchInFiles/styles.scss @@ -54,58 +54,99 @@ } } - .ace_editor { + .cm-editor { height: 100%; - width: calc(100% + 18px); - margin-left: -8px; - background-color: rgb(153, 153, 255); + width: 100%; background-color: var(--primary-color); - color: rgb(255, 255, 255); color: var(--primary-text-color); - .ace_gutter, - .ace_gutter-cell { - background-color: inherit !important; - color: inherit !important; + + .cm-content { + background-color: inherit; + color: inherit; + padding: 0 !important; + + .cm-line { + padding: 0 !important; + } + + .cm-line:nth-child(odd) { + background-color: rgba(0, 0, 0, 0.2) !important; + } } - .ace_fold { - display: none !important; + .cm-scroller { + overflow: auto; } - .ace_bracket { - display: none !important; + .cm-line.cm-fileName .cm-foldChevron { + display: inline-flex; + align-items: center; + width: auto; + margin-right: 2px; + opacity: 0.9; + vertical-align: middle; } - .ace_cursor { - display: none !important; + + .cm-line.cm-fileName { + font-weight: 600; } - .ace_marker-layer { - display: none !important; + .cm-line.cm-fileName .cm-fileIcon { + display: inline-flex; + align-items: center; + vertical-align: middle; + margin-right: 2px; + font-size: 1em; + line-height: 1; } - .ace_highlight { - border: solid 1px rgba(122, 122, 122, 0.2); - border: solid 1px var(--border-color); - border-radius: 2px; - background-color: rgb(255, 255, 255); - background-color: var(--secondary-color); - color: rgb(37, 37, 37); + .cm-line.cm-fileName .cm-fileCount { + display: inline-block; + margin-left: 8px; + font-size: 0.9em; color: var(--secondary-text-color); } - .ace_file_name { - color: rgb(255, 215, 0); - color: var(--active-text-color); + .cm-collapsedSummary { + padding: 4px 8px; + margin: 2px 0 6px 18px; + font-size: 0.9em; + color: var(--secondary-text-color); + background: color-mix(in srgb, var(--secondary-color) 60%, transparent); + border: 1px solid var(--border-color); + border-radius: 4px; } - .ace_gutter-cell:nth-child(odd), - .ace_line_group:nth-child(odd) { - background-color: rgba(0, 0, 0, 0.2) !important; + /* Match highlight */ + .cm-match { + background: color-mix(in srgb, var(--active-color) 60%, transparent); + color: var(--secondary-text-color); + outline: 1px solid var(--border-color); + border-radius: 2px; + font-weight: 500; } } + .cm-editor { + width: 100% !important; + margin-left: 0 !important; + } + + .search-in-file-editor { + height: 100%; + min-height: 0; + overflow: hidden; + display: block; + } + + textarea { + height: auto; + resize: none; + overflow-y: hidden; + } + .extras { display: block !important; line-height: 0px !important; diff --git a/src/sidebarApps/searchInFiles/worker.js b/src/sidebarApps/searchInFiles/worker.js index b740b2866..7f3ce85bf 100644 --- a/src/sidebarApps/searchInFiles/worker.js +++ b/src/sidebarApps/searchInFiles/worker.js @@ -222,7 +222,53 @@ function done(ratio, mode) { * @param {string} arg.include - The inclusion patterns separated by commas. */ function Skip({ exclude, include }) { - const excludeFiles = (exclude ? exclude.split(",") : []).map((p) => p.trim()); + // Default exclude patterns for binary/media/archives/fonts/etc. + const defaultExcludes = [ + "**/*.png", + "**/*.jpg", + "**/*.jpeg", + "**/*.gif", + "**/*.bmp", + "**/*.webp", + "**/*.avif", + "**/*.ico", + "**/*.svgz", + "**/*.mp3", + "**/*.wav", + "**/*.ogg", + "**/*.flac", + "**/*.m4a", + "**/*.aac", + "**/*.mp4", + "**/*.mkv", + "**/*.webm", + "**/*.mov", + "**/*.avi", + "**/*.zip", + "**/*.gz", + "**/*.bz2", + "**/*.xz", + "**/*.7z", + "**/*.rar", + "**/*.tar", + "**/*.exe", + "**/*.dll", + "**/*.so", + "**/*.bin", + "**/*.class", + "**/*.ttf", + "**/*.otf", + "**/*.woff", + "**/*.woff2", + "**/*.pdf", + "**/*.psd", + "**/*.ai", + "**/*.sketch", + ]; + const userExcludes = (exclude ? exclude.split(",") : []) + .map((p) => p.trim()) + .filter(Boolean); + const excludeFiles = [...defaultExcludes, ...userExcludes]; const includeFiles = (include ? include.split(",") : ["**"]).map((p) => p.trim(), ); diff --git a/src/styles/codemirror.scss b/src/styles/codemirror.scss new file mode 100644 index 000000000..68610d760 --- /dev/null +++ b/src/styles/codemirror.scss @@ -0,0 +1,130 @@ +.editor-container { + position: relative; +} + +.cm-editor, +.cm-editor * { + -webkit-touch-callout: none; +} + +.editor-container > .cursor { + pointer-events: auto; + touch-action: none; + z-index: 600; +} + +.editor-container > .cursor-menu { + z-index: 600; +} + +.cm-tooltip { + box-sizing: border-box; + max-width: min(32rem, calc(100vw - 1.25rem)); + width: max-content; + padding: 0.4rem 0.45rem; + border-radius: 0; + overscroll-behavior: contain; + overflow-y: auto; + max-height: min(70vh, 22rem); + + .cm-tooltip-section + .cm-tooltip-section { + margin-top: 0.5rem; + } +} + +.cm-tooltip.cm-tooltip-hover { + font-size: 0.9rem; + line-height: 1.45; + word-break: break-word; + max-height: min(65vh, 20rem); +} + +.cm-tooltip.cm-tooltip-autocomplete { + display: flex; + flex-wrap: nowrap; + align-items: stretch; + gap: 0.4rem; + width: auto; + min-width: min(15rem, calc(100vw - 1.75rem)); + max-width: min(32rem, calc(100vw - 1.25rem)); + max-height: min(60vh, 20rem); + padding: 0.25rem; + overflow: visible; +} + +.cm-tooltip.cm-tooltip-autocomplete > ul { + flex: 1 1 auto; + max-height: inherit; + overflow: auto; + padding: 0.25rem; + margin: 0; + scrollbar-gutter: stable; +} + +.cm-tooltip.cm-tooltip-autocomplete > ul > li { + display: flex; + align-items: center; + gap: 0.12rem; + padding: 0.3rem 0.36rem; + border-radius: 0.2rem; +} + +.cm-tooltip.cm-tooltip-autocomplete .cm-completionIcon { + flex: 0 0 auto; + min-width: 1rem; + text-align: center; + line-height: 1; +} + +.cm-tooltip.cm-tooltip-autocomplete .cm-completionLabel { + flex: 1 1 auto; + font-size: 0.95em; + line-height: 1.4; + overflow-wrap: anywhere; +} + +.cm-tooltip.cm-tooltip-autocomplete .cm-completionMatchedText { + font-weight: 600; +} + +.cm-tooltip.cm-tooltip-autocomplete .cm-completionDetail { + margin-left: auto; + font-size: 0.85em; +} + +.cm-tooltip.cm-tooltip-autocomplete .cm-completionInfo { + flex: 1 1 45%; + min-width: min(12rem, calc(100vw - 3rem)); + max-width: min(18rem, calc(100vw - 2.5rem)); + max-height: inherit; + padding: 0.3rem 0.35rem; + font-size: 0.85rem; + line-height: 1.35; + overflow: auto; +} + +@media (max-width: 480px) { + .cm-tooltip { + font-size: 0.9rem; + max-width: calc(100vw - 1.25rem); + max-height: min(70vh, 20rem); + } + + .cm-tooltip.cm-tooltip-autocomplete { + flex-direction: column; + min-width: min(13.5rem, calc(100vw - 1.5rem)); + max-width: calc(100vw - 1.35rem); + max-height: min(65vh, 18rem); + } + + .cm-tooltip.cm-tooltip-autocomplete > ul > li { + padding: 0.32rem 0.4rem; + } + + .cm-tooltip.cm-tooltip-autocomplete .cm-completionInfo { + min-width: auto; + max-width: 100%; + max-height: 12rem; + padding: 0.35rem 0.4rem 0.2rem; + } +} diff --git a/src/test/ace.test.js b/src/test/ace.test.js new file mode 100644 index 000000000..1facdb0dd --- /dev/null +++ b/src/test/ace.test.js @@ -0,0 +1,252 @@ +import { TestRunner } from "./tester"; + +/** + * Ace Editor API Compatibility Tests + * + * These tests validate that the CodeMirror-based editor (from editorManager) + * properly implements the Ace Editor API compatibility layer. + */ +export async function runAceCompatibilityTests(writeOutput) { + const runner = new TestRunner("Ace API Compatibility"); + + function getEditor() { + return editorManager?.editor; + } + + async function createTestFile(text = "") { + const EditorFile = acode.require("editorFile"); + const file = new EditorFile("__ace_test__.txt", { + text, + render: true, + }); + await new Promise((r) => setTimeout(r, 100)); + return file; + } + + runner.test("editorManager.editor exists", (test) => { + test.assert( + typeof editorManager !== "undefined", + "editorManager should exist", + ); + test.assert( + editorManager.editor != null, + "editorManager.editor should exist", + ); + }); + + runner.test("editor.getValue()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.getValue === "function", + "getValue should be a function", + ); + const value = editor.getValue(); + test.assert(typeof value === "string", "getValue should return string"); + }); + + runner.test("editor.insert()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.insert === "function", + "insert should be a function", + ); + }); + + runner.test("editor.getCursorPosition()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.getCursorPosition === "function", + "getCursorPosition should exist", + ); + const pos = editor.getCursorPosition(); + test.assert(typeof pos.row === "number", "row should be number"); + test.assert(typeof pos.column === "number", "column should be number"); + }); + + runner.test("editor.gotoLine()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.gotoLine === "function", + "gotoLine should be a function", + ); + }); + + runner.test("editor.moveCursorToPosition()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.moveCursorToPosition === "function", + "moveCursorToPosition should exist", + ); + }); + + runner.test("editor.selection object", (test) => { + const editor = getEditor(); + test.assert(editor.selection != null, "selection should exist"); + }); + + runner.test("editor.selection.getRange()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.selection.getRange === "function", + "getRange should be a function", + ); + const range = editor.selection.getRange(); + test.assert(range.start != null, "range should have start"); + test.assert(range.end != null, "range should have end"); + }); + + runner.test("editor.selection.getCursor()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.selection.getCursor === "function", + "getCursor should be a function", + ); + const pos = editor.selection.getCursor(); + test.assert(typeof pos.row === "number", "row should be number"); + test.assert(typeof pos.column === "number", "column should be number"); + }); + + runner.test("editor.getCopyText()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.getCopyText === "function", + "getCopyText should exist", + ); + const text = editor.getCopyText(); + test.assert(typeof text === "string", "should return string"); + }); + + runner.test("editor.session exists", async (test) => { + const testFile = await createTestFile("test"); + const editor = getEditor(); + test.assert(editor.session != null, "session should exist"); + testFile.remove(false); + }); + + runner.test("editor.setTheme()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.setTheme === "function", + "setTheme should be a function", + ); + }); + + runner.test("editor.commands object", (test) => { + const editor = getEditor(); + test.assert(editor.commands != null, "commands should exist"); + }); + + runner.test("editor.commands.addCommand()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.commands.addCommand === "function", + "addCommand should be a function", + ); + }); + + runner.test("editor.commands.removeCommand()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.commands.removeCommand === "function", + "removeCommand should exist", + ); + }); + + runner.test("editor.commands.commands getter", (test) => { + const editor = getEditor(); + const cmds = editor.commands.commands; + test.assert( + typeof cmds === "object" && cmds !== null, + "commands should return object", + ); + }); + + runner.test("editor.execCommand()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.execCommand === "function", + "execCommand should be a function", + ); + }); + + runner.test("editor.focus()", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.focus === "function", + "focus should be a function", + ); + }); + + runner.test("editor.state (CodeMirror)", (test) => { + const editor = getEditor(); + test.assert(editor.state != null, "state should exist"); + }); + + runner.test("editor.dispatch (CodeMirror)", (test) => { + const editor = getEditor(); + test.assert( + typeof editor.dispatch === "function", + "dispatch should be a function", + ); + }); + + runner.test("editor.contentDOM (CodeMirror)", (test) => { + const editor = getEditor(); + test.assert(editor.contentDOM != null, "contentDOM should exist"); + }); + + // Session API tests + + runner.test("session.getValue()", async (test) => { + const testFile = await createTestFile("test content"); + const editor = getEditor(); + test.assert( + typeof editor.session.getValue === "function", + "getValue should exist", + ); + const value = editor.session.getValue(); + test.assert(typeof value === "string", "should return string"); + test.assertEqual(value, "test content"); + testFile.remove(false); + }); + + runner.test("session.setValue()", async (test) => { + const testFile = await createTestFile("original"); + const editor = getEditor(); + test.assert( + typeof editor.session.setValue === "function", + "setValue should exist", + ); + editor.session.setValue("modified"); + test.assertEqual(editor.session.getValue(), "modified"); + testFile.remove(false); + }); + + runner.test("session.getLength()", async (test) => { + const testFile = await createTestFile("line1\nline2\nline3"); + const editor = getEditor(); + test.assert( + typeof editor.session.getLength === "function", + "getLength should exist", + ); + const len = editor.session.getLength(); + test.assert(typeof len === "number", "should return number"); + test.assertEqual(len, 3); + testFile.remove(false); + }); + + runner.test("session.getLine()", async (test) => { + const testFile = await createTestFile("first\nsecond\nthird"); + const editor = getEditor(); + test.assert( + typeof editor.session.getLine === "function", + "getLine should exist", + ); + test.assertEqual(editor.session.getLine(0), "first"); + test.assertEqual(editor.session.getLine(1), "second"); + test.assertEqual(editor.session.getLine(2), "third"); + testFile.remove(false); + }); + + return await runner.run(writeOutput); +} diff --git a/src/test/editor.tests.js b/src/test/editor.tests.js index d48b07973..b34cb7ad1 100644 --- a/src/test/editor.tests.js +++ b/src/test/editor.tests.js @@ -1,217 +1,722 @@ +import { history, isolateHistory, redo, undo } from "@codemirror/commands"; +import { + bracketMatching, + defaultHighlightStyle, + foldGutter, + syntaxHighlighting, +} from "@codemirror/language"; +import { highlightSelectionMatches, searchKeymap } from "@codemirror/search"; +import { EditorSelection, EditorState } from "@codemirror/state"; +import { EditorView } from "@codemirror/view"; +import createBaseExtensions from "cm/baseExtensions"; import { TestRunner } from "./tester"; -export async function runAceEditorTests(writeOutput) { - const runner = new TestRunner("Ace Editor API Tests"); +export async function runCodeMirrorTests(writeOutput) { + const runner = new TestRunner("CodeMirror 6 Editor Tests"); - function createEditor() { + function createEditor(doc = "", extensions = []) { const container = document.createElement("div"); container.style.width = "500px"; container.style.height = "300px"; - container.style.backgroundColor = "#a02f2f"; + container.style.backgroundColor = "#1e1e1e"; document.body.appendChild(container); - const editor = ace.edit(container); - return { editor, container }; + const state = EditorState.create({ + doc, + extensions: [...createBaseExtensions(), ...extensions], + }); + + const view = new EditorView({ state, parent: container }); + return { view, container }; } - async function withEditor(test, fn) { - let editor, container; + async function withEditor(test, fn, initialDoc = "", extensions = []) { + let view, container; try { - ({ editor, container } = createEditor()); - test.assert(editor != null, "Editor instance should be created"); + ({ view, container } = createEditor(initialDoc, extensions)); + test.assert(view != null, "EditorView instance should be created"); await new Promise((resolve) => setTimeout(resolve, 100)); - await fn(editor); + await fn(view); await new Promise((resolve) => setTimeout(resolve, 200)); } finally { - if (editor) editor.destroy(); + if (view) view.destroy(); if (container) container.remove(); } } - // Test 1: Ace is available - runner.test("Ace is loaded", async (test) => { - test.assert(typeof ace !== "undefined", "Ace should be available globally"); + // ========================================= + // BASIC EDITOR TESTS + // ========================================= + + runner.test("CodeMirror imports available", async (test) => { test.assert( - typeof ace.edit === "function", - "ace.edit should be a function", + typeof EditorView !== "undefined", + "EditorView should be defined", + ); + test.assert( + typeof EditorState !== "undefined", + "EditorState should be defined", + ); + test.assert( + typeof EditorState.create === "function", + "EditorState.create should be a function", ); }); - // Test 2: Editor creation runner.test("Editor creation", async (test) => { - const { editor, container } = createEditor(); - test.assert(editor != null, "Editor instance should be created"); - test.assert( - typeof editor.getSession === "function", - "Editor should expose getSession", - ); - editor.destroy(); + const { view, container } = createEditor(); + test.assert(view != null, "EditorView instance should be created"); + test.assert(view.dom instanceof HTMLElement, "Editor should have DOM"); + test.assert(view.state instanceof EditorState, "Editor should have state"); + view.destroy(); container.remove(); }); - // Test 3: Session access - runner.test("Session access", async (test) => { - await withEditor(test, async (editor) => { - const session = editor.getSession(); - test.assert(session != null, "Editor session should exist"); + runner.test("State access", async (test) => { + await withEditor(test, async (view) => { + const state = view.state; + test.assert(state != null, "Editor state should exist"); + test.assert(typeof state.doc !== "undefined", "State should have doc"); test.assert( - typeof session.getValue === "function", - "Session should expose getValue", + typeof state.doc.toString === "function", + "Doc should have toString", ); }); }); - // Test 4: Set and get value - runner.test("Set and get value", async (test) => { - await withEditor(test, async (editor) => { - const text = "Hello Ace Editor"; - editor.setValue(text, -1); - test.assertEqual(editor.getValue(), text); + runner.test("Set and get document content", async (test) => { + await withEditor(test, async (view) => { + const text = "Hello CodeMirror 6"; + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: text }, + }); + test.assertEqual(view.state.doc.toString(), text); }); }); - // Test 5: Cursor movement - runner.test("Cursor movement", async (test) => { - await withEditor(test, async (editor) => { - editor.setValue("line1\nline2\nline3", -1); - editor.moveCursorTo(1, 2); + // ========================================= + // CURSOR AND SELECTION TESTS + // ========================================= - const pos = editor.getCursorPosition(); - test.assertEqual(pos.row, 1); - test.assertEqual(pos.column, 2); + runner.test("Cursor movement", async (test) => { + await withEditor(test, async (view) => { + const doc = "line1\nline2\nline3"; + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: doc }, + }); + + const line2 = view.state.doc.line(2); + const targetPos = line2.from + 2; + view.dispatch({ + selection: { anchor: targetPos, head: targetPos }, + }); + + const pos = view.state.selection.main.head; + const lineInfo = view.state.doc.lineAt(pos); + test.assertEqual(lineInfo.number, 2); + test.assertEqual(pos - lineInfo.from, 2); }); }); - // Test 6: Selection API runner.test("Selection handling", async (test) => { - await withEditor(test, async (editor) => { - editor.setValue("abc\ndef", -1); - editor.selectAll(); - test.assert(editor.getSelectedText().length > 0); + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: "abc\ndef" }, + }); + view.dispatch({ + selection: { anchor: 0, head: view.state.doc.length }, + }); + + const { from, to } = view.state.selection.main; + const selectedText = view.state.doc.sliceString(from, to); + test.assert(selectedText.length > 0, "Should have selected text"); + test.assertEqual(selectedText, "abc\ndef"); }); }); - // Test 7: Undo manager - runner.test("Undo manager works", async (test) => { - await withEditor(test, async (editor) => { - const session = editor.getSession(); - const undoManager = session.getUndoManager(); + runner.test("Multiple selections", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: "foo bar foo" }, + }); + + view.dispatch({ + selection: EditorSelection.create([ + EditorSelection.range(0, 3), + EditorSelection.range(8, 11), + ]), + }); + + test.assertEqual(view.state.selection.ranges.length, 2); + test.assertEqual(view.state.doc.sliceString(0, 3), "foo"); + test.assertEqual(view.state.doc.sliceString(8, 11), "foo"); + }); + }); - session.setValue("one"); - undoManager.reset(); + runner.test("Selection with cursor (empty range)", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: "hello world" }, + }); - editor.insert("\ntwo"); - editor.undo(); + view.dispatch({ + selection: EditorSelection.cursor(5), + }); - test.assertEqual(editor.getValue(), "one"); + const main = view.state.selection.main; + test.assertEqual(main.from, 5); + test.assertEqual(main.to, 5); + test.assert(main.empty, "Cursor selection should be empty"); }); }); - // Test 8: Mode setting - runner.test("Mode setting", async (test) => { - await withEditor(test, async (editor) => { - const session = editor.getSession(); - session.setMode("ace/mode/javascript"); + // ========================================= + // HISTORY (UNDO/REDO) TESTS + // ========================================= + + runner.test("Undo works", async (test) => { + const { view, container } = createEditor("one"); - const mode = session.getMode(); - test.assert(mode && mode.$id === "ace/mode/javascript"); + try { + view.dispatch({ + changes: { from: 3, insert: "\ntwo" }, + }); + test.assertEqual(view.state.doc.toString(), "one\ntwo"); + + undo(view); + test.assertEqual(view.state.doc.toString(), "one"); + } finally { + view.destroy(); + container.remove(); + } + }); + + runner.test("Redo works", async (test) => { + const { view, container } = createEditor("one"); + + try { + view.dispatch({ + changes: { from: 3, insert: "\ntwo" }, + }); + + undo(view); + test.assertEqual(view.state.doc.toString(), "one"); + + redo(view); + test.assertEqual(view.state.doc.toString(), "one\ntwo"); + } finally { + view.destroy(); + container.remove(); + } + }); + + runner.test("Multiple undo steps", async (test) => { + const { view, container } = createEditor(""); + + try { + // Use isolateHistory to force each change into separate history entries + view.dispatch({ + changes: { from: 0, insert: "a" }, + annotations: isolateHistory.of("full"), + }); + view.dispatch({ + changes: { from: 1, insert: "b" }, + annotations: isolateHistory.of("full"), + }); + view.dispatch({ + changes: { from: 2, insert: "c" }, + annotations: isolateHistory.of("full"), + }); + + test.assertEqual(view.state.doc.toString(), "abc"); + + undo(view); + undo(view); + test.assertEqual(view.state.doc.toString(), "a"); + } finally { + view.destroy(); + container.remove(); + } + }); + + // ========================================= + // DOCUMENT MANIPULATION TESTS + // ========================================= + + runner.test("Line count", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: "a\nb\nc\nd" }, + }); + test.assertEqual(view.state.doc.lines, 4); }); }); - // Test 9: Theme setting - runner.test("Theme setting", async (test) => { - await withEditor(test, async (editor) => { - editor.setTheme("ace/theme/monokai"); - test.assert(editor.getTheme().includes("monokai")); + runner.test("Insert text at position", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: "hello world" }, + }); + + view.dispatch({ + changes: { from: 5, to: 5, insert: " there" }, + }); + + test.assertEqual(view.state.doc.toString(), "hello there world"); }); }); - // Test 11: Line count - runner.test("Line count", async (test) => { - await withEditor(test, async (editor) => { - editor.setValue("a\nb\nc\nd", -1); - test.assertEqual(editor.session.getLength(), 4); + runner.test("Replace text range", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: "hello world" }, + }); + + view.dispatch({ + changes: { from: 6, to: 11, insert: "cm6" }, + }); + + test.assertEqual(view.state.doc.toString(), "hello cm6"); }); }); - // Test 12: Replace text - runner.test("Replace text", async (test) => { - await withEditor(test, async (editor) => { - editor.setValue("hello world", -1); - editor.find("world"); - editor.replace("ace"); + runner.test("Delete text", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "hello world" }, + }); - test.assertEqual(editor.getValue(), "hello ace"); + view.dispatch({ + changes: { from: 5, to: 11, insert: "" }, + }); + + test.assertEqual(view.state.doc.toString(), "hello"); }); }); - // Test 13: Search API - runner.test("Search API", async (test) => { - await withEditor(test, async (editor) => { - editor.setValue("foo bar foo", -1); - editor.find("foo"); + runner.test("Batch changes", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "aaa bbb ccc" }, + }); + + view.dispatch({ + changes: [ + { from: 0, to: 3, insert: "xxx" }, + { from: 4, to: 7, insert: "yyy" }, + { from: 8, to: 11, insert: "zzz" }, + ], + }); + + test.assertEqual(view.state.doc.toString(), "xxx yyy zzz"); + }); + }); + + runner.test("Line information", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { + from: 0, + to: view.state.doc.length, + insert: "line one\nline two\nline three", + }, + }); + + const line2 = view.state.doc.line(2); + test.assertEqual(line2.number, 2); + test.assertEqual(line2.text, "line two"); + test.assert(line2.from > 0, "Line 2 should have positive from"); + }); + }); - const range = editor.getSelectionRange(); - test.assert(range.start.column === 0); + runner.test("Position conversions", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { + from: 0, + to: view.state.doc.length, + insert: "abc\ndefgh\nij", + }, + }); + + const pos = 7; // 'g' in "defgh" + const lineInfo = view.state.doc.lineAt(pos); + + test.assertEqual(lineInfo.number, 2); + test.assertEqual(lineInfo.text, "defgh"); + test.assertEqual(pos - lineInfo.from, 3); }); }); - // Test 14: Renderer availability - runner.test("Renderer exists", async (test) => { - await withEditor(test, async (editor) => { - const renderer = editor.renderer; - test.assert(renderer != null); - test.assert(typeof renderer.updateFull === "function"); + runner.test("Empty document handling", async (test) => { + await withEditor(test, async (view) => { + test.assertEqual(view.state.doc.length, 0); + test.assertEqual(view.state.doc.lines, 1); + test.assertEqual(view.state.doc.toString(), ""); }); }); - // Test 15: Editor options - runner.test("Editor options", async (test) => { - await withEditor(test, async (editor) => { - editor.setOption("showPrintMargin", false); - test.assertEqual(editor.getOption("showPrintMargin"), false); + // ========================================= + // DOM AND VIEW TESTS + // ========================================= + + runner.test("DOM elements exist", async (test) => { + await withEditor(test, async (view) => { + test.assert(view.dom != null, "view.dom should exist"); + test.assert(view.scrollDOM != null, "view.scrollDOM should exist"); + test.assert(view.contentDOM != null, "view.contentDOM should exist"); + }); + }); + + runner.test("Focus and blur", async (test) => { + await withEditor(test, async (view) => { + view.focus(); + await new Promise((resolve) => setTimeout(resolve, 50)); + test.assert(view.hasFocus, "Editor should have focus"); + + view.contentDOM.blur(); + await new Promise((resolve) => setTimeout(resolve, 50)); + test.assert(!view.hasFocus, "Editor should not have focus after blur"); }); }); - // Test 16: Scroll API runner.test("Scroll API", async (test) => { - await withEditor(test, async (editor) => { - editor.setValue(Array(100).fill("line").join("\n"), -1); - editor.scrollToLine(50, true, true, () => {}); + await withEditor(test, async (view) => { + const longDoc = Array(100).fill("line").join("\n"); + view.dispatch({ + changes: { from: 0, to: view.state.doc.length, insert: longDoc }, + }); - const firstVisibleRow = editor.renderer.getFirstVisibleRow(); - test.assert(firstVisibleRow >= 0); + const line50 = view.state.doc.line(50); + view.dispatch({ + effects: EditorView.scrollIntoView(line50.from, { y: "center" }), + }); + + await new Promise((resolve) => setTimeout(resolve, 100)); + test.assert( + view.scrollDOM.scrollTop >= 0, + "scrollTop should be accessible", + ); + }); + }); + + runner.test("Viewport info", async (test) => { + await withEditor(test, async (view) => { + const longDoc = Array(200).fill("some text content").join("\n"); + view.dispatch({ + changes: { from: 0, insert: longDoc }, + }); + + const viewport = view.viewport; + test.assert(typeof viewport.from === "number", "viewport.from exists"); + test.assert(typeof viewport.to === "number", "viewport.to exists"); + test.assert(viewport.to > viewport.from, "viewport has range"); }); }); - // Test 17: Redo manager - runner.test("Redo manager works", async (test) => { - await withEditor(test, async (editor) => { - const session = editor.getSession(); - const undoManager = session.getUndoManager(); + // ========================================= + // CODEMIRROR-SPECIFIC FEATURES + // ========================================= - session.setValue("one"); - undoManager.reset(); + runner.test("EditorState facets", async (test) => { + const { view, container } = createEditor("test"); + + try { + const readOnly = view.state.facet(EditorState.readOnly); + test.assert(typeof readOnly === "boolean", "readOnly facet exists"); + test.assertEqual(readOnly, false); + } finally { + view.destroy(); + container.remove(); + } + }); - session.insert({ row: 0, column: 3 }, "\ntwo"); - editor.undo(); - editor.redo(); + runner.test("Read-only facet value", async (test) => { + const container = document.createElement("div"); + container.style.width = "500px"; + container.style.height = "300px"; + document.body.appendChild(container); - test.assertEqual(editor.getValue(), "one\ntwo"); + const state = EditorState.create({ + doc: "read only content", + extensions: [EditorState.readOnly.of(true)], }); + + const view = new EditorView({ state, parent: container }); + + try { + const isReadOnly = view.state.facet(EditorState.readOnly); + test.assertEqual(isReadOnly, true, "Should report as read-only"); + } finally { + view.destroy(); + container.remove(); + } }); - // Test 18: Focus and blur - runner.test("Focus and blur", async (test) => { - await withEditor(test, async (editor) => { - editor.focus(); - test.assert(editor.isFocused()); + runner.test("Transaction filtering", async (test) => { + let filterCalled = false; - editor.blur(); - test.assert(!editor.isFocused()); + const container = document.createElement("div"); + container.style.width = "500px"; + container.style.height = "300px"; + document.body.appendChild(container); + + const state = EditorState.create({ + doc: "original", + extensions: [ + EditorState.transactionFilter.of((tr) => { + if (tr.docChanged) filterCalled = true; + return tr; + }), + ], + }); + + const view = new EditorView({ state, parent: container }); + + try { + view.dispatch({ + changes: { from: 0, to: 8, insert: "modified" }, + }); + + test.assert(filterCalled, "Transaction filter should be called"); + test.assertEqual(view.state.doc.toString(), "modified"); + } finally { + view.destroy(); + container.remove(); + } + }); + + runner.test("Update listener", async (test) => { + let updateCount = 0; + let docChanged = false; + + const container = document.createElement("div"); + container.style.width = "500px"; + container.style.height = "300px"; + document.body.appendChild(container); + + const state = EditorState.create({ + doc: "", + extensions: [ + EditorView.updateListener.of((update) => { + updateCount++; + if (update.docChanged) docChanged = true; + }), + ], + }); + + const view = new EditorView({ state, parent: container }); + + try { + view.dispatch({ + changes: { from: 0, insert: "hello" }, + }); + + test.assert(updateCount > 0, "Update listener should fire"); + test.assert(docChanged, "docChanged should be true"); + } finally { + view.destroy(); + container.remove(); + } + }); + + runner.test("State effects", async (test) => { + const { StateEffect } = await import("@codemirror/state"); + const myEffect = StateEffect.define(); + + let effectReceived = false; + + const container = document.createElement("div"); + container.style.width = "500px"; + container.style.height = "300px"; + document.body.appendChild(container); + + const state = EditorState.create({ + doc: "", + extensions: [ + EditorView.updateListener.of((update) => { + for (const tr of update.transactions) { + for (const effect of tr.effects) { + if (effect.is(myEffect)) { + effectReceived = true; + } + } + } + }), + ], + }); + + const view = new EditorView({ state, parent: container }); + + try { + view.dispatch({ + effects: myEffect.of("test-value"), + }); + + test.assert(effectReceived, "Custom state effect should be received"); + } finally { + view.destroy(); + container.remove(); + } + }); + + runner.test("Compartments for dynamic config", async (test) => { + const { Compartment } = await import("@codemirror/state"); + + const readOnlyComp = new Compartment(); + + const container = document.createElement("div"); + container.style.width = "500px"; + container.style.height = "300px"; + document.body.appendChild(container); + + const state = EditorState.create({ + doc: "test", + extensions: [readOnlyComp.of(EditorState.readOnly.of(false))], + }); + + const view = new EditorView({ state, parent: container }); + + try { + test.assertEqual(view.state.facet(EditorState.readOnly), false); + + view.dispatch({ + effects: readOnlyComp.reconfigure(EditorState.readOnly.of(true)), + }); + + test.assertEqual(view.state.facet(EditorState.readOnly), true); + } finally { + view.destroy(); + container.remove(); + } + }); + + runner.test("Document iteration", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "line1\nline2\nline3" }, + }); + + const lines = []; + for (let i = 1; i <= view.state.doc.lines; i++) { + lines.push(view.state.doc.line(i).text); + } + + test.assertEqual(lines.length, 3); + test.assertEqual(lines[0], "line1"); + test.assertEqual(lines[1], "line2"); + test.assertEqual(lines[2], "line3"); + }); + }); + + runner.test("Text iterator", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "hello world" }, + }); + + const iter = view.state.doc.iter(); + let text = ""; + while (!iter.done) { + text += iter.value; + iter.next(); + } + + test.assertEqual(text, "hello world"); + }); + }); + + runner.test("Slice string", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "hello world" }, + }); + + test.assertEqual(view.state.doc.sliceString(0, 5), "hello"); + test.assertEqual(view.state.doc.sliceString(6, 11), "world"); + test.assertEqual(view.state.doc.sliceString(6), "world"); + }); + }); + + runner.test("Line at position", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "aaa\nbbb\nccc" }, + }); + + const lineAtStart = view.state.doc.lineAt(0); + test.assertEqual(lineAtStart.number, 1); + + const lineAtMiddle = view.state.doc.lineAt(5); + test.assertEqual(lineAtMiddle.number, 2); + + const lineAtEnd = view.state.doc.lineAt(10); + test.assertEqual(lineAtEnd.number, 3); + }); + }); + + runner.test("Visible ranges", async (test) => { + await withEditor(test, async (view) => { + const longDoc = Array(100).fill("content").join("\n"); + view.dispatch({ + changes: { from: 0, insert: longDoc }, + }); + + const visibleRanges = view.visibleRanges; + test.assert(Array.isArray(visibleRanges), "visibleRanges is an array"); + test.assert(visibleRanges.length > 0, "Should have visible ranges"); + + for (const range of visibleRanges) { + test.assert(typeof range.from === "number", "range.from exists"); + test.assert(typeof range.to === "number", "range.to exists"); + } + }); + }); + + runner.test("coordsAtPos", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "hello" }, + }); + + const coords = view.coordsAtPos(0); + test.assert(coords != null, "coords should exist"); + test.assert(typeof coords.left === "number", "coords.left exists"); + test.assert(typeof coords.top === "number", "coords.top exists"); + }); + }); + + runner.test("posAtCoords", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "hello world" }, + }); + + const rect = view.contentDOM.getBoundingClientRect(); + const pos = view.posAtCoords({ x: rect.left + 10, y: rect.top + 10 }); + + test.assert(pos != null || pos === null, "posAtCoords should return"); + }); + }); + + runner.test("lineBlockAt", async (test) => { + await withEditor(test, async (view) => { + view.dispatch({ + changes: { from: 0, insert: "line1\nline2\nline3" }, + }); + + const line2Start = view.state.doc.line(2).from; + const block = view.lineBlockAt(line2Start); + + test.assert(block != null, "lineBlockAt should return block"); + test.assert(typeof block.from === "number", "block.from exists"); + test.assert(typeof block.to === "number", "block.to exists"); + test.assert(typeof block.height === "number", "block.height exists"); }); }); return await runner.run(writeOutput); } + +export { runCodeMirrorTests as runAceEditorTests }; diff --git a/src/test/tester.js b/src/test/tester.js index 62dfa163b..fbfc16307 100644 --- a/src/test/tester.js +++ b/src/test/tester.js @@ -1,4 +1,5 @@ -import { runAceEditorTests } from "./editor.tests"; +import { runAceCompatibilityTests } from "./ace.test"; +import { runCodeMirrorTests } from "./editor.tests"; import { runExecutorTests } from "./exec.tests"; import { runSanityTests } from "./sanity.tests"; @@ -16,7 +17,8 @@ export async function runAllTests() { try { // Run unit tests await runSanityTests(write); - await runAceEditorTests(write); + await runCodeMirrorTests(write); + await runAceCompatibilityTests(write); await runExecutorTests(write); write("\x1b[36m\x1b[1mTests completed!\x1b[0m\n"); diff --git a/src/theme/preInstalled.js b/src/theme/preInstalled.js index 0389f203f..1e3584bd5 100644 --- a/src/theme/preInstalled.js +++ b/src/theme/preInstalled.js @@ -45,7 +45,7 @@ oled.activeTextColor = "rgb(255, 255, 255)"; oled.errorTextColor = "rgb(255, 69, 58)"; oled.dangerColor = "rgb(255, 69, 58)"; oled.scrollbarColor = "rgba(255, 255, 255, 0.1)"; -oled.preferredEditorTheme = "ace/theme/terminal"; +oled.preferredEditorTheme = "tokyoNight"; const ocean = createBuiltInTheme("Ocean"); ocean.darkenedPrimaryColor = "rgb(19, 19, 26)"; @@ -61,7 +61,7 @@ ocean.popupBackgroundColor = "rgb(32, 32, 44)"; ocean.popupTextColor = WHITE; ocean.popupActiveColor = "rgb(255, 215, 0)"; ocean.boxShadowColor = "rgba(0, 0, 0, 0.5)"; -ocean.preferredEditorTheme = "ace/theme/solarized_dark"; +ocean.preferredEditorTheme = "solarizedDark"; ocean.preferredFont = "Fira Code"; const bump = createBuiltInTheme("Bump"); @@ -80,7 +80,7 @@ bump.popupActiveColor = "rgb(255, 215, 0)"; bump.buttonBackgroundColor = "rgb(242, 163, 101)"; bump.buttonTextColor = "rgb(236, 236, 236)"; bump.buttonActiveColor = "rgb(212, 137, 79)"; -bump.preferredEditorTheme = "ace/theme/one_dark"; +bump.preferredEditorTheme = "one_dark"; const bling = createBuiltInTheme("Bling"); bling.darkenedPrimaryColor = "rgb(19, 19, 38)"; @@ -98,7 +98,6 @@ bling.popupActiveColor = "rgb(51, 153, 255)"; bling.buttonBackgroundColor = "rgb(255, 99, 99)"; bling.buttonTextColor = "rgb(255, 189, 105)"; bling.buttonActiveColor = "rgb(160, 99, 52)"; -bling.preferredEditorTheme = "ace/theme/tomorrow_night_blue"; const moon = createBuiltInTheme("Moon"); moon.darkenedPrimaryColor = "rgb(20, 24, 29)"; @@ -116,7 +115,7 @@ moon.popupActiveColor = "rgb(51, 153, 255)"; moon.buttonBackgroundColor = "rgb(0, 173, 181)"; moon.buttonTextColor = "rgb(0, 142, 149)"; moon.buttonActiveColor = "rgb(0, 173, 181)"; -moon.preferredEditorTheme = "ace/theme/one_dark"; +moon.preferredEditorTheme = "tokyoNight"; const atticus = createBuiltInTheme("Atticus"); atticus.darkenedPrimaryColor = "rgb(32, 30, 30)"; @@ -134,7 +133,6 @@ atticus.popupActiveColor = "rgb(51, 153, 255)"; atticus.buttonBackgroundColor = "rgb(225, 100, 40)"; atticus.buttonTextColor = "rgb(246, 233, 233)"; atticus.buttonActiveColor = "rgb(0, 145, 153)"; -atticus.preferredEditorTheme = "ace/theme/pastel_on_dark"; const tomyris = createBuiltInTheme("Tomyris"); tomyris.darkenedPrimaryColor = "rgb(32, 30, 30)"; @@ -152,7 +150,6 @@ tomyris.popupActiveColor = "rgb(51, 153, 255)"; tomyris.buttonBackgroundColor = "rgb(161, 37, 89)"; tomyris.buttonTextColor = "rgb(241, 187, 213)"; tomyris.buttonActiveColor = "rgb(0, 145, 153)"; -tomyris.preferredEditorTheme = "ace/theme/cobalt"; const menes = createBuiltInTheme("Menes"); menes.darkenedPrimaryColor = "rgb(31, 34, 38)"; @@ -170,7 +167,6 @@ menes.popupActiveColor = "rgb(51, 153, 255)"; menes.buttonBackgroundColor = "rgb(95, 133, 219)"; menes.buttonTextColor = "rgb(144, 184, 248)"; menes.buttonActiveColor = "rgb(0, 145, 153)"; -menes.preferredEditorTheme = "ace/theme/nord_dark"; const light = createBuiltInTheme("Light", "light"); light.primaryColor = "rgb(255, 255, 255)"; @@ -194,9 +190,9 @@ const system = createBuiltInTheme("System", "dark", "free"); export function getSystemEditorTheme(darkTheme) { if (darkTheme) { - return "ace/theme/clouds_midnight"; + return "one_dark"; } else { - return "ace/theme/crimson_editor"; + return "noctisLilac"; } } @@ -282,7 +278,7 @@ neon.buttonBackgroundColor = "rgb(255, 20, 147)"; neon.buttonTextColor = "rgb(0, 0, 0)"; neon.buttonActiveColor = "rgb(0, 255, 255)"; neon.boxShadowColor = "rgba(10, 255, 200, 0.2)"; -neon.preferredEditorTheme = "ace/theme/monokai"; +neon.preferredEditorTheme = "monokai"; neon.activeTextColor = "rgb(0, 0, 0)"; neon.errorTextColor = "rgb(255, 20, 147)"; neon.dangerColor = "rgb(255, 20, 147)"; @@ -309,7 +305,7 @@ glassDark.activeTextColor = "rgb(255, 255, 255)"; glassDark.errorTextColor = "rgb(248, 113, 113)"; glassDark.dangerColor = "rgb(239, 68, 68)"; glassDark.scrollbarColor = "rgba(255, 255, 255, 0.2)"; -glassDark.preferredEditorTheme = "ace/theme/one_dark"; +glassDark.preferredEditorTheme = "tokyoNight"; const sunset = createBuiltInTheme("Sunset"); sunset.darkenedPrimaryColor = "rgb(251, 243, 235)"; diff --git a/src/utils/codeHighlight.js b/src/utils/codeHighlight.js new file mode 100644 index 000000000..1b587dfc3 --- /dev/null +++ b/src/utils/codeHighlight.js @@ -0,0 +1,323 @@ +import { classHighlighter, highlightCode } from "@lezer/highlight"; +import { getModeForPath, getModesByName } from "cm/modelist"; +import { getThemeConfig } from "cm/themes"; +import DOMPurify from "dompurify"; +import settings from "lib/settings"; + +const highlightCache = new Map(); +const MAX_CACHE_SIZE = 500; + +let styleElement = null; +let currentThemeId = null; + +export function sanitize(text) { + if (!text) return ""; + return DOMPurify.sanitize(text, { ALLOWED_TAGS: [] }); +} + +function escapeHtml(text) { + return text + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function addSymbolHighlight(html, symbol) { + if (!symbol) return html; + const escapedSymbol = escapeRegExp(sanitize(symbol)); + const regex = new RegExp(`(${escapedSymbol})`, "gi"); + return html.replace(regex, '$1'); +} + +function setCache(key, value) { + if (highlightCache.size >= MAX_CACHE_SIZE) { + const firstKey = highlightCache.keys().next().value; + highlightCache.delete(firstKey); + } + highlightCache.set(key, value); +} + +/** + * Generates CSS styles for syntax highlighting tokens + * @param {Object} config - Theme config with color values + * @param {string} selector - CSS selector to scope styles + * @param {boolean} includeBackground - Whether to include background/foreground base styles + */ +function generateStyles(config, selector, includeBackground = true) { + const c = config; + const keyword = c.keyword || "#c678dd"; + const string = c.string || "#98c379"; + const number = c.number || "#d19a66"; + const comment = c.comment || "#5c6370"; + const func = c.function || "#61afef"; + const variable = c.variable || "#e06c75"; + const type = c.type || "#e5c07b"; + const className = c.class || type; + const constant = c.constant || number; + const operator = c.operator || keyword; + const invalid = c.invalid || "#ff6b6b"; + const foreground = c.foreground || "#abb2bf"; + const background = c.background || "#282c34"; + + const baseStyles = includeBackground + ? ` +${selector} { + background: ${background}; + color: ${foreground}; +}` + : ""; + + return `${baseStyles} +${selector} .tok-keyword { color: ${keyword}; } +${selector} .tok-operator { color: ${operator}; } +${selector} .tok-number { color: ${number}; } +${selector} .tok-string { color: ${string}; } +${selector} .tok-comment { color: ${comment}; font-style: italic; } +${selector} .tok-variableName { color: ${variable}; } +${selector} .tok-propertyName { color: ${func}; } +${selector} .tok-typeName { color: ${type}; } +${selector} .tok-className { color: ${className}; } +${selector} .tok-function { color: ${func}; } +${selector} .tok-bool { color: ${constant}; } +${selector} .tok-null { color: ${constant}; } +${selector} .tok-punctuation { color: ${foreground}; } +${selector} .tok-definition { color: ${variable}; } +${selector} .tok-labelName { color: ${variable}; } +${selector} .tok-namespace { color: ${type}; } +${selector} .tok-macroName { color: ${keyword}; } +${selector} .tok-atom { color: ${constant}; } +${selector} .tok-meta { color: ${foreground}; } +${selector} .tok-heading { color: ${variable}; font-weight: bold; } +${selector} .tok-link { color: ${func}; text-decoration: underline; } +${selector} .tok-strikethrough { text-decoration: line-through; } +${selector} .tok-emphasis { font-style: italic; } +${selector} .tok-strong { font-weight: bold; } +${selector} .tok-invalid { color: ${invalid}; } +${selector} .tok-name { color: ${variable}; } +${selector} .tok-deleted { color: ${invalid}; } +${selector} .tok-inserted { color: ${string}; } +${selector} .tok-changed { color: ${number}; } +`.trim(); +} + +/** + * Injects dynamic CSS for syntax highlighting based on current editor theme + */ +function injectStyles() { + const themeId = settings?.value?.editorTheme || "one_dark"; + const config = getThemeConfig(themeId); + + // Code blocks need background, references panel uses parent's background + const codeBlockStyles = generateStyles(config, ".cm-highlighted", true); + const refPreviewStyles = generateStyles(config, ".ref-preview", false); + const allStyles = `${codeBlockStyles}\n${refPreviewStyles}`; + + if (!styleElement) { + styleElement = document.createElement("style"); + styleElement.id = "cm-static-highlight-styles"; + document.head.appendChild(styleElement); + } + + styleElement.textContent = allStyles; + currentThemeId = themeId; +} + +/** + * Gets the language parser for a given URI using the modelist + */ +async function getLanguageParser(uri) { + const mode = getModeForPath(uri); + if (!mode?.languageExtension) return null; + + try { + const langExt = await mode.languageExtension(); + if (!langExt) return null; + + const langArray = Array.isArray(langExt) ? langExt : [langExt]; + for (const ext of langArray) { + if (ext && typeof ext === "object" && "language" in ext) { + return ext.language.parser; + } + } + } catch (e) { + console.warn("Failed to get language parser for", uri, e); + } + return null; +} + +/** + * Gets language parser by language name (e.g., "javascript", "python") + * Uses modelist to find the mode and get first valid extension for file matching + */ +async function getParserForLanguage(langName) { + if (!langName) return null; + + const modesByName = getModesByName(); + const normalizedName = langName.toLowerCase(); + + // Try to find mode by name (case-insensitive) + const mode = modesByName[normalizedName]; + if (mode?.languageExtension) { + try { + const langExt = await mode.languageExtension(); + if (!langExt) return null; + + const langArray = Array.isArray(langExt) ? langExt : [langExt]; + for (const ext of langArray) { + if (ext && typeof ext === "object" && "language" in ext) { + return ext.language.parser; + } + } + } catch (e) { + console.warn("Failed to get parser for language:", langName, e); + } + } + + // Fallback: create a fake filename and use getModeForPath + // This handles cases where the language name doesn't match mode name exactly + const fakeUri = `file.${normalizedName}`; + return await getLanguageParser(fakeUri); +} + +/** + * Highlights a single line of code for display in references panel + * @param {string} text - The line of code to highlight + * @param {string} uri - File URI for language detection + * @param {string|null} symbolName - Optional symbol to highlight with special styling + */ +export async function highlightLine(text, uri, symbolName = null) { + if (!text || !text.trim()) return ""; + + const themeId = settings?.value?.editorTheme || "one_dark"; + const cacheKey = `line:${themeId}:${uri}:${text}:${symbolName || ""}`; + + if (highlightCache.has(cacheKey)) { + return highlightCache.get(cacheKey); + } + + const trimmedText = text.trim(); + + try { + const parser = await getLanguageParser(uri); + if (parser) { + const tree = parser.parse(trimmedText); + let result = ""; + + highlightCode( + trimmedText, + tree, + classHighlighter, + (code, classes) => { + if (classes) { + result += `${escapeHtml(code)}`; + } else { + result += escapeHtml(code); + } + }, + () => {}, + ); + + if (result) { + const highlighted = symbolName + ? addSymbolHighlight(result, symbolName) + : result; + setCache(cacheKey, highlighted); + return highlighted; + } + } + } catch (e) { + console.warn("Highlighting failed for", uri, e); + } + + const escaped = escapeHtml(trimmedText); + const highlighted = symbolName + ? addSymbolHighlight(escaped, symbolName) + : escaped; + setCache(cacheKey, highlighted); + return highlighted; +} + +/** + * Highlights a code block for display in markdown/plugin pages + * @param {string} code - The code to highlight + * @param {string} language - Language identifier from markdown fence (e.g., "javascript", "python") + */ +export async function highlightCodeBlock(code, language) { + if (!code) return ""; + + const themeId = settings?.value?.editorTheme || "one_dark"; + const langKey = (language || "text").toLowerCase(); + + const cacheKey = `block:${themeId}:${langKey}:${code}`; + if (highlightCache.has(cacheKey)) { + return highlightCache.get(cacheKey); + } + + try { + const parser = await getParserForLanguage(langKey); + if (parser) { + const tree = parser.parse(code); + let result = ""; + + highlightCode( + code, + tree, + classHighlighter, + (text, classes) => { + if (classes) { + result += `${escapeHtml(text)}`; + } else { + result += escapeHtml(text); + } + }, + () => { + result += "\n"; + }, + ); + + if (result) { + setCache(cacheKey, result); + return result; + } + } + } catch (e) { + console.warn("Code block highlighting failed for", language, e); + } + + const escaped = escapeHtml(code); + setCache(cacheKey, escaped); + return escaped; +} + +export function clearHighlightCache() { + highlightCache.clear(); +} + +/** + * Initializes the static code highlighting system. + * Injects theme-based CSS and sets up listener for theme changes. + */ +export function initHighlighting() { + injectStyles(); + + settings.on("update:editorTheme:after", () => { + const newThemeId = settings?.value?.editorTheme || "one_dark"; + if (newThemeId !== currentThemeId) { + injectStyles(); + highlightCache.clear(); + } + }); +} + +export default { + sanitize, + highlightLine, + highlightCodeBlock, + clearHighlightCache, + initHighlighting, +}; diff --git a/src/utils/color/regex.js b/src/utils/color/regex.js index 5f3fa5061..5b239bcee 100644 --- a/src/utils/color/regex.js +++ b/src/utils/color/regex.js @@ -247,40 +247,46 @@ export const colorRegex = { }; /** - * Select the color at current line and cursor position - * @returns {AceAjax.Range} + * Select the color at current line and cursor position (CodeMirror) + * @returns {{from:number,to:number}|null} */ export function getColorRange() { const { editor } = editorManager; - const copyText = editor.getCopyText(); - if (copyText) { - if (!isValidColor(copyText)) return null; - return editor.selection.getRange(); - } + try { + const sel = editor.state.selection.main; + const from = sel.from; + const to = sel.to; - const { Range } = ace.require("ace/range"); - let range; + // If there is a selection, validate and return it + if (from !== to) { + const text = editor.state.doc.sliceString(from, to); + if (!isValidColor(text)) return null; + return { from, to }; + } - const cursorPos = editor.selection.getCursor(); - /**@type {string} */ - const line = editor.session.getLine(cursorPos.row); + // No selection: find color under cursor in the current line + const head = sel.head; + const line = editor.state.doc.lineAt(head); + const lineText = line.text; + const col = head - line.from; - // match color in current line and get range - const regex = colorRegex.anyGlobal; - let match; + const regex = colorRegex.anyGlobal; + let match; - while ((match = regex.exec(line))) { - const start = match.index + match[1].length; - const end = start + match[2].length; + while ((match = regex.exec(lineText))) { + const startCol = match.index + match[1].length; + const endCol = startCol + match[2].length; - if (cursorPos.column >= start && cursorPos.column <= end) { - range = new Range(cursorPos.row, start, cursorPos.row, end); - break; + if (col >= startCol && col <= endCol) { + return { from: line.from + startCol, to: line.from + endCol }; + } } - } - return range; + return null; + } catch { + return null; + } } export function isValidColor(value) { diff --git a/src/utils/helpers.js b/src/utils/helpers.js index f39c14c40..0a9c69434 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -1,5 +1,6 @@ import fsOperation from "fileSystem"; import ajax from "@deadlyjack/ajax"; +import { getModeForPath as getCMModeForPath } from "cm/modelist"; import alert from "dialogs/alert"; import escapeStringRegexp from "escape-string-regexp"; import constants from "lib/constants"; @@ -73,11 +74,17 @@ export default { * @param {string} filename */ getIconForFile(filename) { - const { getModeForPath } = ace.require("ace/ext/modelist"); const type = getFileType(filename); - const { name } = getModeForPath(filename); + // Use CodeMirror's modelist to determine mode name + let modeName = "text"; + try { + const mode = getCMModeForPath?.(filename); + modeName = mode?.name || modeName; + } catch (e) { + // fallback to default if CodeMirror modelist isn't available yet + } - const iconForMode = `file_type_${name}`; + const iconForMode = `file_type_${modeName}`; const iconForType = `file_type_${type}`; return `file file_type_default ${iconForMode} ${iconForType}`; diff --git a/src/views/file-menu.hbs b/src/views/file-menu.hbs index 734e2a5cb..045352f07 100644 --- a/src/views/file-menu.hbs +++ b/src/views/file-menu.hbs @@ -42,6 +42,12 @@ {{format}}
    +{{#has_lsp_servers}} +
  • + LSP Info + +
  • +{{/has_lsp_servers}} {{/is_editor}}
    {{#file_on_disk}} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..c48aa3fa7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "strict": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "declaration": false, + "allowJs": true, + "checkJs": false, + "baseUrl": "./src", + "paths": { + "*": ["*"] + }, + "jsx": "preserve", + "types": ["node"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "platforms", "www", "www/js/ace/**/*"] +} diff --git a/utils/custom-loaders/html-tag-jsx-loader.js b/utils/custom-loaders/html-tag-jsx-loader.js new file mode 100644 index 000000000..e51b96a6f --- /dev/null +++ b/utils/custom-loaders/html-tag-jsx-loader.js @@ -0,0 +1,330 @@ +/** + * Custom loader that transforms JSX to html-tag-js tag() calls + * This uses Babel's parser/transformer but is lighter than full babel-loader + */ +const { parse } = require("@babel/parser"); +const traverse = require("@babel/traverse").default; +const generate = require("@babel/generator").default; +const t = require("@babel/types"); + +module.exports = function htmlTagJsxLoader(source) { + const callback = this.async(); + + // Enable caching for this loader + this.cacheable && this.cacheable(); + + try { + // Debug logging - verify loader is running + // console.log(`🔧 Custom JSX loader processing: ${this.resourcePath}\n`); + + // Determine file type from extension + const isTypeScript = /\.tsx?$/.test(this.resourcePath); + + // Quick check: if no JSX syntax at all, pass through unchanged + // Look for complete JSX opening tags with proper spacing + const hasJSXLike = + /<\/?[A-Z][a-zA-Z0-9]*[^>]*>|<\/?[a-z][a-z0-9-]*[^>]*>/.test(source); + + if (!hasJSXLike) { + return callback(null, source); + } + + // Parse with appropriate plugins + const parserPlugins = ["jsx"]; + if (isTypeScript) { + parserPlugins.push("typescript"); + } + + const ast = parse(source, { + sourceType: "module", + plugins: parserPlugins, + }); + + // Track if we need to add the import + let needsTagImport = false; + let hasJSX = false; + const hasExistingImport = + /import\s+(?:\{[^}]*\btag\b[^}]*\}|tag(?:\s+as\s+\w+)?)\s+from\s+['"]html-tag-js['"]/.test( + source, + ) || + /(?:const|let|var)\s+(?:\{[^}]*\btag\b[^}]*\}|tag)\s*=\s*require\s*\(\s*['"]html-tag-js['"]\s*\)/.test( + source, + ); + + // Transform JSX elements + traverse(ast, { + JSXFragment(path) { + hasJSX = true; + needsTagImport = true; + const { node } = path; + const { children: childrenNode } = node; + + const children = []; + populateChildren(childrenNode, children, t); + const arrayExpression = t.arrayExpression(children); + path.replaceWith(arrayExpression); + }, + + JSXElement(path) { + hasJSX = true; + needsTagImport = true; + const { node } = path; + const { openingElement: el, children: childrenNode } = node; + + let { name: tagName } = el.name; + const { attributes } = el; + + let id; + let className; + const on = []; + const args = []; + const attrs = []; + const children = []; + const options = []; + const events = {}; + let isComponent = + /^(?:[A-Z][a-zA-Z0-9_$]*|(?:[a-zA-Z_$][a-zA-Z0-9_$]*\.)+[a-zA-Z_$][a-zA-Z0-9_$]*)$/.test( + tagName, + ); + + if (el.name.type === "JSXMemberExpression") { + const { object, property } = el.name; + tagName = `${object.name}.${property.name}`; + isComponent = true; + } + + populateChildren(childrenNode, children, t); + + for (const attr of attributes) { + if (attr.type === "JSXSpreadAttribute") { + if (isComponent) { + attrs.push(t.spreadElement(attr.argument)); + } else { + options.push(t.spreadElement(attr.argument)); + } + continue; + } + + let { name, namespace } = attr.name; + + if (!isComponent) { + if (name === "id") { + if (attr.value && attr.value.type === "StringLiteral") { + id = attr.value; + } else if ( + attr.value && + attr.value.type === "JSXExpressionContainer" + ) { + id = attr.value.expression; + } + continue; + } + + if (["class", "className"].includes(name)) { + if (attr.value && attr.value.type === "StringLiteral") { + className = attr.value; + } else if ( + attr.value && + attr.value.type === "JSXExpressionContainer" + ) { + className = attr.value.expression; + } + continue; + } + } + + if (namespace) { + namespace = namespace.name; + name = name.name; + } + + if (!attr.value) { + attrs.push( + t.objectProperty(t.stringLiteral(name), t.stringLiteral("")), + ); + continue; + } + + const { type } = attr.value; + const isAttr = /-/.test(name); + let value; + + if (type === "StringLiteral") { + value = attr.value; + } else { + value = attr.value.expression; + } + + if (namespace) { + if (!["on", "once", "off"].includes(namespace)) { + attrs.push( + t.objectProperty( + t.stringLiteral( + namespace === "attr" ? name : `${namespace}:${name}`, + ), + value, + ), + ); + continue; + } + + if (namespace === "off") continue; + + if (!events[name]) { + events[name] = []; + on.push( + t.objectProperty( + t.stringLiteral(name), + t.arrayExpression(events[name]), + ), + ); + } + + events[name].push(value); + continue; + } + + if (isAttr) { + const attrRegex = /^attr-(.+)/; + if (attrRegex.test(name)) { + [, name] = attrRegex.exec(name); + } + + attrs.push(t.objectProperty(t.stringLiteral(name), value)); + continue; + } + + (isComponent ? attrs : options).unshift( + t.objectProperty(t.identifier(name), value), + ); + } + + if (isComponent) { + args.push(t.identifier(tagName)); + + if (on.length > 0) { + attrs.push( + t.objectProperty(t.identifier("on"), t.objectExpression(on)), + ); + } + + if (attrs.length > 0) { + args.push(t.objectExpression(attrs)); + } + + if (children.length > 0) { + args.push(t.arrayExpression(children)); + } + } else { + args.push(t.stringLiteral(tagName)); + + if (on.length > 0) { + options.push( + t.objectProperty(t.identifier("on"), t.objectExpression(on)), + ); + } + + if (attrs.length > 0) { + options.push( + t.objectProperty(t.identifier("attr"), t.objectExpression(attrs)), + ); + } + + if (id || className) { + if (className) { + args.push(className); + } else { + args.push(t.nullLiteral()); + } + + if (id) { + args.push(id); + } else if (className) { + // Push null for id when we have className but no id + args.push(t.nullLiteral()); + } + } + + if (children.length) { + args.push(t.arrayExpression(children)); + } + + if (options.length) { + args.push(t.objectExpression(options)); + } + } + + const identifier = t.identifier("tag"); + const callExpression = t.callExpression(identifier, args); + path.replaceWith(callExpression); + }, + }); + + // If no JSX was found, return original source + if (!hasJSX) { + return callback(null, source); + } + + // Generate the transformed code + const output = generate( + ast, + { + sourceMaps: true, + sourceFileName: this.resourcePath, + retainLines: false, + compact: false, + }, + source, + ); + + // Add import if needed + if (needsTagImport && !hasExistingImport) { + output.code = `import tag from 'html-tag-js';\n${output.code}`; + } + + callback(null, output.code, output.map); + } catch (error) { + const errorMessage = `html-tag-jsx-loader failed to process ${this.resourcePath}: ${error.message}`; + const enhancedError = new Error(errorMessage); + enhancedError.stack = error.stack; + callback(enhancedError); + } +}; + +/** + * Parse node to expression + */ +function parseNode(types, node) { + const { type } = node; + if (type === "JSXText") { + const trimmed = node.value.trim(); + if (!trimmed) return null; + // Preserve original text if it contains non-whitespace + // This maintains intentional spacing like "Hello " in Hello + return types.stringLiteral(node.value); + } + + if (type === "JSXElement") { + return node; + } + + const { expression } = node; + const invalidExpressions = ["JSXEmptyExpression"]; + + if (invalidExpressions.includes(expression.type)) { + return null; + } + + return expression; +} + +/** + * Populate children + */ +function populateChildren(childrenNode, children, t) { + for (let node of childrenNode) { + node = parseNode(t, node); + if (!node) continue; + children.push(node); + } +} diff --git a/utils/extra-icons/lightbulb.svg b/utils/extra-icons/lightbulb.svg new file mode 100644 index 000000000..f177a19a8 --- /dev/null +++ b/utils/extra-icons/lightbulb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/utils/scripts/build.sh b/utils/scripts/build.sh index 7b7e73b8f..ea5834040 100644 --- a/utils/scripts/build.sh +++ b/utils/scripts/build.sh @@ -80,7 +80,7 @@ RED='' NC='' script1="node ./utils/config.js $mode $app" -script2="webpack --progress --mode $webpackmode " +script2="rspack --mode $webpackmode" # script3="node ./utils/loadStyles.js" echo "type : $packageType" diff --git a/utils/scripts/start.sh b/utils/scripts/start.sh index 9418aa48a..fd9cb5ecb 100644 --- a/utils/scripts/start.sh +++ b/utils/scripts/start.sh @@ -30,7 +30,7 @@ fi RED='' NC='' script1="node ./utils/config.js $mode $app" -script2="webpack --progress --mode $webpackmode " +script2="rspack --mode $webpackmode" # script3="node ./utils/loadStyles.js" script4="cordova run $platform $cordovamode" eval " @@ -42,4 +42,4 @@ $script2&& # $script3; echo \"${RED}$script4${NC}\"; $script4 -" \ No newline at end of file +" diff --git a/utils/setup.js b/utils/setup.js index 9eaafa923..f410253eb 100644 --- a/utils/setup.js +++ b/utils/setup.js @@ -12,7 +12,7 @@ const fs = require("node:fs"); const path = require("node:path"); const PLATFORM_FILES = [".DS_Store"]; -execSync("npm install", { stdio: "inherit" }); +execSync("bun install", { stdio: "inherit" }); try { execSync("cordova platform add android", { stdio: "inherit" }); } catch (error) { diff --git a/webpack.config.js b/webpack.config.js index 29c42385d..f66bc6e3a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -7,6 +7,25 @@ const WWW = path.resolve(__dirname, 'www'); module.exports = (env, options) => { const { mode = 'development' } = options; const rules = [ + { + test: /\.tsx?$/, + exclude: /node_modules/, + use: [ + 'html-tag-js/jsx/tag-loader.js', + { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env', '@babel/preset-typescript'], + }, + }, + { + loader: 'ts-loader', + options: { + transpileOnly: true, // Skip type checking for faster builds + }, + }, + ], + }, { test: /\.(hbs|md)$/, use: ['raw-loader'], @@ -39,6 +58,7 @@ module.exports = (env, options) => { // if (mode === 'production') { rules.push({ test: /\.m?js$/, + exclude: /node_modules\/(@codemirror|codemirror|marked)/, // Exclude CodeMirror and marked files from html-tag-js loader use: [ 'html-tag-js/jsx/tag-loader.js', { @@ -49,6 +69,34 @@ module.exports = (env, options) => { }, ], }); + + // Separate rule for CodeMirror files - only babel-loader, no html-tag-js + rules.push({ + test: /\.m?js$/, + include: /node_modules\/(@codemirror|codemirror)/, + use: [ + { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'], + }, + }, + ], + }); + + // Separate rule for CodeMirror files - only babel-loader, no html-tag-js + rules.push({ + test: /\.m?js$/, + include: /node_modules\/(@codemirror|codemirror)/, + use: [ + { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'], + }, + }, + ], + }); // } const main = { @@ -56,6 +104,7 @@ module.exports = (env, options) => { entry: { main: './src/main.js', console: './src/lib/console.js', + searchInFilesWorker: './src/sidebarApps/searchInFiles/worker.js', }, output: { path: path.resolve(__dirname, 'www/build/'), @@ -69,6 +118,7 @@ module.exports = (env, options) => { rules, }, resolve: { + extensions: ['.ts', '.tsx', '.js', '.mjs', '.json'], fallback: { path: require.resolve('path-browserify'), crypto: false, @@ -83,4 +133,4 @@ module.exports = (env, options) => { }; return [main]; -}; \ No newline at end of file +}; diff --git a/www/index.html b/www/index.html index e305fb525..c6139bea9 100644 --- a/www/index.html +++ b/www/index.html @@ -86,22 +86,6 @@ - - - - - - - - - - - - - - - -