Use guesslang to detect the language

This commit is contained in:
2025-06-19 16:55:02 +08:00
parent f2894b2a89
commit 25858cb42b
12 changed files with 724 additions and 790 deletions

View File

@@ -21,7 +21,7 @@
"@codemirror/lang-less": "^6.0.2", "@codemirror/lang-less": "^6.0.2",
"@codemirror/lang-lezer": "^6.0.1", "@codemirror/lang-lezer": "^6.0.1",
"@codemirror/lang-liquid": "^6.2.3", "@codemirror/lang-liquid": "^6.2.3",
"@codemirror/lang-markdown": "^6.3.2", "@codemirror/lang-markdown": "^6.3.3",
"@codemirror/lang-php": "^6.0.1", "@codemirror/lang-php": "^6.0.1",
"@codemirror/lang-python": "^6.2.1", "@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.1", "@codemirror/lang-rust": "^6.0.1",
@@ -37,7 +37,7 @@
"@codemirror/lint": "^6.8.5", "@codemirror/lint": "^6.8.5",
"@codemirror/search": "^6.5.11", "@codemirror/search": "^6.5.11",
"@codemirror/state": "^6.5.2", "@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.37.1", "@codemirror/view": "^6.37.2",
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.1",
"@lezer/lr": "^1.4.2", "@lezer/lr": "^1.4.2",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
@@ -48,24 +48,24 @@
"colors-named-hex": "^1.0.2", "colors-named-hex": "^1.0.2",
"hsl-matcher": "^1.2.4", "hsl-matcher": "^1.2.4",
"lezer": "^0.13.5", "lezer": "^0.13.5",
"pinia": "^3.0.2", "pinia": "^3.0.3",
"sass": "^1.89.1", "sass": "^1.89.2",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vue": "^3.5.16", "vue": "^3.5.17",
"vue-i18n": "^11.1.5", "vue-i18n": "^11.1.6",
"vue-router": "^4.5.1" "vue-router": "^4.5.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.28.0", "@eslint/js": "^9.29.0",
"@lezer/generator": "^1.7.3", "@lezer/generator": "^1.7.3",
"@types/node": "^22.15.29", "@types/node": "^24.0.3",
"@vitejs/plugin-vue": "^5.2.4", "@vitejs/plugin-vue": "^5.2.4",
"@wailsio/runtime": "latest", "@wailsio/runtime": "latest",
"eslint": "^9.28.0", "eslint": "^9.29.0",
"eslint-plugin-vue": "^10.1.0", "eslint-plugin-vue": "^10.2.0",
"globals": "^16.2.0", "globals": "^16.2.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.33.1", "typescript-eslint": "^8.34.1",
"unplugin-vue-components": "^28.7.0", "unplugin-vue-components": "^28.7.0",
"vite": "^6.3.5", "vite": "^6.3.5",
"vue-eslint-parser": "^10.1.3", "vue-eslint-parser": "^10.1.3",
@@ -91,12 +91,12 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.27.2", "version": "7.27.5",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.5.tgz",
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.27.1" "@babel/types": "^7.27.3"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -106,9 +106,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.27.1", "version": "7.27.6",
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.1.tgz", "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.6.tgz",
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.27.1", "@babel/helper-string-parser": "^7.27.1",
@@ -286,9 +286,9 @@
} }
}, },
"node_modules/@codemirror/lang-markdown": { "node_modules/@codemirror/lang-markdown": {
"version": "6.3.2", "version": "6.3.3",
"resolved": "https://registry.npmmirror.com/@codemirror/lang-markdown/-/lang-markdown-6.3.2.tgz", "resolved": "https://registry.npmmirror.com/@codemirror/lang-markdown/-/lang-markdown-6.3.3.tgz",
"integrity": "sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==", "integrity": "sha512-1fn1hQAPWlSSMCvnF810AkhWpNLkJpl66CRfIy3vVl20Sl4NwChkorCHqpMtNbXr1EuMJsrDnhEpjZxKZ2UX3A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.7.1", "@codemirror/autocomplete": "^6.7.1",
@@ -503,9 +503,9 @@
} }
}, },
"node_modules/@codemirror/view": { "node_modules/@codemirror/view": {
"version": "6.37.1", "version": "6.37.2",
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.37.1.tgz", "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.37.2.tgz",
"integrity": "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==", "integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@codemirror/state": "^6.5.0", "@codemirror/state": "^6.5.0",
@@ -982,9 +982,9 @@
} }
}, },
"node_modules/@eslint/config-array": { "node_modules/@eslint/config-array": {
"version": "0.20.0", "version": "0.20.1",
"resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.20.0.tgz", "resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.20.1.tgz",
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
@@ -1057,9 +1057,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.28.0", "version": "9.29.0",
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.28.0.tgz", "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.29.0.tgz",
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -1160,13 +1160,13 @@
} }
}, },
"node_modules/@intlify/core-base": { "node_modules/@intlify/core-base": {
"version": "11.1.5", "version": "11.1.6",
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.1.5.tgz", "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.1.6.tgz",
"integrity": "sha512-xGRkISwV/2Trqb8yVQevlHm5roaQqy+75qwUzEQrviaQF0o4c5VDhjBW7WEGEoKFx09HSgq7NkvK/DAyuerTDg==", "integrity": "sha512-gfMLnoWGiQkA1BwK6Qbrog/e3I6Lnkhqk08XObJb0lMq6sLG1Ggl2MazVaMfGnv/E1Td8pCS5UwR54Ys+fOxmQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@intlify/message-compiler": "11.1.5", "@intlify/message-compiler": "11.1.6",
"@intlify/shared": "11.1.5" "@intlify/shared": "11.1.6"
}, },
"engines": { "engines": {
"node": ">= 16" "node": ">= 16"
@@ -1176,12 +1176,12 @@
} }
}, },
"node_modules/@intlify/message-compiler": { "node_modules/@intlify/message-compiler": {
"version": "11.1.5", "version": "11.1.6",
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.1.5.tgz", "resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.1.6.tgz",
"integrity": "sha512-YLSBbjD7qUdShe3ZAat9Hnf9E8FRpN6qmNFD/x5Xg5JVXjsks0kJ90Zj6aAuyoppJQA/YJdWZ8/bB7k3dg2TjQ==", "integrity": "sha512-w0LYo5sqgQZF3vEmjLlx+5PYk5EEiB+uigsBkka/DKoAIH2c5xlXcjAxhTgSw35Vrck+GOGriahFsfbHL+ZjPw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@intlify/shared": "11.1.5", "@intlify/shared": "11.1.6",
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
}, },
"engines": { "engines": {
@@ -1192,9 +1192,9 @@
} }
}, },
"node_modules/@intlify/shared": { "node_modules/@intlify/shared": {
"version": "11.1.5", "version": "11.1.6",
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-11.1.5.tgz", "resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-11.1.6.tgz",
"integrity": "sha512-+I4vRzHm38VjLr/CAciEPJhGYFzWWW4HMTm+6H3WqknXLh0ozNX9oC8ogMUwTSXYR/wGUb1/lTpNziiCH5MybQ==", "integrity": "sha512-G1Pe4UILhiGOItuehRW+Pk9/NlnRaMFsdnhZ1fwBjiHvrzitmPNZdLx7Eo3GPfRrsk1mdkilZSfgH8SnM419vA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 16" "node": ">= 16"
@@ -2093,13 +2093,13 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.15.29", "version": "24.0.3",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.15.29.tgz", "resolved": "https://registry.npmmirror.com/@types/node/-/node-24.0.3.tgz",
"integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==", "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~7.8.0"
} }
}, },
"node_modules/@types/uuid": { "node_modules/@types/uuid": {
@@ -2115,17 +2115,17 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
"integrity": "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==", "integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/scope-manager": "8.34.1",
"@typescript-eslint/type-utils": "8.33.1", "@typescript-eslint/type-utils": "8.34.1",
"@typescript-eslint/utils": "8.33.1", "@typescript-eslint/utils": "8.34.1",
"@typescript-eslint/visitor-keys": "8.33.1", "@typescript-eslint/visitor-keys": "8.34.1",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^7.0.0", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@@ -2139,7 +2139,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.33.1", "@typescript-eslint/parser": "^8.34.1",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <5.9.0" "typescript": ">=4.8.4 <5.9.0"
} }
@@ -2155,16 +2155,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.34.1.tgz",
"integrity": "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==", "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/scope-manager": "8.34.1",
"@typescript-eslint/types": "8.33.1", "@typescript-eslint/types": "8.34.1",
"@typescript-eslint/typescript-estree": "8.33.1", "@typescript-eslint/typescript-estree": "8.34.1",
"@typescript-eslint/visitor-keys": "8.33.1", "@typescript-eslint/visitor-keys": "8.34.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -2180,14 +2180,14 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
"integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==", "integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.33.1", "@typescript-eslint/tsconfig-utils": "^8.34.1",
"@typescript-eslint/types": "^8.33.1", "@typescript-eslint/types": "^8.34.1",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -2202,14 +2202,14 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
"integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==", "integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.33.1", "@typescript-eslint/types": "8.34.1",
"@typescript-eslint/visitor-keys": "8.33.1" "@typescript-eslint/visitor-keys": "8.34.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2220,9 +2220,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
"integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==", "integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2237,14 +2237,14 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
"integrity": "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==", "integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "8.33.1", "@typescript-eslint/typescript-estree": "8.34.1",
"@typescript-eslint/utils": "8.33.1", "@typescript-eslint/utils": "8.34.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@@ -2261,9 +2261,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.34.1.tgz",
"integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==", "integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2275,16 +2275,16 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
"integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==", "integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.33.1", "@typescript-eslint/project-service": "8.34.1",
"@typescript-eslint/tsconfig-utils": "8.33.1", "@typescript-eslint/tsconfig-utils": "8.34.1",
"@typescript-eslint/types": "8.33.1", "@typescript-eslint/types": "8.34.1",
"@typescript-eslint/visitor-keys": "8.33.1", "@typescript-eslint/visitor-keys": "8.34.1",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -2304,9 +2304,9 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.2",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -2330,16 +2330,16 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.34.1.tgz",
"integrity": "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==", "integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.33.1", "@typescript-eslint/scope-manager": "8.34.1",
"@typescript-eslint/types": "8.33.1", "@typescript-eslint/types": "8.34.1",
"@typescript-eslint/typescript-estree": "8.33.1" "@typescript-eslint/typescript-estree": "8.34.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2354,14 +2354,14 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
"integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==", "integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.33.1", "@typescript-eslint/types": "8.34.1",
"eslint-visitor-keys": "^4.2.0" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2415,53 +2415,53 @@
} }
}, },
"node_modules/@vue/compiler-core": { "node_modules/@vue/compiler-core": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.17.tgz",
"integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.27.2", "@babel/parser": "^7.27.5",
"@vue/shared": "3.5.16", "@vue/shared": "3.5.17",
"entities": "^4.5.0", "entities": "^4.5.0",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
} }
}, },
"node_modules/@vue/compiler-dom": { "node_modules/@vue/compiler-dom": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz",
"integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-core": "3.5.16", "@vue/compiler-core": "3.5.17",
"@vue/shared": "3.5.16" "@vue/shared": "3.5.17"
} }
}, },
"node_modules/@vue/compiler-sfc": { "node_modules/@vue/compiler-sfc": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz",
"integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.27.2", "@babel/parser": "^7.27.5",
"@vue/compiler-core": "3.5.16", "@vue/compiler-core": "3.5.17",
"@vue/compiler-dom": "3.5.16", "@vue/compiler-dom": "3.5.17",
"@vue/compiler-ssr": "3.5.16", "@vue/compiler-ssr": "3.5.17",
"@vue/shared": "3.5.16", "@vue/shared": "3.5.17",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"magic-string": "^0.30.17", "magic-string": "^0.30.17",
"postcss": "^8.5.3", "postcss": "^8.5.6",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
} }
}, },
"node_modules/@vue/compiler-ssr": { "node_modules/@vue/compiler-ssr": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz",
"integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.16", "@vue/compiler-dom": "3.5.17",
"@vue/shared": "3.5.16" "@vue/shared": "3.5.17"
} }
}, },
"node_modules/@vue/compiler-vue2": { "node_modules/@vue/compiler-vue2": {
@@ -2560,53 +2560,53 @@
} }
}, },
"node_modules/@vue/reactivity": { "node_modules/@vue/reactivity": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz",
"integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==", "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/shared": "3.5.16" "@vue/shared": "3.5.17"
} }
}, },
"node_modules/@vue/runtime-core": { "node_modules/@vue/runtime-core": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.17.tgz",
"integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==", "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/reactivity": "3.5.16", "@vue/reactivity": "3.5.17",
"@vue/shared": "3.5.16" "@vue/shared": "3.5.17"
} }
}, },
"node_modules/@vue/runtime-dom": { "node_modules/@vue/runtime-dom": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz",
"integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==", "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/reactivity": "3.5.16", "@vue/reactivity": "3.5.17",
"@vue/runtime-core": "3.5.16", "@vue/runtime-core": "3.5.17",
"@vue/shared": "3.5.16", "@vue/shared": "3.5.17",
"csstype": "^3.1.3" "csstype": "^3.1.3"
} }
}, },
"node_modules/@vue/server-renderer": { "node_modules/@vue/server-renderer": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.17.tgz",
"integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==", "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-ssr": "3.5.16", "@vue/compiler-ssr": "3.5.17",
"@vue/shared": "3.5.16" "@vue/shared": "3.5.17"
}, },
"peerDependencies": { "peerDependencies": {
"vue": "3.5.16" "vue": "3.5.17"
} }
}, },
"node_modules/@vue/shared": { "node_modules/@vue/shared": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.17.tgz",
"integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==", "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vueuse/core": { "node_modules/@vueuse/core": {
@@ -2655,9 +2655,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.14.1", "version": "8.15.0",
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.1.tgz", "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@@ -3186,19 +3186,19 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.28.0", "version": "9.29.0",
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.28.0.tgz", "resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.29.0.tgz",
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.20.0", "@eslint/config-array": "^0.20.1",
"@eslint/config-helpers": "^0.2.1", "@eslint/config-helpers": "^0.2.1",
"@eslint/core": "^0.14.0", "@eslint/core": "^0.14.0",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.28.0", "@eslint/js": "9.29.0",
"@eslint/plugin-kit": "^0.3.1", "@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
@@ -3210,9 +3210,9 @@
"cross-spawn": "^7.0.6", "cross-spawn": "^7.0.6",
"debug": "^4.3.2", "debug": "^4.3.2",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^8.3.0", "eslint-scope": "^8.4.0",
"eslint-visitor-keys": "^4.2.0", "eslint-visitor-keys": "^4.2.1",
"espree": "^10.3.0", "espree": "^10.4.0",
"esquery": "^1.5.0", "esquery": "^1.5.0",
"esutils": "^2.0.2", "esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
@@ -3247,9 +3247,9 @@
} }
}, },
"node_modules/eslint-plugin-vue": { "node_modules/eslint-plugin-vue": {
"version": "10.1.0", "version": "10.2.0",
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.1.0.tgz", "resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.2.0.tgz",
"integrity": "sha512-/VTiJ1eSfNLw6lvG9ENySbGmcVvz6wZ9nA7ZqXlLBY2RkaF15iViYKxglWiIch12KiLAj0j1iXPYU6W4wTROFA==", "integrity": "sha512-tl9s+KN3z0hN2b8fV2xSs5ytGl7Esk1oSCxULLwFcdaElhZ8btYYZFrWxvh4En+czrSDtuLCeCOGa8HhEZuBdQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -3269,9 +3269,9 @@
} }
}, },
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "8.3.0", "version": "8.4.0",
"resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.3.0.tgz", "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.4.0.tgz",
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
@@ -3286,9 +3286,9 @@
} }
}, },
"node_modules/eslint-visitor-keys": { "node_modules/eslint-visitor-keys": {
"version": "4.2.0", "version": "4.2.1",
"resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
@@ -3299,15 +3299,15 @@
} }
}, },
"node_modules/espree": { "node_modules/espree": {
"version": "10.3.0", "version": "10.4.0",
"resolved": "https://registry.npmmirror.com/espree/-/espree-10.3.0.tgz", "resolved": "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz",
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"acorn": "^8.14.0", "acorn": "^8.15.0",
"acorn-jsx": "^5.3.2", "acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.2.0" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4204,9 +4204,9 @@
} }
}, },
"node_modules/pinia": { "node_modules/pinia": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-3.0.2.tgz", "resolved": "https://registry.npmmirror.com/pinia/-/pinia-3.0.3.tgz",
"integrity": "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==", "integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/devtools-api": "^7.7.2" "@vue/devtools-api": "^7.7.2"
@@ -4237,9 +4237,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.3", "version": "8.5.6",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz", "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@@ -4256,7 +4256,7 @@
], ],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"nanoid": "^3.3.8", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"source-map-js": "^1.2.1" "source-map-js": "^1.2.1"
}, },
@@ -4454,9 +4454,9 @@
} }
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.89.1", "version": "1.89.2",
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.89.1.tgz", "resolved": "https://registry.npmmirror.com/sass/-/sass-1.89.2.tgz",
"integrity": "sha512-eMLLkl+qz7tx/0cJ9wI+w09GQ2zodTkcE/aVfywwdlRcI3EO19xGnbmJwg/JMIm+5MxVJ6outddLZ4Von4E++Q==", "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"chokidar": "^4.0.0", "chokidar": "^4.0.0",
@@ -4712,15 +4712,15 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.33.1", "version": "8.34.1",
"resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.33.1.tgz", "resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
"integrity": "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==", "integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.33.1", "@typescript-eslint/eslint-plugin": "8.34.1",
"@typescript-eslint/parser": "8.33.1", "@typescript-eslint/parser": "8.34.1",
"@typescript-eslint/utils": "8.33.1" "@typescript-eslint/utils": "8.34.1"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -4769,9 +4769,9 @@
} }
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.21.0", "version": "7.8.0",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz", "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.8.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -5150,16 +5150,16 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vue": { "node_modules/vue": {
"version": "3.5.16", "version": "3.5.17",
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.16.tgz", "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.17.tgz",
"integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==", "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.16", "@vue/compiler-dom": "3.5.17",
"@vue/compiler-sfc": "3.5.16", "@vue/compiler-sfc": "3.5.17",
"@vue/runtime-dom": "3.5.16", "@vue/runtime-dom": "3.5.17",
"@vue/server-renderer": "3.5.16", "@vue/server-renderer": "3.5.17",
"@vue/shared": "3.5.16" "@vue/shared": "3.5.17"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "*" "typescript": "*"
@@ -5196,13 +5196,13 @@
} }
}, },
"node_modules/vue-i18n": { "node_modules/vue-i18n": {
"version": "11.1.5", "version": "11.1.6",
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.1.5.tgz", "resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.1.6.tgz",
"integrity": "sha512-XCwuaEA5AF97g1frvH/EI1zI9uo1XKTf2/OCFgts7NvUWRsjlgeHPrkJV+a3gpzai2pC4quZ4AnOHFO8QK9hsg==", "integrity": "sha512-+IbsW/sTZHj7U1w0rPOYJbuSB0/7DeO1nvUo3BxvO20OQgHs+ukJ3QeLqvoUA6DiLk+8SA9+djRmKC9+FC6cAg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@intlify/core-base": "11.1.5", "@intlify/core-base": "11.1.6",
"@intlify/shared": "11.1.5", "@intlify/shared": "11.1.6",
"@vue/devtools-api": "^6.5.0" "@vue/devtools-api": "^6.5.0"
}, },
"engines": { "engines": {

View File

@@ -25,7 +25,7 @@
"@codemirror/lang-less": "^6.0.2", "@codemirror/lang-less": "^6.0.2",
"@codemirror/lang-lezer": "^6.0.1", "@codemirror/lang-lezer": "^6.0.1",
"@codemirror/lang-liquid": "^6.2.3", "@codemirror/lang-liquid": "^6.2.3",
"@codemirror/lang-markdown": "^6.3.2", "@codemirror/lang-markdown": "^6.3.3",
"@codemirror/lang-php": "^6.0.1", "@codemirror/lang-php": "^6.0.1",
"@codemirror/lang-python": "^6.2.1", "@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.1", "@codemirror/lang-rust": "^6.0.1",
@@ -41,7 +41,7 @@
"@codemirror/lint": "^6.8.5", "@codemirror/lint": "^6.8.5",
"@codemirror/search": "^6.5.11", "@codemirror/search": "^6.5.11",
"@codemirror/state": "^6.5.2", "@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.37.1", "@codemirror/view": "^6.37.2",
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.1",
"@lezer/lr": "^1.4.2", "@lezer/lr": "^1.4.2",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
@@ -52,24 +52,24 @@
"colors-named-hex": "^1.0.2", "colors-named-hex": "^1.0.2",
"hsl-matcher": "^1.2.4", "hsl-matcher": "^1.2.4",
"lezer": "^0.13.5", "lezer": "^0.13.5",
"pinia": "^3.0.2", "pinia": "^3.0.3",
"sass": "^1.89.1", "sass": "^1.89.2",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vue": "^3.5.16", "vue": "^3.5.17",
"vue-i18n": "^11.1.5", "vue-i18n": "^11.1.6",
"vue-router": "^4.5.1" "vue-router": "^4.5.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.28.0", "@eslint/js": "^9.29.0",
"@lezer/generator": "^1.7.3", "@lezer/generator": "^1.7.3",
"@types/node": "^22.15.29", "@types/node": "^24.0.3",
"@vitejs/plugin-vue": "^5.2.4", "@vitejs/plugin-vue": "^5.2.4",
"@wailsio/runtime": "latest", "@wailsio/runtime": "latest",
"eslint": "^9.28.0", "eslint": "^9.29.0",
"eslint-plugin-vue": "^10.1.0", "eslint-plugin-vue": "^10.2.0",
"globals": "^16.2.0", "globals": "^16.2.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.33.1", "typescript-eslint": "^8.34.1",
"unplugin-vue-components": "^28.7.0", "unplugin-vue-components": "^28.7.0",
"vite": "^6.3.5", "vite": "^6.3.5",
"vue-eslint-parser": "^10.1.3", "vue-eslint-parser": "^10.1.3",

28
frontend/public/guesslang.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,48 @@
importScripts("guesslang.min.js")
const LANGUAGES = ["json", "py", "html", "sql", "md", "java", "php", "css", "xml", "cpp", "rs", "cs", "rb", "sh", "yaml", "toml", "go", "clj", "ex", "erl", "js", "ts", "swift", "kt", "groovy", "ps1", "dart", "scala"]
const guessLang = new self.GuessLang()
function sendResult(language, confidence, idx) {
postMessage({language, confidence, idx})
}
onmessage = (event) => {
const {content, idx} = event.data
// JSON 快速检测
const trimmed = content.trim()
if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
(trimmed.startsWith("[") && trimmed.endsWith("]"))) {
try {
if (typeof JSON.parse(trimmed) === "object") {
sendResult("json", 1.0, idx)
return
}
} catch (e) {
}
}
guessLang.runModel(content).then((result) => {
if (result.length > 0) {
const lang = result[0]
if (LANGUAGES.includes(lang.languageId) && lang.confidence > 0.15) {
sendResult(lang.languageId, lang.confidence, idx)
return
}
}
for (let lang of result) {
if (LANGUAGES.includes(lang.languageId) && lang.confidence > 0.5) {
sendResult(lang.languageId, lang.confidence, idx)
return
}
}
sendResult("text", 0.0, idx)
}).catch(() => {
sendResult("text", 0.0, idx)
})
}

View File

@@ -13,28 +13,71 @@ const searchInputRef = ref<HTMLInputElement>();
// 语言别名映射 // 语言别名映射
const LANGUAGE_ALIASES: Record<SupportedLanguage, string> = { const LANGUAGE_ALIASES: Record<SupportedLanguage, string> = {
text: 'txt', text: 'txt',
javascript: 'js', json: 'JSON',
typescript: 'ts', py: 'python',
python: 'py', html: 'HTML',
html: 'htm', sql: 'SQL',
css: '', md: 'markdown',
json: '', java: 'Java',
markdown: 'md', php: 'PHP',
shell: 'sh', css: 'CSS',
sql: '', xml: 'XML',
yaml: 'yml',
xml: '',
php: '',
java: '',
cpp: 'c++', cpp: 'c++',
c: '', rs: 'rust',
go: '', cs: 'c#',
rust: 'rs', rb: 'ruby',
ruby: 'rb' sh: 'shell',
yaml: 'yml',
toml: 'TOML',
go: 'Go',
clj: 'clojure',
ex: 'elixir',
erl: 'erlang',
js: 'javascript',
ts: 'typescript',
swift: 'Swift',
kt: 'kotlin',
groovy: 'Groovy',
ps1: 'powershell',
dart: 'Dart',
scala: 'Scala'
};
// 语言显示名称映射
const LANGUAGE_NAMES: Record<SupportedLanguage, string> = {
text: 'Plain Text',
json: 'JSON',
py: 'Python',
html: 'HTML',
sql: 'SQL',
md: 'Markdown',
java: 'Java',
php: 'PHP',
css: 'CSS',
xml: 'XML',
cpp: 'C++',
rs: 'Rust',
cs: 'C#',
rb: 'Ruby',
sh: 'Shell',
yaml: 'YAML',
toml: 'TOML',
go: 'Go',
clj: 'Clojure',
ex: 'Elixir',
erl: 'Erlang',
js: 'JavaScript',
ts: 'TypeScript',
swift: 'Swift',
kt: 'Kotlin',
groovy: 'Groovy',
ps1: 'PowerShell',
dart: 'Dart',
scala: 'Scala'
}; };
// 当前选中的语言 // 当前选中的语言
const currentLanguage = ref<SupportedLanguage>('javascript'); const currentLanguage = ref<SupportedLanguage>('text');
// 过滤后的语言列表 // 过滤后的语言列表
const filteredLanguages = computed(() => { const filteredLanguages = computed(() => {
@@ -44,8 +87,10 @@ const filteredLanguages = computed(() => {
const query = searchQuery.value.toLowerCase(); const query = searchQuery.value.toLowerCase();
return SUPPORTED_LANGUAGES.filter(langId => { return SUPPORTED_LANGUAGES.filter(langId => {
const name = LANGUAGE_NAMES[langId];
const alias = LANGUAGE_ALIASES[langId]; const alias = LANGUAGE_ALIASES[langId];
return langId.toLowerCase().includes(query) || return langId.toLowerCase().includes(query) ||
(name && name.toLowerCase().includes(query)) ||
(alias && alias.toLowerCase().includes(query)); (alias && alias.toLowerCase().includes(query));
}); });
}); });
@@ -96,7 +141,7 @@ onUnmounted(() => {
// 获取当前语言的显示名称 // 获取当前语言的显示名称
const getCurrentLanguageName = computed(() => { const getCurrentLanguageName = computed(() => {
return currentLanguage.value; return LANGUAGE_NAMES[currentLanguage.value] || currentLanguage.value;
}); });
</script> </script>
@@ -143,8 +188,8 @@ const getCurrentLanguageName = computed(() => {
:class="{ 'active': currentLanguage === language }" :class="{ 'active': currentLanguage === language }"
@click="selectLanguage(language)" @click="selectLanguage(language)"
> >
<span class="language-name">{{ language }}</span> <span class="language-name">{{ LANGUAGE_NAMES[language] || language }}</span>
<span class="language-alias" v-if="LANGUAGE_ALIASES[language]">{{ LANGUAGE_ALIASES[language] }}</span> <span class="language-alias">{{ language }}</span>
</div> </div>
<!-- 无结果提示 --> <!-- 无结果提示 -->

View File

@@ -13,21 +13,20 @@
*/ */
import {Extension} from '@codemirror/state'; import {Extension} from '@codemirror/state';
import {keymap} from '@codemirror/view'; import {keymap, lineNumbers} from '@codemirror/view';
// 导入核心模块 // 导入核心模块
import {blockState} from './state'; import {blockState} from './state';
import {getBlockDecorationExtensions} from './decorations'; import {getBlockDecorationExtensions} from './decorations';
import * as commands from './commands'; import * as commands from './commands';
import {selectAll, getBlockSelectExtensions} from './selectAll'; import {getBlockSelectExtensions, selectAll} from './selectAll';
import {getCopyPasteExtensions, getCopyPasteKeymap} from './copyPaste'; import {getCopyPasteExtensions, getCopyPasteKeymap} from './copyPaste';
import {deleteLineCommand} from './deleteLine'; import {deleteLineCommand} from './deleteLine';
import {moveLineUp, moveLineDown} from './moveLines'; import {moveLineDown, moveLineUp} from './moveLines';
import {transposeChars} from './transposeChars'; import {transposeChars} from './transposeChars';
import {getCodeBlockLanguageExtension} from './lang-parser'; import {getCodeBlockLanguageExtension} from './lang-parser';
import {createLanguageDetection} from './language-detection'; import {createLanguageDetection} from './language-detection';
import {EditorOptions, SupportedLanguage} from './types'; import {EditorOptions, SupportedLanguage} from './types';
import {lineNumbers} from '@codemirror/view';
/** /**
* 代码块扩展配置选项 * 代码块扩展配置选项
@@ -112,8 +111,8 @@ export function createCodeBlockExtension(options: CodeBlockOptions = {}): Extens
// 语言自动检测(如果启用) // 语言自动检测(如果启用)
...(enableAutoDetection ? [createLanguageDetection({ ...(enableAutoDetection ? [createLanguageDetection({
defaultLanguage: defaultLanguage, defaultLanguage: defaultLanguage,
confidenceThreshold: 0.3, confidenceThreshold: 0.15,
minContentLength: 8, minContentLength: 8
})] : []), })] : []),
// 视觉装饰系统 // 视觉装饰系统
@@ -297,14 +296,12 @@ export {
createLanguageDetection, createLanguageDetection,
detectLanguage, detectLanguage,
detectLanguages, detectLanguages,
detectLanguageHeuristic,
getSupportedDetectionLanguages,
levenshteinDistance, levenshteinDistance,
type LanguageDetectionResult type LanguageDetectionResult
} from './language-detection'; } from './language-detection';
// 行号相关 // 行号相关
export { getBlockLineFromPos, blockLineNumbers }; export {getBlockLineFromPos, blockLineNumbers};
/** /**
* 默认导出 * 默认导出

View File

@@ -14,12 +14,21 @@ import { cssLanguage } from "@codemirror/lang-css";
import { cppLanguage } from "@codemirror/lang-cpp"; import { cppLanguage } from "@codemirror/lang-cpp";
import { xmlLanguage } from "@codemirror/lang-xml"; import { xmlLanguage } from "@codemirror/lang-xml";
import { rustLanguage } from "@codemirror/lang-rust"; import { rustLanguage } from "@codemirror/lang-rust";
import { yamlLanguage } from "@codemirror/lang-yaml";
import { StreamLanguage } from "@codemirror/language"; import { StreamLanguage } from "@codemirror/language";
import { ruby } from "@codemirror/legacy-modes/mode/ruby"; import { ruby } from "@codemirror/legacy-modes/mode/ruby";
import { shell } from "@codemirror/legacy-modes/mode/shell"; import { shell } from "@codemirror/legacy-modes/mode/shell";
import { go } from "@codemirror/legacy-modes/mode/go"; import { go } from "@codemirror/legacy-modes/mode/go";
import { yamlLanguage } from "@codemirror/lang-yaml"; import { csharp } from "@codemirror/legacy-modes/mode/clike";
import { clojure } from "@codemirror/legacy-modes/mode/clojure";
import { erlang } from "@codemirror/legacy-modes/mode/erlang";
import { swift } from "@codemirror/legacy-modes/mode/swift";
import { kotlin } from "@codemirror/legacy-modes/mode/clike";
import { groovy } from "@codemirror/legacy-modes/mode/groovy";
import { powerShell } from "@codemirror/legacy-modes/mode/powershell";
import { scala } from "@codemirror/legacy-modes/mode/clike";
import { toml } from "@codemirror/legacy-modes/mode/toml";
import { SupportedLanguage } from '../types'; import { SupportedLanguage } from '../types';
@@ -30,34 +39,43 @@ export class LanguageInfo {
constructor( constructor(
public token: SupportedLanguage, public token: SupportedLanguage,
public name: string, public name: string,
public parser: any, public parser: any
public guesslang?: string | null
) {} ) {}
} }
/** /**
* 支持的语言列表 * 支持的语言列表(与 Worker 中的 LANGUAGES 对应)
*/ */
export const LANGUAGES: LanguageInfo[] = [ export const LANGUAGES: LanguageInfo[] = [
new LanguageInfo("text", "Plain Text", null), new LanguageInfo("text", "Plain Text", null),
new LanguageInfo("json", "JSON", jsonLanguage.parser, "json"), new LanguageInfo("json", "JSON", jsonLanguage.parser),
new LanguageInfo("python", "Python", pythonLanguage.parser, "py"), new LanguageInfo("py", "Python", pythonLanguage.parser),
new LanguageInfo("javascript", "JavaScript", javascriptLanguage.parser, "js"), new LanguageInfo("html", "HTML", htmlLanguage.parser),
new LanguageInfo("typescript", "TypeScript", typescriptLanguage.parser, "ts"), new LanguageInfo("sql", "SQL", StandardSQL.language.parser),
new LanguageInfo("html", "HTML", htmlLanguage.parser, "html"), new LanguageInfo("md", "Markdown", markdownLanguage.parser),
new LanguageInfo("css", "CSS", cssLanguage.parser, "css"), new LanguageInfo("java", "Java", javaLanguage.parser),
new LanguageInfo("sql", "SQL", StandardSQL.language.parser, "sql"), new LanguageInfo("php", "PHP", phpLanguage.configure({top:"Program"}).parser),
new LanguageInfo("markdown", "Markdown", markdownLanguage.parser, "md"), new LanguageInfo("css", "CSS", cssLanguage.parser),
new LanguageInfo("java", "Java", javaLanguage.parser, "java"), new LanguageInfo("xml", "XML", xmlLanguage.parser),
new LanguageInfo("php", "PHP", phpLanguage.configure({top:"Program"}).parser, "php"), new LanguageInfo("cpp", "C++", cppLanguage.parser),
new LanguageInfo("xml", "XML", xmlLanguage.parser, "xml"), new LanguageInfo("rs", "Rust", rustLanguage.parser),
new LanguageInfo("cpp", "C++", cppLanguage.parser, "cpp"), new LanguageInfo("cs", "C#", StreamLanguage.define(csharp).parser),
new LanguageInfo("c", "C", cppLanguage.parser, "c"), new LanguageInfo("rb", "Ruby", StreamLanguage.define(ruby).parser),
new LanguageInfo("rust", "Rust", rustLanguage.parser, "rs"), new LanguageInfo("sh", "Shell", StreamLanguage.define(shell).parser),
new LanguageInfo("ruby", "Ruby", StreamLanguage.define(ruby).parser, "rb"), new LanguageInfo("yaml", "YAML", yamlLanguage.parser),
new LanguageInfo("shell", "Shell", StreamLanguage.define(shell).parser, "sh"), new LanguageInfo("toml", "TOML", StreamLanguage.define(toml).parser),
new LanguageInfo("yaml", "YAML", yamlLanguage.parser, "yaml"), new LanguageInfo("go", "Go", StreamLanguage.define(go).parser),
new LanguageInfo("go", "Go", StreamLanguage.define(go).parser, "go"), new LanguageInfo("clj", "Clojure", StreamLanguage.define(clojure).parser),
new LanguageInfo("ex", "Elixir", null), // 暂无解析器
new LanguageInfo("erl", "Erlang", StreamLanguage.define(erlang).parser),
new LanguageInfo("js", "JavaScript", javascriptLanguage.parser),
new LanguageInfo("ts", "TypeScript", typescriptLanguage.parser),
new LanguageInfo("swift", "Swift", StreamLanguage.define(swift).parser),
new LanguageInfo("kt", "Kotlin", StreamLanguage.define(kotlin).parser),
new LanguageInfo("groovy", "Groovy", StreamLanguage.define(groovy).parser),
new LanguageInfo("ps1", "PowerShell", StreamLanguage.define(powerShell).parser),
new LanguageInfo("dart", "Dart", null), // 暂无解析器
new LanguageInfo("scala", "Scala", StreamLanguage.define(scala).parser),
]; ];
/** /**

View File

@@ -1,62 +1,92 @@
/** /**
* 自动语言检测 * 基于 Web Worker 的语言自动检测
* 基于内容变化自动检测和更新代码块语言
*/ */
import { EditorState, Annotation } from '@codemirror/state'; import { EditorState, Annotation } from '@codemirror/state';
import { EditorView, ViewPlugin } from '@codemirror/view'; import { EditorView, ViewPlugin } from '@codemirror/view';
import { blockState, getActiveNoteBlock } from '../state'; import { blockState } from '../state';
import { levenshteinDistance } from './levenshtein'; import { levenshteinDistance } from './levenshtein';
import { detectLanguageHeuristic, LanguageDetectionResult } from './heuristics';
import { LANGUAGES } from '../lang-parser/languages'; import { LANGUAGES } from '../lang-parser/languages';
import { SupportedLanguage, Block } from '../types'; import { SupportedLanguage, Block } from '../types';
// ===== 类型定义 =====
/** /**
* 语言检测配置 * 语言检测配置选项
*/ */
interface LanguageDetectionConfig { export interface LanguageDetectionConfig {
/** 最小内容长度阈值 */ minContentLength?: number;
minContentLength: number; confidenceThreshold?: number;
/** 变化阈值比例 */ idleDelay?: number;
changeThreshold: number; defaultLanguage?: SupportedLanguage;
/** 检测置信度阈值 */
confidenceThreshold: number;
/** 空闲检测延迟 (ms) */
idleDelay: number;
/** 默认语言 */
defaultLanguage: SupportedLanguage;
} }
/**
* 语言检测结果
*/
export interface LanguageDetectionResult {
language: SupportedLanguage;
confidence: number;
}
/**
* Worker 消息接口
*/
interface WorkerMessage {
content: string;
idx: number;
}
/**
* Worker 响应接口
*/
interface WorkerResponse {
language: string;
confidence: number;
idx: number;
}
// ===== 常量配置 =====
/** /**
* 默认配置 * 默认配置
*/ */
const DEFAULT_CONFIG: LanguageDetectionConfig = { const DEFAULT_CONFIG = {
minContentLength: 8, minContentLength: 20,
changeThreshold: 0.1, confidenceThreshold: 0.15,
confidenceThreshold: 0.3,
idleDelay: 1000, idleDelay: 1000,
defaultLanguage: 'text', defaultLanguage: 'text' as SupportedLanguage,
}; };
/** /**
* 语言标记映射 * 支持的语言列表
* 将检测结果映射到我们的语言标记
*/ */
const DETECTION_TO_TOKEN = Object.fromEntries( const SUPPORTED_LANGUAGES = new Set([
LANGUAGES.map(l => [l.token, l.token]) "json", "py", "html", "sql", "md", "java", "php", "css", "xml",
); "cpp", "rs", "cs", "rb", "sh", "yaml", "toml", "go", "clj",
"ex", "erl", "js", "ts", "swift", "kt", "groovy", "ps1", "dart", "scala"
]);
/** /**
* 兼容性函数 * 语言标记映射表
*/ */
function requestIdleCallbackCompat(cb: () => void): number { const LANGUAGE_MAP = new Map(LANGUAGES.map(lang => [lang.token, lang.token]));
// ===== 工具函数 =====
/**
* 兼容性函数requestIdleCallback
*/
function requestIdleCallbackCompat(callback: () => void): number {
if (typeof window !== 'undefined' && window.requestIdleCallback) { if (typeof window !== 'undefined' && window.requestIdleCallback) {
return window.requestIdleCallback(cb); return window.requestIdleCallback(callback);
} else {
return setTimeout(cb, 0) as any;
} }
return setTimeout(callback, 0) as any;
} }
/**
* 兼容性函数cancelIdleCallback
*/
function cancelIdleCallbackCompat(id: number): void { function cancelIdleCallbackCompat(id: number): void {
if (typeof window !== 'undefined' && window.cancelIdleCallback) { if (typeof window !== 'undefined' && window.cancelIdleCallback) {
window.cancelIdleCallback(id); window.cancelIdleCallback(id);
@@ -71,167 +101,192 @@ function cancelIdleCallbackCompat(id: number): void {
const languageChangeAnnotation = Annotation.define<boolean>(); const languageChangeAnnotation = Annotation.define<boolean>();
/** /**
* 语言更改命令 * 更新代码块语言
* 简化版本,直接更新块的语言标记
*/ */
function changeLanguageTo( function updateBlockLanguage(
state: EditorState, state: EditorState,
dispatch: (tr: any) => void, dispatch: (transaction: any) => void,
block: Block, block: Block,
newLanguage: SupportedLanguage, newLanguage: SupportedLanguage
isAuto: boolean
): void { ): void {
// 构建新的分隔符文本 const newDelimiter = `\n∞∞∞${newLanguage}-a\n`;
const autoSuffix = isAuto ? '-a' : '';
const newDelimiter = `\n∞∞∞${newLanguage}${autoSuffix}\n`;
// 创建事务来替换分隔符
const transaction = state.update({ const transaction = state.update({
changes: { changes: {
from: block.delimiter.from, from: block.delimiter.from,
to: block.delimiter.to, to: block.delimiter.to,
insert: newDelimiter, insert: newDelimiter,
}, },
annotations: [ annotations: [languageChangeAnnotation.of(true)]
languageChangeAnnotation.of(true)
]
}); });
dispatch(transaction); dispatch(transaction);
} }
// ===== Web Worker 管理器 =====
/**
* 语言检测 Worker 管理器
* 负责 Worker 的生命周期管理和消息通信
*/
class LanguageDetectionWorker {
private worker: Worker | null = null;
private pendingRequests = new Map<number, {
resolve: (result: LanguageDetectionResult) => void;
reject: (error: Error) => void;
}>();
private requestId = 0;
constructor() {
this.initWorker();
}
/**
* 初始化 Worker
*/
private initWorker(): void {
try {
this.worker = new Worker('/langdetect-worker.js');
this.worker.onmessage = (event) => {
const response: WorkerResponse = event.data;
const request = this.pendingRequests.get(response.idx);
if (request) {
this.pendingRequests.delete(response.idx);
if (response.language) {
request.resolve({
language: response.language as SupportedLanguage,
confidence: response.confidence
});
} else {
request.reject(new Error('No detection result'));
}
}
};
this.worker.onerror = () => {
this.pendingRequests.forEach(request => request.reject(new Error('Worker error')));
this.pendingRequests.clear();
};
} catch (error) {
console.error('Failed to initialize worker:', error);
}
}
/**
* 检测语言
*/
async detectLanguage(content: string): Promise<LanguageDetectionResult> {
if (!this.worker) {
throw new Error('Worker not initialized');
}
return new Promise((resolve, reject) => {
const id = ++this.requestId;
this.pendingRequests.set(id, { resolve, reject });
this.worker!.postMessage({ content, idx: id } as WorkerMessage);
// 5秒超时
setTimeout(() => {
if (this.pendingRequests.has(id)) {
this.pendingRequests.delete(id);
reject(new Error('Detection timeout'));
}
}, 5000);
});
}
/**
* 销毁 Worker
*/
destroy(): void {
if (this.worker) {
this.worker.terminate();
this.worker = null;
}
this.pendingRequests.clear();
}
}
// ===== 语言检测插件 =====
/** /**
* 创建语言检测插件 * 创建语言检测插件
*/ */
export function createLanguageDetection( export function createLanguageDetection(config: LanguageDetectionConfig = {}): ViewPlugin<any> {
config: Partial<LanguageDetectionConfig> = {}
): ViewPlugin<any> {
const finalConfig = { ...DEFAULT_CONFIG, ...config }; const finalConfig = { ...DEFAULT_CONFIG, ...config };
const previousBlockContent: Record<number, string> = {}; const contentCache = new Map<number, string>();
let idleCallbackId: number | null = null; let idleCallbackId: number | null = null;
let worker: LanguageDetectionWorker | null = null;
return ViewPlugin.fromClass( return ViewPlugin.fromClass(
class LanguageDetectionPlugin { class LanguageDetectionPlugin {
constructor(public view: EditorView) {} constructor(public view: EditorView) {
worker = new LanguageDetectionWorker();
}
update(update: any) { update(update: any) {
if (update.docChanged) { if (update.docChanged && !update.transactions.some((tr: any) =>
// 取消之前的检测 tr.annotation(languageChangeAnnotation))) {
if (idleCallbackId !== null) { if (idleCallbackId !== null) {
cancelIdleCallbackCompat(idleCallbackId); cancelIdleCallbackCompat(idleCallbackId);
idleCallbackId = null;
} }
// 安排新的检测
idleCallbackId = requestIdleCallbackCompat(() => { idleCallbackId = requestIdleCallbackCompat(() => {
idleCallbackId = null; this.performDetection(update.state);
this.performLanguageDetection(update);
}); });
} }
} }
private performLanguageDetection(update: any) { private performDetection(state: EditorState): void {
const range = update.state.selection.asSingle().ranges[0]; const selection = state.selection.asSingle().ranges[0];
const blocks = update.state.field(blockState); const blocks = state.field(blockState);
let block: Block | null = null; const block = blocks.find(b =>
let blockIndex: number | null = null; b.content.from <= selection.from && b.content.to >= selection.from
);
// 找到当前块 if (!block || !block.language.auto) return;
for (let i = 0; i < blocks.length; i++) {
if (blocks[i].content.from <= range.from && blocks[i].content.to >= range.from) {
block = blocks[i];
blockIndex = i;
break;
}
}
if (block === null || blockIndex === null) { const blockIndex = blocks.indexOf(block);
return; const content = state.doc.sliceString(block.content.from, block.content.to);
}
// 内容为空时重置为默认语言
// 如果不是自动检测模式,清除缓存并返回
if (!block.language.auto) {
delete previousBlockContent[blockIndex];
return;
}
const content = update.state.doc.sliceString(block.content.from, block.content.to);
// 如果内容为空,重置为默认语言
if (content === "") { if (content === "") {
if (block.language.name !== finalConfig.defaultLanguage) { if (block.language.name !== finalConfig.defaultLanguage) {
changeLanguageTo( updateBlockLanguage(state, this.view.dispatch, block, finalConfig.defaultLanguage);
update.state,
this.view.dispatch,
block,
finalConfig.defaultLanguage,
true
);
} }
delete previousBlockContent[blockIndex]; contentCache.delete(blockIndex);
return; return;
} }
// 内容太短跳过检测 // 内容太短跳过
if (content.length <= finalConfig.minContentLength) { if (content.length <= finalConfig.minContentLength) return;
// 检查内容变化
const cachedContent = contentCache.get(blockIndex);
if (cachedContent && levenshteinDistance(cachedContent, content) < content.length * 0.1) {
return; return;
} }
// 检查内容是否有显著变化 this.detectAndUpdate(content, block, blockIndex, state);
const threshold = content.length * finalConfig.changeThreshold;
const previousContent = previousBlockContent[blockIndex];
if (!previousContent) {
// 执行语言检测
this.detectAndUpdateLanguage(content, block, blockIndex, update.state);
previousBlockContent[blockIndex] = content;
} else {
const distance = levenshteinDistance(previousContent, content);
if (distance >= threshold) {
// 执行语言检测
this.detectAndUpdateLanguage(content, block, blockIndex, update.state);
previousBlockContent[blockIndex] = content;
}
}
} }
private detectAndUpdateLanguage( private async detectAndUpdate(content: string, block: Block, blockIndex: number, state: EditorState): Promise<void> {
content: string, if (!worker) return;
block: any,
blockIndex: number,
state: EditorState
) {
// 使用启发式检测 try {
const detectionResult = detectLanguageHeuristic(content); const result = await worker.detectLanguage(content);
// 检查置信度和语言变化 if (result.confidence >= finalConfig.confidenceThreshold &&
if (detectionResult.confidence >= finalConfig.confidenceThreshold && result.language !== block.language.name &&
detectionResult.language !== block.language.name && SUPPORTED_LANGUAGES.has(result.language) &&
DETECTION_TO_TOKEN[detectionResult.language]) { LANGUAGE_MAP.has(result.language)) {
updateBlockLanguage(state, this.view.dispatch, block, result.language);
// 验证内容未显著变化
const currentContent = state.doc.sliceString(block.content.from, block.content.to);
const threshold = currentContent.length * finalConfig.changeThreshold;
const contentDistance = levenshteinDistance(content, currentContent);
if (contentDistance <= threshold) {
// 内容未显著变化,安全更新语言
changeLanguageTo(
state,
this.view.dispatch,
block,
detectionResult.language,
true
);
} }
contentCache.set(blockIndex, content);
} catch (error) {
console.warn('Language detection failed:', error);
} }
} }
@@ -239,21 +294,38 @@ export function createLanguageDetection(
if (idleCallbackId !== null) { if (idleCallbackId !== null) {
cancelIdleCallbackCompat(idleCallbackId); cancelIdleCallbackCompat(idleCallbackId);
} }
if (worker) {
worker.destroy();
worker = null;
}
contentCache.clear();
} }
} }
); );
} }
// ===== 公共 API =====
/** /**
* 手动检测语言 * 手动检测单个内容的语言
*/ */
export function detectLanguage(content: string): LanguageDetectionResult { export async function detectLanguage(content: string): Promise<LanguageDetectionResult> {
return detectLanguageHeuristic(content); const worker = new LanguageDetectionWorker();
try {
return await worker.detectLanguage(content);
} finally {
worker.destroy();
}
} }
/** /**
* 批量检测多个内容的语言 * 批量检测多个内容的语言
*/ */
export function detectLanguages(contents: string[]): LanguageDetectionResult[] { export async function detectLanguages(contents: string[]): Promise<LanguageDetectionResult[]> {
return contents.map(content => detectLanguageHeuristic(content)); const worker = new LanguageDetectionWorker();
try {
return await Promise.all(contents.map(content => worker.detectLanguage(content)));
} finally {
worker.destroy();
}
} }

View File

@@ -1,269 +0,0 @@
/**
* 基于启发式规则的语言检测
* 用于快速识别常见的编程语言模式
*/
import { SupportedLanguage } from '../types';
/**
* 语言检测结果
*/
export interface LanguageDetectionResult {
language: SupportedLanguage;
confidence: number;
}
/**
* 语言模式定义
*/
interface LanguagePattern {
patterns: RegExp[];
weight: number;
}
/**
* 语言检测规则映射
*/
const LANGUAGE_PATTERNS: Record<string, LanguagePattern> = {
javascript: {
patterns: [
/\b(function|const|let|var|class|extends|import|export|async|await)\b/g,
/\b(console\.log|document\.|window\.)\b/g,
/=>\s*[{(]/g,
/\b(require|module\.exports)\b/g,
],
weight: 1.0,
},
typescript: {
patterns: [
/\b(interface|type|enum|namespace|implements|declare)\b/g,
/:\s*(string|number|boolean|object|any)\b/g,
/<[A-Z][a-zA-Z0-9<>,\s]*>/g,
/\b(public|private|protected|readonly)\b/g,
],
weight: 1.2,
},
python: {
patterns: [
/\b(def|class|import|from|if __name__|print|len|range)\b/g,
/^\s*#.*$/gm,
/\b(True|False|None)\b/g,
/:\s*$/gm,
],
weight: 1.0,
},
java: {
patterns: [
/\b(public|private|protected|static|final|class|interface)\b/g,
/\b(System\.out\.println|String|int|void)\b/g,
/import\s+[a-zA-Z0-9_.]+;/g,
/\b(extends|implements)\b/g,
],
weight: 1.0,
},
html: {
patterns: [
/<\/?[a-zA-Z][^>]*>/g,
/<!DOCTYPE\s+html>/gi,
/<(div|span|p|h[1-6]|body|head|html)\b/g,
/\s(class|id|src|href)=/g,
],
weight: 1.5,
},
css: {
patterns: [
/[.#][a-zA-Z][\w-]*\s*{/g,
/\b(color|background|margin|padding|font-size):\s*[^;]+;/g,
/@(media|keyframes|import)\b/g,
/\{[^}]*\}/g,
],
weight: 1.3,
},
json: {
patterns: [
/^\s*[{\[][\s\S]*[}\]]\s*$/,
/"[^"]*":\s*(".*"|[\d.]+|true|false|null)/g,
/,\s*$/gm,
],
weight: 2.0,
},
sql: {
patterns: [
/\b(SELECT|FROM|WHERE|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\b/gi,
/\b(JOIN|LEFT|RIGHT|INNER|OUTER|ON|GROUP BY|ORDER BY)\b/gi,
/;\s*$/gm,
/\b(TABLE|DATABASE|INDEX)\b/gi,
],
weight: 1.4,
},
shell: {
patterns: [
/^#!/g,
/\b(echo|cd|ls|grep|awk|sed|cat|chmod)\b/g,
/\$\{?\w+\}?/g,
/\|\s*\w+/g,
],
weight: 1.2,
},
markdown: {
patterns: [
/^#+\s+/gm,
/\*\*.*?\*\*/g,
/\[.*?\]\(.*?\)/g,
/^```/gm,
],
weight: 1.1,
},
php: {
patterns: [
/<\?php/g,
/\$\w+/g,
/\b(function|class|extends|implements)\b/g,
/echo\s+/g,
],
weight: 1.3,
},
cpp: {
patterns: [
/#include\s*<.*>/g,
/\b(int|char|float|double|void|class|struct)\b/g,
/std::/g,
/cout\s*<<|cin\s*>>/g,
],
weight: 1.1,
},
rust: {
patterns: [
/\bfn\s+\w+/g,
/\b(let|mut|struct|enum|impl|trait)\b/g,
/println!\(/g,
/::\w+/g,
],
weight: 1.2,
},
go: {
patterns: [
/\bfunc\s+\w+/g,
/\b(var|const|type|package|import)\b/g,
/fmt\.\w+/g,
/:=\s*/g,
],
weight: 1.1,
},
ruby: {
patterns: [
/\b(def|class|module|end)\b/g,
/\b(puts|print|require)\b/g,
/@\w+/g,
/\|\w+\|/g,
],
weight: 1.0,
},
yaml: {
patterns: [
/^\s*\w+:\s*.*$/gm, // key: value 模式
/^\s*-\s+\w+/gm, // 列表项
/^---\s*$/gm, // 文档分隔符
/^\s*\w+:\s*\|/gm, // 多行字符串
/^\s*\w+:\s*>/gm, // 折叠字符串
/^\s*#.*$/gm, // 注释
/:\s*\[.*\]/g, // 内联数组
/:\s*\{.*\}/g, // 内联对象
],
weight: 1.5,
},
xml: {
patterns: [
/<\?xml/g,
/<\/\w+>/g,
/<\w+[^>]*\/>/g,
/\s\w+="[^"]*"/g,
],
weight: 1.3,
},
};
/**
* JSON 特殊检测
* 使用更严格的规则检测 JSON
*/
function detectJSON(content: string): LanguageDetectionResult | null {
const trimmed = content.trim();
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
try {
JSON.parse(trimmed);
return {
language: 'json',
confidence: 1.0,
};
} catch (e) {
// JSON 解析失败,继续其他检测
}
}
return null;
}
/**
* 计算文本与语言模式的匹配分数
*/
function calculateScore(content: string, pattern: LanguagePattern): number {
let score = 0;
const contentLength = Math.max(content.length, 1);
for (const regex of pattern.patterns) {
const matches = content.match(regex);
if (matches) {
score += matches.length;
}
}
// 根据内容长度和权重标准化分数
return (score * pattern.weight) / (contentLength / 100);
}
/**
* 基于启发式规则检测语言
*/
export function detectLanguageHeuristic(content: string): LanguageDetectionResult {
if (!content.trim()) {
return { language: 'text', confidence: 1.0 };
}
// 首先尝试 JSON 特殊检测
const jsonResult = detectJSON(content);
if (jsonResult) {
return jsonResult;
}
const scores: Record<string, number> = {};
// 计算每种语言的匹配分数
for (const [language, pattern] of Object.entries(LANGUAGE_PATTERNS)) {
scores[language] = calculateScore(content, pattern);
}
// 找到最高分的语言
const sortedScores = Object.entries(scores)
.sort(([, a], [, b]) => b - a)
.filter(([, score]) => score > 0);
if (sortedScores.length > 0) {
const [bestLanguage, bestScore] = sortedScores[0];
return {
language: bestLanguage as SupportedLanguage,
confidence: Math.min(bestScore, 1.0),
};
}
return { language: 'text', confidence: 1.0 };
}
/**
* 获取所有支持的检测语言
*/
export function getSupportedDetectionLanguages(): SupportedLanguage[] {
return Object.keys(LANGUAGE_PATTERNS) as SupportedLanguage[];
}

View File

@@ -1,26 +1,14 @@
/** /**
* 语言检测模块入口 * 语言检测模块
* 导出所有语言检测相关的功能
*/ */
// 主要检测功能
export { export {
createLanguageDetection, createLanguageDetection,
detectLanguage, detectLanguage,
detectLanguages detectLanguages,
type LanguageDetectionResult,
type LanguageDetectionConfig
} from './autodetect'; } from './autodetect';
// 启发式检测 export { levenshteinDistance } from './levenshtein';
export {
detectLanguageHeuristic,
getSupportedDetectionLanguages,
type LanguageDetectionResult
} from './heuristics';
// 工具函数
export {
levenshteinDistance
} from './levenshtein';
// 重新导出类型
export type { SupportedLanguage } from '../types'; export type { SupportedLanguage } from '../types';

View File

@@ -1,78 +1,70 @@
/** /**
* Levenshtein 距离算法 * Levenshtein 距离算法
* 用于计算两个字符串之间的编辑距离
*/ */
/** /**
* 内部最小值计算函数 * 内部最小值计算函数
* 用于计算编辑距离的最小成本
*
* @param d0 - 对角线上的距离
* @param d1 - 左侧的距离
* @param d2 - 上方的距离
* @param bx - 字符串 b 的当前字符
* @param ay - 字符串 a 的当前字符
* @returns 最小编辑距离
*/ */
function _min(d0: number, d1: number, d2: number, bx: number, ay: number): number { function min(d0: number, d1: number, d2: number, bx: number, ay: number): number {
return d0 < d1 || d2 < d1 return d0 < d1 || d2 < d1
? d0 > d2 ? d0 > d2 ? d2 + 1 : d0 + 1
? d2 + 1 : bx === ay ? d1 : d1 + 1;
: d0 + 1
: bx === ay
? d1
: d1 + 1;
} }
/** /**
* 计算两个字符串之间的 Levenshtein 距离 * 计算两个字符串之间的 Levenshtein 距离
* @param a 第一个字符串 *
* @param b 第二个字符串 * 该实现使用了多项优化:
* @returns 编辑距离 * 1. 确保较短的字符串作为第一个参数
* 2. 跳过公共前缀和后缀
* 3. 使用滚动数组减少空间复杂度
* 4. 批量处理以提高性能
*
* @param stringA - 第一个字符串
* @param stringB - 第二个字符串
* @returns 编辑距离(非负整数)
*/ */
export function levenshteinDistance(a: string, b: string): number { export function levenshteinDistance(a: string, b: string): number {
if (a === b) { if (a === b) return 0;
return 0;
}
if (a.length > b.length) { if (a.length > b.length) {
const tmp = a; [a, b] = [b, a];
a = b;
b = tmp;
} }
let la = a.length; let la = a.length;
let lb = b.length; let lb = b.length;
while (la > 0 && (a.charCodeAt(la - 1) === b.charCodeAt(lb - 1))) { // 跳过公共后缀
while (la > 0 && a.charCodeAt(la - 1) === b.charCodeAt(lb - 1)) {
la--; la--;
lb--; lb--;
} }
let offset = 0; let offset = 0;
// 跳过公共前缀
while (offset < la && (a.charCodeAt(offset) === b.charCodeAt(offset))) { while (offset < la && a.charCodeAt(offset) === b.charCodeAt(offset)) {
offset++; offset++;
} }
la -= offset; la -= offset;
lb -= offset; lb -= offset;
if (la === 0 || lb < 3) { if (la === 0 || lb < 3) return lb;
return lb;
}
let x = 0; let x = 0, y: number, d0: number, d1: number, d2: number, d3: number;
let y: number; let dd = 0, dy: number, ay: number, bx0: number, bx1: number, bx2: number, bx3: number;
let d0: number;
let d1: number;
let d2: number;
let d3: number;
let dd = 0;
let dy: number;
let ay: number;
let bx0: number;
let bx1: number;
let bx2: number;
let bx3: number;
const vector: number[] = []; const vector: number[] = [];
for (y = 0; y < la; y++) { for (y = 0; y < la; y++) {
vector.push(y + 1); vector.push(y + 1, a.charCodeAt(offset + y));
vector.push(a.charCodeAt(offset + y));
} }
const len = vector.length - 1; const len = vector.length - 1;
@@ -84,18 +76,16 @@ export function levenshteinDistance(a: string, b: string): number {
bx3 = b.charCodeAt(offset + (d3 = x + 3)); bx3 = b.charCodeAt(offset + (d3 = x + 3));
x += 4; x += 4;
dd = x; dd = x;
for (y = 0; y < len; y += 2) { for (y = 0; y < len; y += 2) {
dy = vector[y]; dy = vector[y];
ay = vector[y + 1]; ay = vector[y + 1];
d0 = _min(dy, d0, d1, bx0, ay); d0 = min(dy, d0, d1, bx0, ay);
d1 = _min(d0, d1, d2, bx1, ay); d1 = min(d0, d1, d2, bx1, ay);
d2 = _min(d1, d2, d3, bx2, ay); d2 = min(d1, d2, d3, bx2, ay);
dd = _min(d2, d3, dd, bx3, ay); dd = min(d2, d3, dd, bx3, ay);
vector[y] = dd; vector[y] = dd;
d3 = d2; d3 = d2; d2 = d1; d1 = d0; d0 = dy;
d2 = d1;
d1 = d0;
d0 = dy;
} }
} }
@@ -104,7 +94,7 @@ export function levenshteinDistance(a: string, b: string): number {
dd = ++x; dd = ++x;
for (y = 0; y < len; y += 2) { for (y = 0; y < len; y += 2) {
dy = vector[y]; dy = vector[y];
vector[y] = dd = _min(dy, d0, dd, bx0, vector[y + 1]); vector[y] = dd = min(dy, d0, dd, bx0, vector[y + 1]);
d0 = dy; d0 = dy;
} }
} }

View File

@@ -25,48 +25,68 @@ export interface Block {
*/ */
export type SupportedLanguage = export type SupportedLanguage =
| 'text' | 'text'
| 'javascript'
| 'typescript'
| 'python'
| 'html'
| 'css'
| 'json' | 'json'
| 'markdown' | 'py' // Python
| 'shell' | 'html'
| 'sql' | 'sql'
| 'yaml' | 'md' // Markdown
| 'xml'
| 'php'
| 'java' | 'java'
| 'cpp' | 'php'
| 'c' | 'css'
| 'xml'
| 'cpp' // C++
| 'rs' // Rust
| 'cs' // C#
| 'rb' // Ruby
| 'sh' // Shell
| 'yaml'
| 'toml'
| 'go' | 'go'
| 'rust' | 'clj' // Clojure
| 'ruby'; | 'ex' // Elixir
| 'erl' // Erlang
| 'js' // JavaScript
| 'ts' // TypeScript
| 'swift'
| 'kt' // Kotlin
| 'groovy'
| 'ps1' // PowerShell
| 'dart'
| 'scala';
/** /**
* 支持的语言列表 * 支持的语言列表
*/ */
export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [ export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [
'text', 'text',
'javascript',
'typescript',
'python',
'html',
'css',
'json', 'json',
'markdown', 'py',
'shell', 'html',
'sql', 'sql',
'yaml', 'md',
'xml',
'php',
'java', 'java',
'php',
'css',
'xml',
'cpp', 'cpp',
'c', 'rs',
'cs',
'rb',
'sh',
'yaml',
'toml',
'go', 'go',
'rust', 'clj',
'ruby' 'ex',
'erl',
'js',
'ts',
'swift',
'kt',
'groovy',
'ps1',
'dart',
'scala'
]; ];
/** /**
@@ -134,9 +154,6 @@ export interface BlockStateUpdate {
operation?: BlockOperation; operation?: BlockOperation;
} }
// 块导航方向
export type NavigationDirection = 'next' | 'previous' | 'first' | 'last';
// 语言检测结果 // 语言检测结果
export interface LanguageDetectionResult { export interface LanguageDetectionResult {
language: SupportedLanguage; language: SupportedLanguage;