✨ Use guesslang to detect the language
This commit is contained in:
416
frontend/package-lock.json
generated
416
frontend/package-lock.json
generated
@@ -21,7 +21,7 @@
|
||||
"@codemirror/lang-less": "^6.0.2",
|
||||
"@codemirror/lang-lezer": "^6.0.1",
|
||||
"@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-python": "^6.2.1",
|
||||
"@codemirror/lang-rust": "^6.0.1",
|
||||
@@ -37,7 +37,7 @@
|
||||
"@codemirror/lint": "^6.8.5",
|
||||
"@codemirror/search": "^6.5.11",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.37.1",
|
||||
"@codemirror/view": "^6.37.2",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
@@ -48,24 +48,24 @@
|
||||
"colors-named-hex": "^1.0.2",
|
||||
"hsl-matcher": "^1.2.4",
|
||||
"lezer": "^0.13.5",
|
||||
"pinia": "^3.0.2",
|
||||
"sass": "^1.89.1",
|
||||
"pinia": "^3.0.3",
|
||||
"sass": "^1.89.2",
|
||||
"uuid": "^11.1.0",
|
||||
"vue": "^3.5.16",
|
||||
"vue-i18n": "^11.1.5",
|
||||
"vue": "^3.5.17",
|
||||
"vue-i18n": "^11.1.6",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@lezer/generator": "^1.7.3",
|
||||
"@types/node": "^22.15.29",
|
||||
"@types/node": "^24.0.3",
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"@wailsio/runtime": "latest",
|
||||
"eslint": "^9.28.0",
|
||||
"eslint-plugin-vue": "^10.1.0",
|
||||
"eslint": "^9.29.0",
|
||||
"eslint-plugin-vue": "^10.2.0",
|
||||
"globals": "^16.2.0",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.33.1",
|
||||
"typescript-eslint": "^8.34.1",
|
||||
"unplugin-vue-components": "^28.7.0",
|
||||
"vite": "^6.3.5",
|
||||
"vue-eslint-parser": "^10.1.3",
|
||||
@@ -91,12 +91,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.27.2",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.2.tgz",
|
||||
"integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==",
|
||||
"version": "7.27.5",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.27.5.tgz",
|
||||
"integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.27.1"
|
||||
"@babel/types": "^7.27.3"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -106,9 +106,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.1.tgz",
|
||||
"integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==",
|
||||
"version": "7.27.6",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.27.6.tgz",
|
||||
"integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.27.1",
|
||||
@@ -286,9 +286,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lang-markdown": {
|
||||
"version": "6.3.2",
|
||||
"resolved": "https://registry.npmmirror.com/@codemirror/lang-markdown/-/lang-markdown-6.3.2.tgz",
|
||||
"integrity": "sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==",
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/@codemirror/lang-markdown/-/lang-markdown-6.3.3.tgz",
|
||||
"integrity": "sha512-1fn1hQAPWlSSMCvnF810AkhWpNLkJpl66CRfIy3vVl20Sl4NwChkorCHqpMtNbXr1EuMJsrDnhEpjZxKZ2UX3A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.7.1",
|
||||
@@ -503,9 +503,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.37.1",
|
||||
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.37.1.tgz",
|
||||
"integrity": "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==",
|
||||
"version": "6.37.2",
|
||||
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.37.2.tgz",
|
||||
"integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.5.0",
|
||||
@@ -982,9 +982,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.20.0.tgz",
|
||||
"integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
|
||||
"version": "0.20.1",
|
||||
"resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.20.1.tgz",
|
||||
"integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -1057,9 +1057,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.28.0.tgz",
|
||||
"integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.29.0.tgz",
|
||||
"integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1160,13 +1160,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/core-base": {
|
||||
"version": "11.1.5",
|
||||
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.1.5.tgz",
|
||||
"integrity": "sha512-xGRkISwV/2Trqb8yVQevlHm5roaQqy+75qwUzEQrviaQF0o4c5VDhjBW7WEGEoKFx09HSgq7NkvK/DAyuerTDg==",
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.1.6.tgz",
|
||||
"integrity": "sha512-gfMLnoWGiQkA1BwK6Qbrog/e3I6Lnkhqk08XObJb0lMq6sLG1Ggl2MazVaMfGnv/E1Td8pCS5UwR54Ys+fOxmQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/message-compiler": "11.1.5",
|
||||
"@intlify/shared": "11.1.5"
|
||||
"@intlify/message-compiler": "11.1.6",
|
||||
"@intlify/shared": "11.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
@@ -1176,12 +1176,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/message-compiler": {
|
||||
"version": "11.1.5",
|
||||
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.1.5.tgz",
|
||||
"integrity": "sha512-YLSBbjD7qUdShe3ZAat9Hnf9E8FRpN6qmNFD/x5Xg5JVXjsks0kJ90Zj6aAuyoppJQA/YJdWZ8/bB7k3dg2TjQ==",
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.1.6.tgz",
|
||||
"integrity": "sha512-w0LYo5sqgQZF3vEmjLlx+5PYk5EEiB+uigsBkka/DKoAIH2c5xlXcjAxhTgSw35Vrck+GOGriahFsfbHL+ZjPw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/shared": "11.1.5",
|
||||
"@intlify/shared": "11.1.6",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1192,9 +1192,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/shared": {
|
||||
"version": "11.1.5",
|
||||
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-11.1.5.tgz",
|
||||
"integrity": "sha512-+I4vRzHm38VjLr/CAciEPJhGYFzWWW4HMTm+6H3WqknXLh0ozNX9oC8ogMUwTSXYR/wGUb1/lTpNziiCH5MybQ==",
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-11.1.6.tgz",
|
||||
"integrity": "sha512-G1Pe4UILhiGOItuehRW+Pk9/NlnRaMFsdnhZ1fwBjiHvrzitmPNZdLx7Eo3GPfRrsk1mdkilZSfgH8SnM419vA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
@@ -2093,13 +2093,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.15.29",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.15.29.tgz",
|
||||
"integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==",
|
||||
"version": "24.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-24.0.3.tgz",
|
||||
"integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
"undici-types": "~7.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
@@ -2115,17 +2115,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz",
|
||||
"integrity": "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
|
||||
"integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.33.1",
|
||||
"@typescript-eslint/type-utils": "8.33.1",
|
||||
"@typescript-eslint/utils": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/type-utils": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@@ -2139,7 +2139,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.33.1",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@@ -2155,16 +2155,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.33.1.tgz",
|
||||
"integrity": "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.34.1.tgz",
|
||||
"integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/typescript-estree": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2180,14 +2180,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.33.1.tgz",
|
||||
"integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
|
||||
"integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.33.1",
|
||||
"@typescript-eslint/types": "^8.33.1",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.34.1",
|
||||
"@typescript-eslint/types": "^8.34.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2202,14 +2202,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz",
|
||||
"integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
|
||||
"integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2220,9 +2220,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz",
|
||||
"integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2237,14 +2237,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz",
|
||||
"integrity": "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
|
||||
"integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.33.1",
|
||||
"@typescript-eslint/utils": "8.33.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@@ -2261,9 +2261,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.33.1.tgz",
|
||||
"integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.34.1.tgz",
|
||||
"integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2275,16 +2275,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz",
|
||||
"integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
|
||||
"integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.33.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/visitor-keys": "8.33.1",
|
||||
"@typescript-eslint/project-service": "8.34.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/visitor-keys": "8.34.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -2304,9 +2304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2330,16 +2330,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.33.1.tgz",
|
||||
"integrity": "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.34.1.tgz",
|
||||
"integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.33.1",
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"@typescript-eslint/typescript-estree": "8.33.1"
|
||||
"@typescript-eslint/scope-manager": "8.34.1",
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"@typescript-eslint/typescript-estree": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2354,14 +2354,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz",
|
||||
"integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
|
||||
"integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.33.1",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"@typescript-eslint/types": "8.34.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2415,53 +2415,53 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.16.tgz",
|
||||
"integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.17.tgz",
|
||||
"integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.27.2",
|
||||
"@vue/shared": "3.5.16",
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@vue/shared": "3.5.17",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz",
|
||||
"integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz",
|
||||
"integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.16",
|
||||
"@vue/shared": "3.5.16"
|
||||
"@vue/compiler-core": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz",
|
||||
"integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz",
|
||||
"integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.27.2",
|
||||
"@vue/compiler-core": "3.5.16",
|
||||
"@vue/compiler-dom": "3.5.16",
|
||||
"@vue/compiler-ssr": "3.5.16",
|
||||
"@vue/shared": "3.5.16",
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@vue/compiler-core": "3.5.17",
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/compiler-ssr": "3.5.17",
|
||||
"@vue/shared": "3.5.17",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.17",
|
||||
"postcss": "^8.5.3",
|
||||
"postcss": "^8.5.6",
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz",
|
||||
"integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz",
|
||||
"integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.16",
|
||||
"@vue/shared": "3.5.16"
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-vue2": {
|
||||
@@ -2560,53 +2560,53 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.16.tgz",
|
||||
"integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.17.tgz",
|
||||
"integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.16"
|
||||
"@vue/shared": "3.5.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.16.tgz",
|
||||
"integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.17.tgz",
|
||||
"integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.16",
|
||||
"@vue/shared": "3.5.16"
|
||||
"@vue/reactivity": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz",
|
||||
"integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz",
|
||||
"integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.16",
|
||||
"@vue/runtime-core": "3.5.16",
|
||||
"@vue/shared": "3.5.16",
|
||||
"@vue/reactivity": "3.5.17",
|
||||
"@vue/runtime-core": "3.5.17",
|
||||
"@vue/shared": "3.5.17",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.16.tgz",
|
||||
"integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.17.tgz",
|
||||
"integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.16",
|
||||
"@vue/shared": "3.5.16"
|
||||
"@vue/compiler-ssr": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.5.16"
|
||||
"vue": "3.5.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.16.tgz",
|
||||
"integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.17.tgz",
|
||||
"integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vueuse/core": {
|
||||
@@ -2655,9 +2655,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.1",
|
||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.1.tgz",
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -3186,19 +3186,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.28.0.tgz",
|
||||
"integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
|
||||
"version": "9.29.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.29.0.tgz",
|
||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@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/core": "^0.14.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.28.0",
|
||||
"@eslint/js": "9.29.0",
|
||||
"@eslint/plugin-kit": "^0.3.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
@@ -3210,9 +3210,9 @@
|
||||
"cross-spawn": "^7.0.6",
|
||||
"debug": "^4.3.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^8.3.0",
|
||||
"eslint-visitor-keys": "^4.2.0",
|
||||
"espree": "^10.3.0",
|
||||
"eslint-scope": "^8.4.0",
|
||||
"eslint-visitor-keys": "^4.2.1",
|
||||
"espree": "^10.4.0",
|
||||
"esquery": "^1.5.0",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
@@ -3247,9 +3247,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.1.0.tgz",
|
||||
"integrity": "sha512-/VTiJ1eSfNLw6lvG9ENySbGmcVvz6wZ9nA7ZqXlLBY2RkaF15iViYKxglWiIch12KiLAj0j1iXPYU6W4wTROFA==",
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.2.0.tgz",
|
||||
"integrity": "sha512-tl9s+KN3z0hN2b8fV2xSs5ytGl7Esk1oSCxULLwFcdaElhZ8btYYZFrWxvh4En+czrSDtuLCeCOGa8HhEZuBdQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3269,9 +3269,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-scope": {
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.3.0.tgz",
|
||||
"integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.4.0.tgz",
|
||||
"integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
@@ -3286,9 +3286,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
@@ -3299,15 +3299,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/espree/-/espree-10.3.0.tgz",
|
||||
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
||||
"version": "10.4.0",
|
||||
"resolved": "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz",
|
||||
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"acorn": "^8.14.0",
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -4204,9 +4204,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/pinia": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-3.0.2.tgz",
|
||||
"integrity": "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/pinia/-/pinia-3.0.3.tgz",
|
||||
"integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^7.7.2"
|
||||
@@ -4237,9 +4237,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz",
|
||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -4256,7 +4256,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.8",
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
@@ -4454,9 +4454,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.89.1",
|
||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.89.1.tgz",
|
||||
"integrity": "sha512-eMLLkl+qz7tx/0cJ9wI+w09GQ2zodTkcE/aVfywwdlRcI3EO19xGnbmJwg/JMIm+5MxVJ6outddLZ4Von4E++Q==",
|
||||
"version": "1.89.2",
|
||||
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.89.2.tgz",
|
||||
"integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.0",
|
||||
@@ -4712,15 +4712,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.33.1",
|
||||
"resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.33.1.tgz",
|
||||
"integrity": "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==",
|
||||
"version": "8.34.1",
|
||||
"resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
|
||||
"integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.33.1",
|
||||
"@typescript-eslint/parser": "8.33.1",
|
||||
"@typescript-eslint/utils": "8.33.1"
|
||||
"@typescript-eslint/eslint-plugin": "8.34.1",
|
||||
"@typescript-eslint/parser": "8.34.1",
|
||||
"@typescript-eslint/utils": "8.34.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -4769,9 +4769,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.8.0.tgz",
|
||||
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -5150,16 +5150,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.16",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.16.tgz",
|
||||
"integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==",
|
||||
"version": "3.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.17.tgz",
|
||||
"integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.16",
|
||||
"@vue/compiler-sfc": "3.5.16",
|
||||
"@vue/runtime-dom": "3.5.16",
|
||||
"@vue/server-renderer": "3.5.16",
|
||||
"@vue/shared": "3.5.16"
|
||||
"@vue/compiler-dom": "3.5.17",
|
||||
"@vue/compiler-sfc": "3.5.17",
|
||||
"@vue/runtime-dom": "3.5.17",
|
||||
"@vue/server-renderer": "3.5.17",
|
||||
"@vue/shared": "3.5.17"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
@@ -5196,13 +5196,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-i18n": {
|
||||
"version": "11.1.5",
|
||||
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.1.5.tgz",
|
||||
"integrity": "sha512-XCwuaEA5AF97g1frvH/EI1zI9uo1XKTf2/OCFgts7NvUWRsjlgeHPrkJV+a3gpzai2pC4quZ4AnOHFO8QK9hsg==",
|
||||
"version": "11.1.6",
|
||||
"resolved": "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.1.6.tgz",
|
||||
"integrity": "sha512-+IbsW/sTZHj7U1w0rPOYJbuSB0/7DeO1nvUo3BxvO20OQgHs+ukJ3QeLqvoUA6DiLk+8SA9+djRmKC9+FC6cAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@intlify/core-base": "11.1.5",
|
||||
"@intlify/shared": "11.1.5",
|
||||
"@intlify/core-base": "11.1.6",
|
||||
"@intlify/shared": "11.1.6",
|
||||
"@vue/devtools-api": "^6.5.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@@ -25,7 +25,7 @@
|
||||
"@codemirror/lang-less": "^6.0.2",
|
||||
"@codemirror/lang-lezer": "^6.0.1",
|
||||
"@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-python": "^6.2.1",
|
||||
"@codemirror/lang-rust": "^6.0.1",
|
||||
@@ -41,7 +41,7 @@
|
||||
"@codemirror/lint": "^6.8.5",
|
||||
"@codemirror/search": "^6.5.11",
|
||||
"@codemirror/state": "^6.5.2",
|
||||
"@codemirror/view": "^6.37.1",
|
||||
"@codemirror/view": "^6.37.2",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
@@ -52,24 +52,24 @@
|
||||
"colors-named-hex": "^1.0.2",
|
||||
"hsl-matcher": "^1.2.4",
|
||||
"lezer": "^0.13.5",
|
||||
"pinia": "^3.0.2",
|
||||
"sass": "^1.89.1",
|
||||
"pinia": "^3.0.3",
|
||||
"sass": "^1.89.2",
|
||||
"uuid": "^11.1.0",
|
||||
"vue": "^3.5.16",
|
||||
"vue-i18n": "^11.1.5",
|
||||
"vue": "^3.5.17",
|
||||
"vue-i18n": "^11.1.6",
|
||||
"vue-router": "^4.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.28.0",
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@lezer/generator": "^1.7.3",
|
||||
"@types/node": "^22.15.29",
|
||||
"@types/node": "^24.0.3",
|
||||
"@vitejs/plugin-vue": "^5.2.4",
|
||||
"@wailsio/runtime": "latest",
|
||||
"eslint": "^9.28.0",
|
||||
"eslint-plugin-vue": "^10.1.0",
|
||||
"eslint": "^9.29.0",
|
||||
"eslint-plugin-vue": "^10.2.0",
|
||||
"globals": "^16.2.0",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.33.1",
|
||||
"typescript-eslint": "^8.34.1",
|
||||
"unplugin-vue-components": "^28.7.0",
|
||||
"vite": "^6.3.5",
|
||||
"vue-eslint-parser": "^10.1.3",
|
||||
|
28
frontend/public/guesslang.min.js
vendored
Normal file
28
frontend/public/guesslang.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
48
frontend/public/langdetect-worker.js
Normal file
48
frontend/public/langdetect-worker.js
Normal 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)
|
||||
})
|
||||
}
|
@@ -13,28 +13,71 @@ const searchInputRef = ref<HTMLInputElement>();
|
||||
// 语言别名映射
|
||||
const LANGUAGE_ALIASES: Record<SupportedLanguage, string> = {
|
||||
text: 'txt',
|
||||
javascript: 'js',
|
||||
typescript: 'ts',
|
||||
python: 'py',
|
||||
html: 'htm',
|
||||
css: '',
|
||||
json: '',
|
||||
markdown: 'md',
|
||||
shell: 'sh',
|
||||
sql: '',
|
||||
yaml: 'yml',
|
||||
xml: '',
|
||||
php: '',
|
||||
java: '',
|
||||
json: 'JSON',
|
||||
py: 'python',
|
||||
html: 'HTML',
|
||||
sql: 'SQL',
|
||||
md: 'markdown',
|
||||
java: 'Java',
|
||||
php: 'PHP',
|
||||
css: 'CSS',
|
||||
xml: 'XML',
|
||||
cpp: 'c++',
|
||||
c: '',
|
||||
go: '',
|
||||
rust: 'rs',
|
||||
ruby: 'rb'
|
||||
rs: 'rust',
|
||||
cs: 'c#',
|
||||
rb: 'ruby',
|
||||
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(() => {
|
||||
@@ -44,8 +87,10 @@ const filteredLanguages = computed(() => {
|
||||
|
||||
const query = searchQuery.value.toLowerCase();
|
||||
return SUPPORTED_LANGUAGES.filter(langId => {
|
||||
const name = LANGUAGE_NAMES[langId];
|
||||
const alias = LANGUAGE_ALIASES[langId];
|
||||
return langId.toLowerCase().includes(query) ||
|
||||
(name && name.toLowerCase().includes(query)) ||
|
||||
(alias && alias.toLowerCase().includes(query));
|
||||
});
|
||||
});
|
||||
@@ -96,7 +141,7 @@ onUnmounted(() => {
|
||||
|
||||
// 获取当前语言的显示名称
|
||||
const getCurrentLanguageName = computed(() => {
|
||||
return currentLanguage.value;
|
||||
return LANGUAGE_NAMES[currentLanguage.value] || currentLanguage.value;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -143,8 +188,8 @@ const getCurrentLanguageName = computed(() => {
|
||||
:class="{ 'active': currentLanguage === language }"
|
||||
@click="selectLanguage(language)"
|
||||
>
|
||||
<span class="language-name">{{ language }}</span>
|
||||
<span class="language-alias" v-if="LANGUAGE_ALIASES[language]">{{ LANGUAGE_ALIASES[language] }}</span>
|
||||
<span class="language-name">{{ LANGUAGE_NAMES[language] || language }}</span>
|
||||
<span class="language-alias">{{ language }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 无结果提示 -->
|
||||
|
@@ -13,21 +13,20 @@
|
||||
*/
|
||||
|
||||
import {Extension} from '@codemirror/state';
|
||||
import {keymap} from '@codemirror/view';
|
||||
import {keymap, lineNumbers} from '@codemirror/view';
|
||||
|
||||
// 导入核心模块
|
||||
import {blockState} from './state';
|
||||
import {getBlockDecorationExtensions} from './decorations';
|
||||
import * as commands from './commands';
|
||||
import {selectAll, getBlockSelectExtensions} from './selectAll';
|
||||
import {getBlockSelectExtensions, selectAll} from './selectAll';
|
||||
import {getCopyPasteExtensions, getCopyPasteKeymap} from './copyPaste';
|
||||
import {deleteLineCommand} from './deleteLine';
|
||||
import {moveLineUp, moveLineDown} from './moveLines';
|
||||
import {moveLineDown, moveLineUp} from './moveLines';
|
||||
import {transposeChars} from './transposeChars';
|
||||
import {getCodeBlockLanguageExtension} from './lang-parser';
|
||||
import {createLanguageDetection} from './language-detection';
|
||||
import {EditorOptions, SupportedLanguage} from './types';
|
||||
import {lineNumbers} from '@codemirror/view';
|
||||
|
||||
/**
|
||||
* 代码块扩展配置选项
|
||||
@@ -112,8 +111,8 @@ export function createCodeBlockExtension(options: CodeBlockOptions = {}): Extens
|
||||
// 语言自动检测(如果启用)
|
||||
...(enableAutoDetection ? [createLanguageDetection({
|
||||
defaultLanguage: defaultLanguage,
|
||||
confidenceThreshold: 0.3,
|
||||
minContentLength: 8,
|
||||
confidenceThreshold: 0.15,
|
||||
minContentLength: 8
|
||||
})] : []),
|
||||
|
||||
// 视觉装饰系统
|
||||
@@ -297,14 +296,12 @@ export {
|
||||
createLanguageDetection,
|
||||
detectLanguage,
|
||||
detectLanguages,
|
||||
detectLanguageHeuristic,
|
||||
getSupportedDetectionLanguages,
|
||||
levenshteinDistance,
|
||||
type LanguageDetectionResult
|
||||
} from './language-detection';
|
||||
|
||||
// 行号相关
|
||||
export { getBlockLineFromPos, blockLineNumbers };
|
||||
export {getBlockLineFromPos, blockLineNumbers};
|
||||
|
||||
/**
|
||||
* 默认导出
|
||||
|
@@ -14,12 +14,21 @@ import { cssLanguage } from "@codemirror/lang-css";
|
||||
import { cppLanguage } from "@codemirror/lang-cpp";
|
||||
import { xmlLanguage } from "@codemirror/lang-xml";
|
||||
import { rustLanguage } from "@codemirror/lang-rust";
|
||||
import { yamlLanguage } from "@codemirror/lang-yaml";
|
||||
|
||||
import { StreamLanguage } from "@codemirror/language";
|
||||
import { ruby } from "@codemirror/legacy-modes/mode/ruby";
|
||||
import { shell } from "@codemirror/legacy-modes/mode/shell";
|
||||
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';
|
||||
|
||||
@@ -30,34 +39,43 @@ export class LanguageInfo {
|
||||
constructor(
|
||||
public token: SupportedLanguage,
|
||||
public name: string,
|
||||
public parser: any,
|
||||
public guesslang?: string | null
|
||||
public parser: any
|
||||
) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持的语言列表
|
||||
* 支持的语言列表(与 Worker 中的 LANGUAGES 对应)
|
||||
*/
|
||||
export const LANGUAGES: LanguageInfo[] = [
|
||||
new LanguageInfo("text", "Plain Text", null),
|
||||
new LanguageInfo("json", "JSON", jsonLanguage.parser, "json"),
|
||||
new LanguageInfo("python", "Python", pythonLanguage.parser, "py"),
|
||||
new LanguageInfo("javascript", "JavaScript", javascriptLanguage.parser, "js"),
|
||||
new LanguageInfo("typescript", "TypeScript", typescriptLanguage.parser, "ts"),
|
||||
new LanguageInfo("html", "HTML", htmlLanguage.parser, "html"),
|
||||
new LanguageInfo("css", "CSS", cssLanguage.parser, "css"),
|
||||
new LanguageInfo("sql", "SQL", StandardSQL.language.parser, "sql"),
|
||||
new LanguageInfo("markdown", "Markdown", markdownLanguage.parser, "md"),
|
||||
new LanguageInfo("java", "Java", javaLanguage.parser, "java"),
|
||||
new LanguageInfo("php", "PHP", phpLanguage.configure({top:"Program"}).parser, "php"),
|
||||
new LanguageInfo("xml", "XML", xmlLanguage.parser, "xml"),
|
||||
new LanguageInfo("cpp", "C++", cppLanguage.parser, "cpp"),
|
||||
new LanguageInfo("c", "C", cppLanguage.parser, "c"),
|
||||
new LanguageInfo("rust", "Rust", rustLanguage.parser, "rs"),
|
||||
new LanguageInfo("ruby", "Ruby", StreamLanguage.define(ruby).parser, "rb"),
|
||||
new LanguageInfo("shell", "Shell", StreamLanguage.define(shell).parser, "sh"),
|
||||
new LanguageInfo("yaml", "YAML", yamlLanguage.parser, "yaml"),
|
||||
new LanguageInfo("go", "Go", StreamLanguage.define(go).parser, "go"),
|
||||
new LanguageInfo("json", "JSON", jsonLanguage.parser),
|
||||
new LanguageInfo("py", "Python", pythonLanguage.parser),
|
||||
new LanguageInfo("html", "HTML", htmlLanguage.parser),
|
||||
new LanguageInfo("sql", "SQL", StandardSQL.language.parser),
|
||||
new LanguageInfo("md", "Markdown", markdownLanguage.parser),
|
||||
new LanguageInfo("java", "Java", javaLanguage.parser),
|
||||
new LanguageInfo("php", "PHP", phpLanguage.configure({top:"Program"}).parser),
|
||||
new LanguageInfo("css", "CSS", cssLanguage.parser),
|
||||
new LanguageInfo("xml", "XML", xmlLanguage.parser),
|
||||
new LanguageInfo("cpp", "C++", cppLanguage.parser),
|
||||
new LanguageInfo("rs", "Rust", rustLanguage.parser),
|
||||
new LanguageInfo("cs", "C#", StreamLanguage.define(csharp).parser),
|
||||
new LanguageInfo("rb", "Ruby", StreamLanguage.define(ruby).parser),
|
||||
new LanguageInfo("sh", "Shell", StreamLanguage.define(shell).parser),
|
||||
new LanguageInfo("yaml", "YAML", yamlLanguage.parser),
|
||||
new LanguageInfo("toml", "TOML", StreamLanguage.define(toml).parser),
|
||||
new LanguageInfo("go", "Go", StreamLanguage.define(go).parser),
|
||||
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),
|
||||
];
|
||||
|
||||
/**
|
||||
|
@@ -1,62 +1,92 @@
|
||||
/**
|
||||
* 自动语言检测
|
||||
* 基于内容变化自动检测和更新代码块语言
|
||||
* 基于 Web Worker 的语言自动检测
|
||||
*/
|
||||
|
||||
import { EditorState, Annotation } from '@codemirror/state';
|
||||
import { EditorView, ViewPlugin } from '@codemirror/view';
|
||||
import { blockState, getActiveNoteBlock } from '../state';
|
||||
import { blockState } from '../state';
|
||||
import { levenshteinDistance } from './levenshtein';
|
||||
import { detectLanguageHeuristic, LanguageDetectionResult } from './heuristics';
|
||||
import { LANGUAGES } from '../lang-parser/languages';
|
||||
import { SupportedLanguage, Block } from '../types';
|
||||
|
||||
// ===== 类型定义 =====
|
||||
|
||||
/**
|
||||
* 语言检测配置
|
||||
* 语言检测配置选项
|
||||
*/
|
||||
interface LanguageDetectionConfig {
|
||||
/** 最小内容长度阈值 */
|
||||
minContentLength: number;
|
||||
/** 变化阈值比例 */
|
||||
changeThreshold: number;
|
||||
/** 检测置信度阈值 */
|
||||
confidenceThreshold: number;
|
||||
/** 空闲检测延迟 (ms) */
|
||||
idleDelay: number;
|
||||
/** 默认语言 */
|
||||
defaultLanguage: SupportedLanguage;
|
||||
export interface LanguageDetectionConfig {
|
||||
minContentLength?: number;
|
||||
confidenceThreshold?: number;
|
||||
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 = {
|
||||
minContentLength: 8,
|
||||
changeThreshold: 0.1,
|
||||
confidenceThreshold: 0.3,
|
||||
const DEFAULT_CONFIG = {
|
||||
minContentLength: 20,
|
||||
confidenceThreshold: 0.15,
|
||||
idleDelay: 1000,
|
||||
defaultLanguage: 'text',
|
||||
defaultLanguage: 'text' as SupportedLanguage,
|
||||
};
|
||||
|
||||
/**
|
||||
* 语言标记映射
|
||||
* 将检测结果映射到我们的语言标记
|
||||
* 支持的语言列表
|
||||
*/
|
||||
const DETECTION_TO_TOKEN = Object.fromEntries(
|
||||
LANGUAGES.map(l => [l.token, l.token])
|
||||
);
|
||||
const SUPPORTED_LANGUAGES = new Set([
|
||||
"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) {
|
||||
return window.requestIdleCallback(cb);
|
||||
} else {
|
||||
return setTimeout(cb, 0) as any;
|
||||
return window.requestIdleCallback(callback);
|
||||
}
|
||||
return setTimeout(callback, 0) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容性函数:cancelIdleCallback
|
||||
*/
|
||||
function cancelIdleCallbackCompat(id: number): void {
|
||||
if (typeof window !== 'undefined' && window.cancelIdleCallback) {
|
||||
window.cancelIdleCallback(id);
|
||||
@@ -71,167 +101,192 @@ function cancelIdleCallbackCompat(id: number): void {
|
||||
const languageChangeAnnotation = Annotation.define<boolean>();
|
||||
|
||||
/**
|
||||
* 语言更改命令
|
||||
* 简化版本,直接更新块的语言标记
|
||||
* 更新代码块语言
|
||||
*/
|
||||
function changeLanguageTo(
|
||||
function updateBlockLanguage(
|
||||
state: EditorState,
|
||||
dispatch: (tr: any) => void,
|
||||
dispatch: (transaction: any) => void,
|
||||
block: Block,
|
||||
newLanguage: SupportedLanguage,
|
||||
isAuto: boolean
|
||||
newLanguage: SupportedLanguage
|
||||
): void {
|
||||
// 构建新的分隔符文本
|
||||
const autoSuffix = isAuto ? '-a' : '';
|
||||
const newDelimiter = `\n∞∞∞${newLanguage}${autoSuffix}\n`;
|
||||
|
||||
// 创建事务来替换分隔符
|
||||
const newDelimiter = `\n∞∞∞${newLanguage}-a\n`;
|
||||
const transaction = state.update({
|
||||
changes: {
|
||||
from: block.delimiter.from,
|
||||
to: block.delimiter.to,
|
||||
insert: newDelimiter,
|
||||
},
|
||||
annotations: [
|
||||
languageChangeAnnotation.of(true)
|
||||
]
|
||||
annotations: [languageChangeAnnotation.of(true)]
|
||||
});
|
||||
|
||||
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(
|
||||
config: Partial<LanguageDetectionConfig> = {}
|
||||
): ViewPlugin<any> {
|
||||
export function createLanguageDetection(config: LanguageDetectionConfig = {}): ViewPlugin<any> {
|
||||
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
||||
const previousBlockContent: Record<number, string> = {};
|
||||
const contentCache = new Map<number, string>();
|
||||
let idleCallbackId: number | null = null;
|
||||
let worker: LanguageDetectionWorker | null = null;
|
||||
|
||||
return ViewPlugin.fromClass(
|
||||
class LanguageDetectionPlugin {
|
||||
constructor(public view: EditorView) {}
|
||||
|
||||
update(update: any) {
|
||||
if (update.docChanged) {
|
||||
// 取消之前的检测
|
||||
if (idleCallbackId !== null) {
|
||||
cancelIdleCallbackCompat(idleCallbackId);
|
||||
idleCallbackId = null;
|
||||
constructor(public view: EditorView) {
|
||||
worker = new LanguageDetectionWorker();
|
||||
}
|
||||
|
||||
update(update: any) {
|
||||
if (update.docChanged && !update.transactions.some((tr: any) =>
|
||||
tr.annotation(languageChangeAnnotation))) {
|
||||
|
||||
if (idleCallbackId !== null) {
|
||||
cancelIdleCallbackCompat(idleCallbackId);
|
||||
}
|
||||
|
||||
// 安排新的检测
|
||||
idleCallbackId = requestIdleCallbackCompat(() => {
|
||||
idleCallbackId = null;
|
||||
this.performLanguageDetection(update);
|
||||
this.performDetection(update.state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private performLanguageDetection(update: any) {
|
||||
const range = update.state.selection.asSingle().ranges[0];
|
||||
const blocks = update.state.field(blockState);
|
||||
private performDetection(state: EditorState): void {
|
||||
const selection = state.selection.asSingle().ranges[0];
|
||||
const blocks = state.field(blockState);
|
||||
|
||||
let block: Block | null = null;
|
||||
let blockIndex: number | null = null;
|
||||
const block = blocks.find(b =>
|
||||
b.content.from <= selection.from && b.content.to >= selection.from
|
||||
);
|
||||
|
||||
// 找到当前块
|
||||
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 || !block.language.auto) return;
|
||||
|
||||
if (block === null || blockIndex === null) {
|
||||
return;
|
||||
}
|
||||
const blockIndex = blocks.indexOf(block);
|
||||
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 (block.language.name !== finalConfig.defaultLanguage) {
|
||||
changeLanguageTo(
|
||||
update.state,
|
||||
this.view.dispatch,
|
||||
block,
|
||||
finalConfig.defaultLanguage,
|
||||
true
|
||||
);
|
||||
updateBlockLanguage(state, this.view.dispatch, block, finalConfig.defaultLanguage);
|
||||
}
|
||||
delete previousBlockContent[blockIndex];
|
||||
contentCache.delete(blockIndex);
|
||||
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;
|
||||
}
|
||||
|
||||
// 检查内容是否有显著变化
|
||||
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;
|
||||
}
|
||||
}
|
||||
this.detectAndUpdate(content, block, blockIndex, state);
|
||||
}
|
||||
|
||||
private detectAndUpdateLanguage(
|
||||
content: string,
|
||||
block: any,
|
||||
blockIndex: number,
|
||||
state: EditorState
|
||||
) {
|
||||
private async detectAndUpdate(content: string, block: Block, blockIndex: number, state: EditorState): Promise<void> {
|
||||
if (!worker) return;
|
||||
|
||||
// 使用启发式检测
|
||||
const detectionResult = detectLanguageHeuristic(content);
|
||||
try {
|
||||
const result = await worker.detectLanguage(content);
|
||||
|
||||
// 检查置信度和语言变化
|
||||
if (detectionResult.confidence >= finalConfig.confidenceThreshold &&
|
||||
detectionResult.language !== block.language.name &&
|
||||
DETECTION_TO_TOKEN[detectionResult.language]) {
|
||||
if (result.confidence >= finalConfig.confidenceThreshold &&
|
||||
result.language !== block.language.name &&
|
||||
SUPPORTED_LANGUAGES.has(result.language) &&
|
||||
LANGUAGE_MAP.has(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
|
||||
);
|
||||
updateBlockLanguage(state, this.view.dispatch, block, result.language);
|
||||
}
|
||||
|
||||
contentCache.set(blockIndex, content);
|
||||
} catch (error) {
|
||||
console.warn('Language detection failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,21 +294,38 @@ export function createLanguageDetection(
|
||||
if (idleCallbackId !== null) {
|
||||
cancelIdleCallbackCompat(idleCallbackId);
|
||||
}
|
||||
if (worker) {
|
||||
worker.destroy();
|
||||
worker = null;
|
||||
}
|
||||
contentCache.clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ===== 公共 API =====
|
||||
|
||||
/**
|
||||
* 手动检测语言
|
||||
* 手动检测单个内容的语言
|
||||
*/
|
||||
export function detectLanguage(content: string): LanguageDetectionResult {
|
||||
return detectLanguageHeuristic(content);
|
||||
export async function detectLanguage(content: string): Promise<LanguageDetectionResult> {
|
||||
const worker = new LanguageDetectionWorker();
|
||||
try {
|
||||
return await worker.detectLanguage(content);
|
||||
} finally {
|
||||
worker.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量检测多个内容块的语言
|
||||
* 批量检测多个内容的语言
|
||||
*/
|
||||
export function detectLanguages(contents: string[]): LanguageDetectionResult[] {
|
||||
return contents.map(content => detectLanguageHeuristic(content));
|
||||
export async function detectLanguages(contents: string[]): Promise<LanguageDetectionResult[]> {
|
||||
const worker = new LanguageDetectionWorker();
|
||||
try {
|
||||
return await Promise.all(contents.map(content => worker.detectLanguage(content)));
|
||||
} finally {
|
||||
worker.destroy();
|
||||
}
|
||||
}
|
@@ -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[];
|
||||
}
|
@@ -1,26 +1,14 @@
|
||||
/**
|
||||
* 语言检测模块入口
|
||||
* 导出所有语言检测相关的功能
|
||||
* 语言检测模块
|
||||
*/
|
||||
|
||||
// 主要检测功能
|
||||
export {
|
||||
createLanguageDetection,
|
||||
detectLanguage,
|
||||
detectLanguages
|
||||
detectLanguages,
|
||||
type LanguageDetectionResult,
|
||||
type LanguageDetectionConfig
|
||||
} from './autodetect';
|
||||
|
||||
// 启发式检测
|
||||
export {
|
||||
detectLanguageHeuristic,
|
||||
getSupportedDetectionLanguages,
|
||||
type LanguageDetectionResult
|
||||
} from './heuristics';
|
||||
|
||||
// 工具函数
|
||||
export {
|
||||
levenshteinDistance
|
||||
} from './levenshtein';
|
||||
|
||||
// 重新导出类型
|
||||
export { levenshteinDistance } from './levenshtein';
|
||||
export type { SupportedLanguage } from '../types';
|
@@ -1,78 +1,70 @@
|
||||
/**
|
||||
* 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
|
||||
? d0 > d2
|
||||
? d2 + 1
|
||||
: d0 + 1
|
||||
: bx === ay
|
||||
? d1
|
||||
: d1 + 1;
|
||||
? d0 > d2 ? d2 + 1 : d0 + 1
|
||||
: bx === ay ? d1 : d1 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个字符串之间的 Levenshtein 距离
|
||||
* @param a 第一个字符串
|
||||
* @param b 第二个字符串
|
||||
* @returns 编辑距离
|
||||
*
|
||||
* 该实现使用了多项优化:
|
||||
* 1. 确保较短的字符串作为第一个参数
|
||||
* 2. 跳过公共前缀和后缀
|
||||
* 3. 使用滚动数组减少空间复杂度
|
||||
* 4. 批量处理以提高性能
|
||||
*
|
||||
* @param stringA - 第一个字符串
|
||||
* @param stringB - 第二个字符串
|
||||
* @returns 编辑距离(非负整数)
|
||||
*/
|
||||
export function levenshteinDistance(a: string, b: string): number {
|
||||
if (a === b) {
|
||||
return 0;
|
||||
}
|
||||
if (a === b) return 0;
|
||||
|
||||
if (a.length > b.length) {
|
||||
const tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
[a, b] = [b, a];
|
||||
}
|
||||
|
||||
let la = a.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--;
|
||||
lb--;
|
||||
}
|
||||
|
||||
let offset = 0;
|
||||
|
||||
while (offset < la && (a.charCodeAt(offset) === b.charCodeAt(offset))) {
|
||||
// 跳过公共前缀
|
||||
while (offset < la && a.charCodeAt(offset) === b.charCodeAt(offset)) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
la -= offset;
|
||||
lb -= offset;
|
||||
|
||||
if (la === 0 || lb < 3) {
|
||||
return lb;
|
||||
}
|
||||
if (la === 0 || lb < 3) return lb;
|
||||
|
||||
let x = 0;
|
||||
let y: 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;
|
||||
let x = 0, y: number, d0: number, d1: number, d2: number, d3: number;
|
||||
let dd = 0, dy: number, ay: number, bx0: number, bx1: number, bx2: number, bx3: number;
|
||||
|
||||
const vector: number[] = [];
|
||||
|
||||
for (y = 0; y < la; y++) {
|
||||
vector.push(y + 1);
|
||||
vector.push(a.charCodeAt(offset + y));
|
||||
vector.push(y + 1, a.charCodeAt(offset + y));
|
||||
}
|
||||
|
||||
const len = vector.length - 1;
|
||||
@@ -84,18 +76,16 @@ export function levenshteinDistance(a: string, b: string): number {
|
||||
bx3 = b.charCodeAt(offset + (d3 = x + 3));
|
||||
x += 4;
|
||||
dd = x;
|
||||
|
||||
for (y = 0; y < len; y += 2) {
|
||||
dy = vector[y];
|
||||
ay = vector[y + 1];
|
||||
d0 = _min(dy, d0, d1, bx0, ay);
|
||||
d1 = _min(d0, d1, d2, bx1, ay);
|
||||
d2 = _min(d1, d2, d3, bx2, ay);
|
||||
dd = _min(d2, d3, dd, bx3, ay);
|
||||
d0 = min(dy, d0, d1, bx0, ay);
|
||||
d1 = min(d0, d1, d2, bx1, ay);
|
||||
d2 = min(d1, d2, d3, bx2, ay);
|
||||
dd = min(d2, d3, dd, bx3, ay);
|
||||
vector[y] = dd;
|
||||
d3 = d2;
|
||||
d2 = d1;
|
||||
d1 = d0;
|
||||
d0 = dy;
|
||||
d3 = d2; d2 = d1; d1 = d0; d0 = dy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +94,7 @@ export function levenshteinDistance(a: string, b: string): number {
|
||||
dd = ++x;
|
||||
for (y = 0; y < len; y += 2) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -25,48 +25,68 @@ export interface Block {
|
||||
*/
|
||||
export type SupportedLanguage =
|
||||
| 'text'
|
||||
| 'javascript'
|
||||
| 'typescript'
|
||||
| 'python'
|
||||
| 'html'
|
||||
| 'css'
|
||||
| 'json'
|
||||
| 'markdown'
|
||||
| 'shell'
|
||||
| 'py' // Python
|
||||
| 'html'
|
||||
| 'sql'
|
||||
| 'yaml'
|
||||
| 'xml'
|
||||
| 'php'
|
||||
| 'md' // Markdown
|
||||
| 'java'
|
||||
| 'cpp'
|
||||
| 'c'
|
||||
| 'php'
|
||||
| 'css'
|
||||
| 'xml'
|
||||
| 'cpp' // C++
|
||||
| 'rs' // Rust
|
||||
| 'cs' // C#
|
||||
| 'rb' // Ruby
|
||||
| 'sh' // Shell
|
||||
| 'yaml'
|
||||
| 'toml'
|
||||
| 'go'
|
||||
| 'rust'
|
||||
| 'ruby';
|
||||
| 'clj' // Clojure
|
||||
| 'ex' // Elixir
|
||||
| 'erl' // Erlang
|
||||
| 'js' // JavaScript
|
||||
| 'ts' // TypeScript
|
||||
| 'swift'
|
||||
| 'kt' // Kotlin
|
||||
| 'groovy'
|
||||
| 'ps1' // PowerShell
|
||||
| 'dart'
|
||||
| 'scala';
|
||||
|
||||
/**
|
||||
* 支持的语言列表
|
||||
*/
|
||||
export const SUPPORTED_LANGUAGES: SupportedLanguage[] = [
|
||||
'text',
|
||||
'javascript',
|
||||
'typescript',
|
||||
'python',
|
||||
'html',
|
||||
'css',
|
||||
'json',
|
||||
'markdown',
|
||||
'shell',
|
||||
'py',
|
||||
'html',
|
||||
'sql',
|
||||
'yaml',
|
||||
'xml',
|
||||
'php',
|
||||
'md',
|
||||
'java',
|
||||
'php',
|
||||
'css',
|
||||
'xml',
|
||||
'cpp',
|
||||
'c',
|
||||
'rs',
|
||||
'cs',
|
||||
'rb',
|
||||
'sh',
|
||||
'yaml',
|
||||
'toml',
|
||||
'go',
|
||||
'rust',
|
||||
'ruby'
|
||||
'clj',
|
||||
'ex',
|
||||
'erl',
|
||||
'js',
|
||||
'ts',
|
||||
'swift',
|
||||
'kt',
|
||||
'groovy',
|
||||
'ps1',
|
||||
'dart',
|
||||
'scala'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -134,9 +154,6 @@ export interface BlockStateUpdate {
|
||||
operation?: BlockOperation;
|
||||
}
|
||||
|
||||
// 块导航方向
|
||||
export type NavigationDirection = 'next' | 'previous' | 'first' | 'last';
|
||||
|
||||
// 语言检测结果
|
||||
export interface LanguageDetectionResult {
|
||||
language: SupportedLanguage;
|
||||
|
Reference in New Issue
Block a user