diff --git a/.vscodeignore b/.vscodeignore index ae09c7a..2319f42 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -12,7 +12,7 @@ client/webpack.config.js server/node_modules/** server/src/** server/webpack.config.js -server/lib/** +server/lib/*-isclexer.node node_modules/** images/*.gif **/*.vsix diff --git a/client/package-lock.json b/client/package-lock.json index 158d7b1..0a5b396 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "language-server-client", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "language-server-client", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "dependencies": { "axios": "^1.15.0", "vscode-languageclient": "^9.0.1" diff --git a/client/package.json b/client/package.json index 7d04fce..ac93a77 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,7 @@ { "name": "language-server-client", "author": "InterSystems Corporation", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "private": true, "engines": { "vscode": "^1.93.0" @@ -15,4 +15,4 @@ "@types/semver": "^7.7.0", "@types/vscode": "1.93.0" } -} +} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index bd0725c..7a97ddb 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -10,6 +10,9 @@ export default tseslint.config( { rules: { "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-empty-object-type": "off", + "@typescript-eslint/no-unused-vars": "warn", "no-control-regex": "off", }, } diff --git a/package-lock.json b/package-lock.json index 528508d..889f275 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "language-server", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "language-server", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE.txt", "devDependencies": { "@eslint/js": "^10.0.1", + "@types/eslint": "^9.6.1", "@types/node": "^22.15.33", "@types/turndown": "^5.0.6", "@vscode/vsce": "^3.7.1", @@ -30,6 +31,11 @@ "vscode": "^1.93.0" } }, + "../iris-class/pkg": { + "name": "iris-class", + "version": "0.1.0", + "extraneous": true + }, "node_modules/@azu/format-text": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", @@ -309,40 +315,6 @@ "node": ">=14.17.0" } }, - "node_modules/@emnapi/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", - "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.0.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", - "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -667,19 +639,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" - } - }, "node_modules/@node-rs/crc32": { "version": "1.10.6", "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz", @@ -710,40 +669,6 @@ "@node-rs/crc32-win32-x64-msvc": "1.10.6" } }, - "node_modules/@node-rs/crc32-android-arm-eabi": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz", - "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-android-arm64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz", - "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@node-rs/crc32-darwin-arm64": { "version": "1.10.6", "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz", @@ -761,193 +686,6 @@ "node": ">= 10" } }, - "node_modules/@node-rs/crc32-darwin-x64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz", - "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-freebsd-x64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz", - "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-arm-gnueabihf": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz", - "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-arm64-gnu": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz", - "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-arm64-musl": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz", - "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-x64-gnu": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz", - "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-linux-x64-musl": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz", - "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-wasm32-wasi": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz", - "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.5" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@node-rs/crc32-win32-arm64-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz", - "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-win32-ia32-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz", - "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/crc32-win32-x64-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz", - "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1279,37 +1017,17 @@ "@textlint/ast-node-types": "15.5.0" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -1686,32 +1404,6 @@ "@vscode/vsce-sign-win32-x64": "2.0.2" } }, - "node_modules/@vscode/vsce-sign-alpine-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.2.tgz", - "integrity": "sha512-E80YvqhtZCLUv3YAf9+tIbbqoinWLCO/B3j03yQPbjT3ZIHCliKZlsy1peNc4XNZ5uIb87Jn0HWx/ZbPXviuAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "alpine" - ] - }, - "node_modules/@vscode/vsce-sign-alpine-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.2.tgz", - "integrity": "sha512-n1WC15MSMvTaeJ5KjWCzo0nzjydwxLyoHiMJHu1Ov0VWTZiddasmOQHekA47tFRycnt4FsQrlkSCTdgHppn6bw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "alpine" - ] - }, "node_modules/@vscode/vsce-sign-darwin-arm64": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz", @@ -1725,84 +1417,6 @@ "darwin" ] }, - "node_modules/@vscode/vsce-sign-darwin-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.2.tgz", - "integrity": "sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/vsce-sign-linux-arm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.2.tgz", - "integrity": "sha512-Fkb5jpbfhZKVw3xwR6t7WYfwKZktVGNXdg1m08uEx1anO0oUPUkoQRsNm4QniL3hmfw0ijg00YA6TrxCRkPVOQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-linux-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.2.tgz", - "integrity": "sha512-Ybeu7cA6+/koxszsORXX0OJk9N0GgfHq70Wqi4vv2iJCZvBrOWwcIrxKjvFtwyDgdeQzgPheH5nhLVl5eQy7WA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-linux-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.2.tgz", - "integrity": "sha512-NsPPFVtLaTlVJKOiTnO8Cl78LZNWy0Q8iAg+LlBiCDEgC12Gt4WXOSs2pmcIjDYzj2kY4NwdeN1mBTaujYZaPg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-win32-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.2.tgz", - "integrity": "sha512-wPs848ymZ3Ny+Y1Qlyi7mcT6VSigG89FWQnp2qRYCyMhdJxOpA4lDwxzlpL8fG6xC8GjQjGDkwbkWUcCobvksQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/vsce-sign-win32-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.2.tgz", - "integrity": "sha512-pAiRN6qSAhDM5SVOIxgx+2xnoVUePHbRNC7OD2aOR3WltTKxxF25OfpK8h8UQ7A0BuRkSgREbB59DBlFk4iAeg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@vscode/vsce/node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -6562,6 +6176,17 @@ "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6995,37 +6620,6 @@ "integrity": "sha512-dDlz3W405VMFO4w5kIP9DOmELBcvFQGmLoKSdIRstBDubKFYwaNHV1NnlzMCQpXQFGWVALmeMORAuiLx18AvZQ==", "dev": true }, - "@emnapi/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", - "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", - "dev": true, - "optional": true, - "requires": { - "@emnapi/wasi-threads": "1.0.2", - "tslib": "^2.4.0" - } - }, - "@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", - "dev": true, - "optional": true, - "requires": { - "tslib": "^2.4.0" - } - }, - "@emnapi/wasi-threads": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", - "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", - "dev": true, - "optional": true, - "requires": { - "tslib": "^2.4.0" - } - }, "@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -7236,18 +6830,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", - "dev": true, - "optional": true, - "requires": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" - } - }, "@node-rs/crc32": { "version": "1.10.6", "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz", @@ -7270,20 +6852,6 @@ "@node-rs/crc32-win32-x64-msvc": "1.10.6" } }, - "@node-rs/crc32-android-arm-eabi": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz", - "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-android-arm64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz", - "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==", - "dev": true, - "optional": true - }, "@node-rs/crc32-darwin-arm64": { "version": "1.10.6", "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz", @@ -7291,86 +6859,6 @@ "dev": true, "optional": true }, - "@node-rs/crc32-darwin-x64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz", - "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-freebsd-x64": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz", - "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-linux-arm-gnueabihf": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz", - "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-linux-arm64-gnu": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz", - "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-linux-arm64-musl": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz", - "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-linux-x64-gnu": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz", - "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-linux-x64-musl": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz", - "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-wasm32-wasi": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz", - "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==", - "dev": true, - "optional": true, - "requires": { - "@napi-rs/wasm-runtime": "^0.2.5" - } - }, - "@node-rs/crc32-win32-arm64-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz", - "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-win32-ia32-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz", - "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==", - "dev": true, - "optional": true - }, - "@node-rs/crc32-win32-x64-msvc": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz", - "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==", - "dev": true, - "optional": true - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7622,16 +7110,6 @@ "@textlint/ast-node-types": "15.5.0" } }, - "@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, - "optional": true, - "requires": { - "tslib": "^2.4.0" - } - }, "@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -7642,16 +7120,6 @@ "@types/json-schema": "*" } }, - "@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -7901,20 +7369,6 @@ "@vscode/vsce-sign-win32-x64": "2.0.2" } }, - "@vscode/vsce-sign-alpine-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.2.tgz", - "integrity": "sha512-E80YvqhtZCLUv3YAf9+tIbbqoinWLCO/B3j03yQPbjT3ZIHCliKZlsy1peNc4XNZ5uIb87Jn0HWx/ZbPXviuAQ==", - "dev": true, - "optional": true - }, - "@vscode/vsce-sign-alpine-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.2.tgz", - "integrity": "sha512-n1WC15MSMvTaeJ5KjWCzo0nzjydwxLyoHiMJHu1Ov0VWTZiddasmOQHekA47tFRycnt4FsQrlkSCTdgHppn6bw==", - "dev": true, - "optional": true - }, "@vscode/vsce-sign-darwin-arm64": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz", @@ -7922,48 +7376,6 @@ "dev": true, "optional": true }, - "@vscode/vsce-sign-darwin-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.2.tgz", - "integrity": "sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==", - "dev": true, - "optional": true - }, - "@vscode/vsce-sign-linux-arm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.2.tgz", - "integrity": "sha512-Fkb5jpbfhZKVw3xwR6t7WYfwKZktVGNXdg1m08uEx1anO0oUPUkoQRsNm4QniL3hmfw0ijg00YA6TrxCRkPVOQ==", - "dev": true, - "optional": true - }, - "@vscode/vsce-sign-linux-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.2.tgz", - "integrity": "sha512-Ybeu7cA6+/koxszsORXX0OJk9N0GgfHq70Wqi4vv2iJCZvBrOWwcIrxKjvFtwyDgdeQzgPheH5nhLVl5eQy7WA==", - "dev": true, - "optional": true - }, - "@vscode/vsce-sign-linux-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.2.tgz", - "integrity": "sha512-NsPPFVtLaTlVJKOiTnO8Cl78LZNWy0Q8iAg+LlBiCDEgC12Gt4WXOSs2pmcIjDYzj2kY4NwdeN1mBTaujYZaPg==", - "dev": true, - "optional": true - }, - "@vscode/vsce-sign-win32-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.2.tgz", - "integrity": "sha512-wPs848ymZ3Ny+Y1Qlyi7mcT6VSigG89FWQnp2qRYCyMhdJxOpA4lDwxzlpL8fG6xC8GjQjGDkwbkWUcCobvksQ==", - "dev": true, - "optional": true - }, - "@vscode/vsce-sign-win32-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.2.tgz", - "integrity": "sha512-pAiRN6qSAhDM5SVOIxgx+2xnoVUePHbRNC7OD2aOR3WltTKxxF25OfpK8h8UQ7A0BuRkSgREbB59DBlFk4iAeg==", - "dev": true, - "optional": true - }, "@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -11197,6 +10609,18 @@ "terser-webpack-plugin": "^5.3.17", "watchpack": "^2.5.1", "webpack-sources": "^3.3.4" + }, + "dependencies": { + "@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + } } }, "webpack-cli": { diff --git a/package.json b/package.json index ccaecad..a40bfc1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "A language server for InterSystems ObjectScript.", "author": "InterSystems Corporation", "license": "SEE LICENSE IN LICENSE.txt", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "publisher": "intersystems", "repository": { "type": "github", @@ -1796,6 +1796,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@types/eslint": "^9.6.1", "@types/node": "^22.15.33", "@types/turndown": "^5.0.6", "@vscode/vsce": "^3.7.1", diff --git a/server/lib/analyzer.wasm b/server/lib/analyzer.wasm new file mode 100755 index 0000000..47c83ca Binary files /dev/null and b/server/lib/analyzer.wasm differ diff --git a/server/package-lock.json b/server/package-lock.json index 0233843..13a65e7 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,13 +1,14 @@ { "name": "language-server-server", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "language-server-server", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "dependencies": { + "@vscode/wasm-component-model": "^1.0.2", "node-html-parser": "^7.1.0", "turndown": "^7.2.4", "vscode-languageserver": "^9.0.1", @@ -23,11 +24,84 @@ "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" }, + "node_modules/@vscode/wasm-component-model": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vscode/wasm-component-model/-/wasm-component-model-1.0.2.tgz", + "integrity": "sha512-3eBdSLvW1wAg2xHHupPD65S7/5eNpHiUY6hurLsoLB39GRGeC+hdthYXLHhbP7OtClhQS+flVH4Uy3ua9kT0pA==", + "license": "MIT", + "dependencies": { + "semver": "^7.7.2", + "uuid": "^11.1.0", + "yargs": "^17.7.2" + }, + "bin": { + "wit2ts": "bin/wit2ts" + }, + "engines": { + "node": ">=18.18.2" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, "node_modules/css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -105,6 +179,12 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, "node_modules/entities": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", @@ -116,6 +196,24 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -124,6 +222,15 @@ "he": "bin/he" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/node-html-parser": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-7.1.0.tgz", @@ -145,6 +252,53 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/turndown": { "version": "7.2.4", "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz", @@ -158,6 +312,19 @@ "npm": ">=9" } }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -200,6 +367,59 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } } }, "dependencies": { @@ -208,11 +428,57 @@ "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==" }, + "@vscode/wasm-component-model": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@vscode/wasm-component-model/-/wasm-component-model-1.0.2.tgz", + "integrity": "sha512-3eBdSLvW1wAg2xHHupPD65S7/5eNpHiUY6hurLsoLB39GRGeC+hdthYXLHhbP7OtClhQS+flVH4Uy3ua9kT0pA==", + "requires": { + "semver": "^7.7.2", + "uuid": "^11.1.0", + "yargs": "^17.7.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -263,16 +529,36 @@ "domhandler": "^5.0.1" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "entities": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" }, + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, "node-html-parser": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-7.1.0.tgz", @@ -290,6 +576,34 @@ "boolbase": "^1.0.0" } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, "turndown": { "version": "7.2.4", "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz", @@ -298,6 +612,11 @@ "@mixmark-io/domino": "^2.2.0" } }, + "uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==" + }, "vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", @@ -334,6 +653,40 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" } } } diff --git a/server/package.json b/server/package.json index f8e221c..a56c479 100644 --- a/server/package.json +++ b/server/package.json @@ -1,16 +1,17 @@ { "name": "language-server-server", - "version": "2.8.4-SNAPSHOT", + "version": "2.9.0-LOCAL", "author": "InterSystems Corporation", "private": true, "engines": { "node": "*" }, "dependencies": { + "@vscode/wasm-component-model": "^1.0.2", "node-html-parser": "^7.1.0", "turndown": "^7.2.4", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.12", "vscode-uri": "^3.1.0" } -} +} \ No newline at end of file diff --git a/server/src/analyzer/bind.ts b/server/src/analyzer/bind.ts new file mode 100644 index 0000000..5e0d6c1 --- /dev/null +++ b/server/src/analyzer/bind.ts @@ -0,0 +1,640 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as $wcm from '@vscode/wasm-component-model'; +import type { u32, u8, i32, ptr, result } from '@vscode/wasm-component-model'; + +export namespace AnalyzerInterface { + export type Position = { + line: u32; + character: u32; + }; + + export type Range = { + start: Position; + end: Position; + }; + + export type Location = { + uri: string; + range: Range; + }; + + export type DiagnosticRelatedInformation = { + location: Location; + message: string; + }; + + export type NameInfo = { + before: Position; + content: string; + after: Position; + }; + + export enum ArgMode { + default = 'default', + output = 'output', + byRef = 'byRef' + } + + export type NormalArg = { + mode: ArgMode; + name: string; + t?: string | undefined; + optional: boolean; + }; + + export type VariadicArg = { + name: string; + t?: string | undefined; + }; + + export type MethodInfo = { + normal: NormalArg[]; + variadic?: VariadicArg | undefined; + t?: string | undefined; + body: Range; + }; + + export type ParameterInfo = { + t?: string | undefined; + v?: string | undefined; + }; + + export namespace MemberKind { + export const parameter = 'parameter' as const; + export type Parameter = { readonly tag: typeof parameter; readonly value: ParameterInfo } & _common; + export function Parameter(value: ParameterInfo): Parameter { + return new VariantImpl(parameter, value) as Parameter; + } + + export const property = 'property' as const; + export type Property = { readonly tag: typeof property; readonly value: string | undefined } & _common; + export function Property(value: string | undefined): Property { + return new VariantImpl(property, value) as Property; + } + + export const relationship = 'relationship' as const; + export type Relationship = { readonly tag: typeof relationship; readonly value: string | undefined } & _common; + export function Relationship(value: string | undefined): Relationship { + return new VariantImpl(relationship, value) as Relationship; + } + + export const foreignKey = 'foreignKey' as const; + export type ForeignKey = { readonly tag: typeof foreignKey } & _common; + export function ForeignKey(): ForeignKey { + return new VariantImpl(foreignKey, undefined) as ForeignKey; + } + + export const index = 'index' as const; + export type Index = { readonly tag: typeof index } & _common; + export function Index(): Index { + return new VariantImpl(index, undefined) as Index; + } + + export const projection = 'projection' as const; + export type Projection = { readonly tag: typeof projection } & _common; + export function Projection(): Projection { + return new VariantImpl(projection, undefined) as Projection; + } + + export const trigger = 'trigger' as const; + export type Trigger = { readonly tag: typeof trigger } & _common; + export function Trigger(): Trigger { + return new VariantImpl(trigger, undefined) as Trigger; + } + + export const xData = 'xData' as const; + export type XData = { readonly tag: typeof xData } & _common; + export function XData(): XData { + return new VariantImpl(xData, undefined) as XData; + } + + export const storage = 'storage' as const; + export type Storage = { readonly tag: typeof storage } & _common; + export function Storage(): Storage { + return new VariantImpl(storage, undefined) as Storage; + } + + export const query = 'query' as const; + export type Query = { readonly tag: typeof query } & _common; + export function Query(): Query { + return new VariantImpl(query, undefined) as Query; + } + + export const method = 'method' as const; + export type Method = { readonly tag: typeof method; readonly value: MethodInfo } & _common; + export function Method(value: MethodInfo): Method { + return new VariantImpl(method, value) as Method; + } + + export const classMethod = 'classMethod' as const; + export type ClassMethod = { readonly tag: typeof classMethod; readonly value: MethodInfo } & _common; + export function ClassMethod(value: MethodInfo): ClassMethod { + return new VariantImpl(classMethod, value) as ClassMethod; + } + + export const clientMethod = 'clientMethod' as const; + export type ClientMethod = { readonly tag: typeof clientMethod; readonly value: MethodInfo } & _common; + export function ClientMethod(value: MethodInfo): ClientMethod { + return new VariantImpl(clientMethod, value) as ClientMethod; + } + + export type _tt = typeof parameter | typeof property | typeof relationship | typeof foreignKey | typeof index | typeof projection | typeof trigger | typeof xData | typeof storage | typeof query | typeof method | typeof classMethod | typeof clientMethod; + export type _vt = ParameterInfo | string | undefined | string | undefined | MethodInfo | MethodInfo | MethodInfo | undefined; + type _common = Omit; + export function _ctor(t: _tt, v: _vt): MemberKind { + return new VariantImpl(t, v) as MemberKind; + } + class VariantImpl { + private readonly _tag: _tt; + private readonly _value?: _vt; + constructor(t: _tt, value: _vt) { + this._tag = t; + this._value = value; + } + get tag(): _tt { + return this._tag; + } + get value(): _vt { + return this._value; + } + isParameter(): this is Parameter { + return this._tag === MemberKind.parameter; + } + isProperty(): this is Property { + return this._tag === MemberKind.property; + } + isRelationship(): this is Relationship { + return this._tag === MemberKind.relationship; + } + isForeignKey(): this is ForeignKey { + return this._tag === MemberKind.foreignKey; + } + isIndex(): this is Index { + return this._tag === MemberKind.index; + } + isProjection(): this is Projection { + return this._tag === MemberKind.projection; + } + isTrigger(): this is Trigger { + return this._tag === MemberKind.trigger; + } + isXData(): this is XData { + return this._tag === MemberKind.xData; + } + isStorage(): this is Storage { + return this._tag === MemberKind.storage; + } + isQuery(): this is Query { + return this._tag === MemberKind.query; + } + isMethod(): this is Method { + return this._tag === MemberKind.method; + } + isClassMethod(): this is ClassMethod { + return this._tag === MemberKind.classMethod; + } + isClientMethod(): this is ClientMethod { + return this._tag === MemberKind.clientMethod; + } + } + } + export type MemberKind = MemberKind.Parameter | MemberKind.Property | MemberKind.Relationship | MemberKind.ForeignKey | MemberKind.Index | MemberKind.Projection | MemberKind.Trigger | MemberKind.XData | MemberKind.Storage | MemberKind.Query | MemberKind.Method | MemberKind.ClassMethod | MemberKind.ClientMethod; + + export type MemberInfo = { + doc: string; + before: Position; + name: NameInfo; + deprecated: boolean; + kind: MemberKind; + after: Position; + }; + + export type ClassInfo = { + doc: string; + name: NameInfo; + extends: string[]; + deprecated: boolean; + members: MemberInfo[]; + }; + + export type MacroInfo = { + name: NameInfo; + args: string[]; + }; + + export type SubroutineInfo = { + name: NameInfo; + args: string[]; + }; + + export namespace RoutineInfo { + export const inc = 'INC' as const; + export type INC = { readonly tag: typeof inc; readonly value: MacroInfo[] } & _common; + export function INC(value: MacroInfo[]): INC { + return new VariantImpl(inc, value) as INC; + } + + export const int = 'INT' as const; + export type INT = { readonly tag: typeof int; readonly value: SubroutineInfo[] } & _common; + export function INT(value: SubroutineInfo[]): INT { + return new VariantImpl(int, value) as INT; + } + + export const mac = 'MAC' as const; + export type MAC = { readonly tag: typeof mac; readonly value: SubroutineInfo[] } & _common; + export function MAC(value: SubroutineInfo[]): MAC { + return new VariantImpl(mac, value) as MAC; + } + + export type _tt = typeof inc | typeof int | typeof mac; + export type _vt = MacroInfo[] | SubroutineInfo[] | SubroutineInfo[]; + type _common = Omit; + export function _ctor(t: _tt, v: _vt): RoutineInfo { + return new VariantImpl(t, v) as RoutineInfo; + } + class VariantImpl { + private readonly _tag: _tt; + private readonly _value: _vt; + constructor(t: _tt, value: _vt) { + this._tag = t; + this._value = value; + } + get tag(): _tt { + return this._tag; + } + get value(): _vt { + return this._value; + } + isINC(): this is INC { + return this._tag === RoutineInfo.inc; + } + isINT(): this is INT { + return this._tag === RoutineInfo.int; + } + isMAC(): this is MAC { + return this._tag === RoutineInfo.mac; + } + } + } + export type RoutineInfo = RoutineInfo.INC | RoutineInfo.INT | RoutineInfo.MAC; + + export type ParseErr = { + range: Range; + message: string; + }; + + export namespace AnalysisErr { + export const p = 'P' as const; + export type P = { readonly tag: typeof p; readonly value: ParseErr } & _common; + export function P(value: ParseErr): P { + return new VariantImpl(p, value) as P; + } + + export type _tt = typeof p; + export type _vt = ParseErr; + type _common = Omit; + export function _ctor(t: _tt, v: _vt): AnalysisErr { + return new VariantImpl(t, v) as AnalysisErr; + } + class VariantImpl { + private readonly _tag: _tt; + private readonly _value: _vt; + constructor(t: _tt, value: _vt) { + this._tag = t; + this._value = value; + } + get tag(): _tt { + return this._tag; + } + get value(): _vt { + return this._value; + } + isP(): this is P { + return this._tag === AnalysisErr.p; + } + } + } + export type AnalysisErr = AnalysisErr.P; + export namespace AnalysisErr { + export class Error_ extends $wcm.ResultError { + constructor(cause: AnalysisErr) { + super(`AnalysisErr: ${cause}`, cause); + } + } + } + + export type Completion = { + classname?: u8 | undefined; + variable?: u8 | undefined; + command?: u8 | undefined; + }; + + export type Diagnostic = { + message: string; + range: Range; + relatedInformation: DiagnosticRelatedInformation[]; + }; + + export namespace Workspace { + export interface Interface extends $wcm.Resource { + /** + * @throws AnalysisErr.Error_ + */ + insertCls(uri: string, src: string): ClassInfo; + + /** + * @throws AnalysisErr.Error_ + */ + insertRtn(uri: string, src: string): RoutineInfo; + + remove(uri: string): void; + + check(uri: string): Diagnostic[]; + + /** + * returns uri and class-info + */ + queryCls(query: string): [string, ClassInfo][]; + + /** + * returns uri and member-info + */ + queryMem(cls: string, query: string): [string, MemberInfo][]; + } + export type Statics = { + $new?(): Interface; + }; + export type Class = Statics & { + new(): Interface; + }; + } + export type Workspace = Workspace.Interface; + + /** + * @throws AnalysisErr.Error_ + */ + export type completeClass = (prefix: string) => Completion; + + /** + * @throws AnalysisErr.Error_ + */ + export type completeMethod = (prefix: string) => Completion; +} +export type AnalyzerInterface = { + Workspace: AnalyzerInterface.Workspace.Class; + completeClass: AnalyzerInterface.completeClass; + completeMethod: AnalyzerInterface.completeMethod; +}; +export namespace analyzer { + export type Imports = { + }; + export namespace Imports { + export type Promisified = $wcm.$imports.Promisify; + } + export namespace imports { + export type Promisify = $wcm.$imports.Promisify; + } + export type Exports = { + analyzerInterface: AnalyzerInterface; + }; + export namespace Exports { + export type Promisified = $wcm.$exports.Promisify; + } + export namespace exports { + export type Promisify = $wcm.$exports.Promisify; + } +} + +export namespace AnalyzerInterface.$ { + export const Position = new $wcm.RecordType([ + ['line', $wcm.u32], + ['character', $wcm.u32], + ]); + export const Range = new $wcm.RecordType([ + ['start', Position], + ['end', Position], + ]); + export const Location = new $wcm.RecordType([ + ['uri', $wcm.wstring], + ['range', Range], + ]); + export const DiagnosticRelatedInformation = new $wcm.RecordType([ + ['location', Location], + ['message', $wcm.wstring], + ]); + export const NameInfo = new $wcm.RecordType([ + ['before', Position], + ['content', $wcm.wstring], + ['after', Position], + ]); + export const ArgMode = new $wcm.EnumType(['default', 'output', 'byRef']); + export const NormalArg = new $wcm.RecordType([ + ['mode', ArgMode], + ['name', $wcm.wstring], + ['t', new $wcm.OptionType($wcm.wstring)], + ['optional', $wcm.bool], + ]); + export const VariadicArg = new $wcm.RecordType([ + ['name', $wcm.wstring], + ['t', new $wcm.OptionType($wcm.wstring)], + ]); + export const MethodInfo = new $wcm.RecordType([ + ['normal', new $wcm.ListType(NormalArg)], + ['variadic', new $wcm.OptionType(VariadicArg)], + ['t', new $wcm.OptionType($wcm.wstring)], + ['body', Range], + ]); + export const ParameterInfo = new $wcm.RecordType([ + ['t', new $wcm.OptionType($wcm.wstring)], + ['v', new $wcm.OptionType($wcm.wstring)], + ]); + export const MemberKind = new $wcm.VariantType([['parameter', ParameterInfo], ['property', new $wcm.OptionType($wcm.wstring)], ['relationship', new $wcm.OptionType($wcm.wstring)], ['foreignKey', undefined], ['index', undefined], ['projection', undefined], ['trigger', undefined], ['xData', undefined], ['storage', undefined], ['query', undefined], ['method', MethodInfo], ['classMethod', MethodInfo], ['clientMethod', MethodInfo]], AnalyzerInterface.MemberKind._ctor); + export const MemberInfo = new $wcm.RecordType([ + ['doc', $wcm.wstring], + ['before', Position], + ['name', NameInfo], + ['deprecated', $wcm.bool], + ['kind', MemberKind], + ['after', Position], + ]); + export const ClassInfo = new $wcm.RecordType([ + ['doc', $wcm.wstring], + ['name', NameInfo], + ['extends', new $wcm.ListType($wcm.wstring)], + ['deprecated', $wcm.bool], + ['members', new $wcm.ListType(MemberInfo)], + ]); + export const MacroInfo = new $wcm.RecordType([ + ['name', NameInfo], + ['args', new $wcm.ListType($wcm.wstring)], + ]); + export const SubroutineInfo = new $wcm.RecordType([ + ['name', NameInfo], + ['args', new $wcm.ListType($wcm.wstring)], + ]); + export const RoutineInfo = new $wcm.VariantType([['INC', new $wcm.ListType(MacroInfo)], ['INT', new $wcm.ListType(SubroutineInfo)], ['MAC', new $wcm.ListType(SubroutineInfo)]], AnalyzerInterface.RoutineInfo._ctor); + export const ParseErr = new $wcm.RecordType([ + ['range', Range], + ['message', $wcm.wstring], + ]); + export const AnalysisErr = new $wcm.VariantType([['P', ParseErr]], AnalyzerInterface.AnalysisErr._ctor); + export const Completion = new $wcm.RecordType([ + ['classname', new $wcm.OptionType($wcm.u8)], + ['variable', new $wcm.OptionType($wcm.u8)], + ['command', new $wcm.OptionType($wcm.u8)], + ]); + export const Diagnostic = new $wcm.RecordType([ + ['message', $wcm.wstring], + ['range', Range], + ['relatedInformation', new $wcm.ListType(DiagnosticRelatedInformation)], + ]); + export const Workspace = new $wcm.ResourceType('workspace', 'iris:objectscript-analyzer/analyzer-interface/workspace'); + export const Workspace_Handle = new $wcm.ResourceHandleType('workspace'); + Workspace.addDestructor('$drop', new $wcm.DestructorType('[resource-drop]workspace', [['inst', Workspace]])); + Workspace.addConstructor('constructor', new $wcm.ConstructorType('[constructor]workspace', [], new $wcm.OwnType(Workspace_Handle))); + Workspace.addMethod('insertCls', new $wcm.MethodType('[method]workspace.insert-cls', [ + ['uri', $wcm.wstring], + ['src', $wcm.wstring], + ], new $wcm.ResultType(ClassInfo, AnalysisErr, AnalyzerInterface.AnalysisErr.Error_))); + Workspace.addMethod('insertRtn', new $wcm.MethodType('[method]workspace.insert-rtn', [ + ['uri', $wcm.wstring], + ['src', $wcm.wstring], + ], new $wcm.ResultType(RoutineInfo, AnalysisErr, AnalyzerInterface.AnalysisErr.Error_))); + Workspace.addMethod('remove', new $wcm.MethodType('[method]workspace.remove', [ + ['uri', $wcm.wstring], + ], undefined)); + Workspace.addMethod('check', new $wcm.MethodType('[method]workspace.check', [ + ['uri', $wcm.wstring], + ], new $wcm.ListType(Diagnostic))); + Workspace.addMethod('queryCls', new $wcm.MethodType('[method]workspace.query-cls', [ + ['query', $wcm.wstring], + ], new $wcm.ListType<[string, AnalyzerInterface.ClassInfo]>(new $wcm.TupleType<[string, AnalyzerInterface.ClassInfo]>([$wcm.wstring, ClassInfo])))); + Workspace.addMethod('queryMem', new $wcm.MethodType('[method]workspace.query-mem', [ + ['cls', $wcm.wstring], + ['query', $wcm.wstring], + ], new $wcm.ListType<[string, AnalyzerInterface.MemberInfo]>(new $wcm.TupleType<[string, AnalyzerInterface.MemberInfo]>([$wcm.wstring, MemberInfo])))); + export const completeClass = new $wcm.FunctionType('complete-class', [ + ['prefix', $wcm.wstring], + ], new $wcm.ResultType(Completion, AnalysisErr, AnalyzerInterface.AnalysisErr.Error_)); + export const completeMethod = new $wcm.FunctionType('complete-method', [ + ['prefix', $wcm.wstring], + ], new $wcm.ResultType(Completion, AnalysisErr, AnalyzerInterface.AnalysisErr.Error_)); +} +export namespace AnalyzerInterface._ { + export const id = 'iris:objectscript-analyzer/analyzer-interface' as const; + export const witName = 'analyzer-interface' as const; + export namespace Workspace { + export type WasmInterface = { + '[constructor]workspace': () => i32; + '[method]workspace.insert-cls': (self: i32, uri_ptr: i32, uri_len: i32, src_ptr: i32, src_len: i32, result: ptr>) => void; + '[method]workspace.insert-rtn': (self: i32, uri_ptr: i32, uri_len: i32, src_ptr: i32, src_len: i32, result: ptr>) => void; + '[method]workspace.remove': (self: i32, uri_ptr: i32, uri_len: i32) => void; + '[method]workspace.check': (self: i32, uri_ptr: i32, uri_len: i32, result: ptr) => void; + '[method]workspace.query-cls': (self: i32, query_ptr: i32, query_len: i32, result: ptr<[string, ClassInfo][]>) => void; + '[method]workspace.query-mem': (self: i32, cls_ptr: i32, cls_len: i32, query_ptr: i32, query_len: i32, result: ptr<[string, MemberInfo][]>) => void; + }; + export namespace imports { + export type WasmInterface = Workspace.WasmInterface & { '[resource-drop]workspace': (self: i32) => void }; + } + export namespace exports { + export type WasmInterface = Workspace.WasmInterface & { '[dtor]workspace': (self: i32) => void }; + } + } + export const types: Map = new Map([ + ['Position', $.Position], + ['Range', $.Range], + ['Location', $.Location], + ['DiagnosticRelatedInformation', $.DiagnosticRelatedInformation], + ['NameInfo', $.NameInfo], + ['ArgMode', $.ArgMode], + ['NormalArg', $.NormalArg], + ['VariadicArg', $.VariadicArg], + ['MethodInfo', $.MethodInfo], + ['ParameterInfo', $.ParameterInfo], + ['MemberKind', $.MemberKind], + ['MemberInfo', $.MemberInfo], + ['ClassInfo', $.ClassInfo], + ['MacroInfo', $.MacroInfo], + ['SubroutineInfo', $.SubroutineInfo], + ['RoutineInfo', $.RoutineInfo], + ['ParseErr', $.ParseErr], + ['AnalysisErr', $.AnalysisErr], + ['Completion', $.Completion], + ['Diagnostic', $.Diagnostic], + ['Workspace', $.Workspace] + ]); + export const functions: Map = new Map([ + ['completeClass', $.completeClass], + ['completeMethod', $.completeMethod] + ]); + export const resources: Map = new Map([ + ['Workspace', $.Workspace] + ]); + export type WasmInterface = { + 'complete-class': (prefix_ptr: i32, prefix_len: i32, result: ptr>) => void; + 'complete-method': (prefix_ptr: i32, prefix_len: i32, result: ptr>) => void; + }; + export namespace imports { + export type WasmInterface = _.WasmInterface & Workspace.imports.WasmInterface; + } + export namespace exports { + export type WasmInterface = _.WasmInterface & Workspace.exports.WasmInterface; + export namespace imports { + export type WasmInterface = { + '[resource-new]workspace': (rep: i32) => i32; + '[resource-rep]workspace': (handle: i32) => i32; + '[resource-drop]workspace': (handle: i32) => void; + }; + } + } +} +export namespace analyzer.$ { +} +export namespace analyzer._ { + type Completion = AnalyzerInterface.Completion; + type AnalysisErr = AnalyzerInterface.AnalysisErr; + type ClassInfo = AnalyzerInterface.ClassInfo; + type MemberInfo = AnalyzerInterface.MemberInfo; + type RoutineInfo = AnalyzerInterface.RoutineInfo; + type Diagnostic = AnalyzerInterface.Diagnostic; + export const id = 'iris:objectscript-analyzer/analyzer' as const; + export const witName = 'analyzer' as const; + export namespace imports { + export function create(service: analyzer.Imports, context: $wcm.WasmContext): Imports { + return $wcm.$imports.create(_, service, context); + } + export function loop(service: analyzer.Imports, context: $wcm.WasmContext): analyzer.Imports { + return $wcm.$imports.loop(_, service, context); + } + } + export type Imports = { + '[export]iris:objectscript-analyzer/analyzer-interface': AnalyzerInterface._.exports.imports.WasmInterface; + }; + export namespace exports { + export const interfaces: Map = new Map([ + ['AnalyzerInterface', AnalyzerInterface._] + ]); + export function bind(exports: Exports, context: $wcm.WasmContext): analyzer.Exports { + return $wcm.$exports.bind(_, exports, context); + } + } + export type Exports = { + 'iris:objectscript-analyzer/analyzer-interface#complete-class': (prefix_ptr: i32, prefix_len: i32, result: ptr>) => void; + 'iris:objectscript-analyzer/analyzer-interface#complete-method': (prefix_ptr: i32, prefix_len: i32, result: ptr>) => void; + 'iris:objectscript-analyzer/analyzer-interface#[constructor]workspace': () => i32; + 'iris:objectscript-analyzer/analyzer-interface#[method]workspace.insert-cls': (self: i32, uri_ptr: i32, uri_len: i32, src_ptr: i32, src_len: i32, result: ptr>) => void; + 'iris:objectscript-analyzer/analyzer-interface#[method]workspace.insert-rtn': (self: i32, uri_ptr: i32, uri_len: i32, src_ptr: i32, src_len: i32, result: ptr>) => void; + 'iris:objectscript-analyzer/analyzer-interface#[method]workspace.remove': (self: i32, uri_ptr: i32, uri_len: i32) => void; + 'iris:objectscript-analyzer/analyzer-interface#[method]workspace.check': (self: i32, uri_ptr: i32, uri_len: i32, result: ptr) => void; + 'iris:objectscript-analyzer/analyzer-interface#[method]workspace.query-cls': (self: i32, query_ptr: i32, query_len: i32, result: ptr<[string, ClassInfo][]>) => void; + 'iris:objectscript-analyzer/analyzer-interface#[method]workspace.query-mem': (self: i32, cls_ptr: i32, cls_len: i32, query_ptr: i32, query_len: i32, result: ptr<[string, MemberInfo][]>) => void; + }; + export function bind(service: analyzer.Imports, code: $wcm.Code, context?: $wcm.ComponentModelContext): Promise; + export function bind(service: analyzer.Imports.Promisified, code: $wcm.Code, port: $wcm.RAL.ConnectionPort, context?: $wcm.ComponentModelContext): Promise; + export function bind(service: analyzer.Imports | analyzer.Imports.Promisified, code: $wcm.Code, portOrContext?: $wcm.RAL.ConnectionPort | $wcm.ComponentModelContext, context?: $wcm.ComponentModelContext | undefined): Promise | Promise { + return $wcm.$main.bind(_, service, code, portOrContext, context); + } +} \ No newline at end of file diff --git a/server/src/analyzer/index.ts b/server/src/analyzer/index.ts new file mode 100644 index 0000000..fb53155 --- /dev/null +++ b/server/src/analyzer/index.ts @@ -0,0 +1,166 @@ +import * as fs from "fs"; +import * as path from "path"; +import { analyzer, AnalyzerInterface } from "./bind"; +import { Diagnostic } from "vscode-languageserver"; +import { connection } from '../utils/variables'; +import { URI } from 'vscode-uri'; + +const filename = path.resolve(__dirname, "../lib/analyzer.wasm"); + +async function loadAnalyzer() { + try { + const bits = fs.readFileSync(filename); + const module = await WebAssembly.compile(bits); + + const service: analyzer.Imports = {}; + const exports = await analyzer._.bind(service, module); + + return exports; + } catch (rawError) { + console.log(rawError); + throw rawError; + } +} + +export type MethodInfo = AnalyzerInterface.MethodInfo; +export type ParameterInfo = AnalyzerInterface.ParameterInfo; +export type MemberKind = AnalyzerInterface.MemberKind; +export type MemberInfo = AnalyzerInterface.MemberInfo; +export type ClassInfo = AnalyzerInterface.ClassInfo; +export type AnalysisErr = AnalyzerInterface.AnalysisErr; +export type NormalArg = AnalyzerInterface.NormalArg; +export type ArgMode = AnalyzerInterface.ArgMode; +export const ArgMode = AnalyzerInterface.ArgMode; + +const wasm = loadAnalyzer(); + +export type AnalyzeResult = ClassInfo | { error: Diagnostic[] }; + +const analyzedFolders = new Map(); + +export async function analyzeCls(filePath: string, src: string, folderURI?: string): Promise { + try { + const workspace = typeof folderURI === "string" ? await rootURIToAnalyzerWorkspace(folderURI) : await filePathToAnalyzerWorkspace(filePath); + if (!workspace) { + return { + error: [{ + message: "No workspace found", + range: { + start: { line: 0, character: 0 }, + end: { line: 0, character: 0 } + }, + }], + }; + } + return workspace.insertCls(filePath, src); + } catch (rawError) { + console.log(rawError); + return { error: [] } + } +} + +export async function completeMethod(src: string) { + try { + return (await wasm).analyzerInterface.completeMethod(src); + } catch (rawError) { + console.log(rawError); + return undefined; + } +} + +export async function completeClass(src: string) { + try { + return (await wasm).analyzerInterface.completeClass(src); + } catch (rawError) { + console.log(rawError); + return undefined; + } +} + +export async function check(fileFsPath: string): Promise { + try { + const workspace = await filePathToAnalyzerWorkspace(fileFsPath); + if (!workspace) { + return []; + } + return workspace.check(fileFsPath); + } catch (rawError) { + console.log(rawError); + return []; + } +} + +export async function filePathToAnalyzerWorkspace(filePath: string): Promise { + const folders = await connection.workspace.getWorkspaceFolders(); + const folder = folders?.find((folder) => { + const folderPath = URI.parse(folder.uri).fsPath; + const rel = path.relative(folderPath, filePath); + return !rel.startsWith("..") && !path.isAbsolute(rel); + }); + return ( + (folder && rootURIToAnalyzerWorkspace(folder.uri)) || + rootURIToAnalyzerWorkspace(filePath) + ); +} + +async function rootURIToAnalyzerWorkspace(folderURI: string): Promise { + let analyzedFolder = analyzedFolders.get(folderURI); + if (!analyzedFolder) { + analyzedFolder = new (await wasm).analyzerInterface.Workspace(); + analyzedFolders.set(folderURI, analyzedFolder); + } + return analyzedFolder +} + +export async function getAnalyzedClass(context: URI, name: string): Promise<[string, ClassInfo] | null> { + for await (const [uri, cls] of getAnalyzedClasses(context)) { + if (cls.name.content === name) { + return [uri, cls]; + } + } + return null; +} + +export async function* getAnalyzedClasses(context: URI): AsyncGenerator<[string, ClassInfo]> { + const workspace = await filePathToAnalyzerWorkspace(context.path); + const classes = workspace.queryCls(""); + for (const x of classes) { + yield x; + } +} + +export async function getAnalyzedClassMember( + context: URI, + clsName: string, + memName: string +): Promise<[string, MemberInfo] | null> { + for await (const [uri, mem] of getAnalyzedClassMembers(context, clsName, memName)) { + if (mem.name.content === memName) { + return [uri, mem]; + } + } + return null; +} + +export async function* getAnalyzedClassMembers( + context: URI, + clsName: string, + memQuery: string = "", + includeExtends: boolean = true +): AsyncGenerator<[string, MemberInfo]> { + const workspace = await filePathToAnalyzerWorkspace(context.fsPath); + for (const x of workspace.queryMem(clsName, memQuery)) { + yield x; + } + if (includeExtends) { + const result = await getAnalyzedClass(context, clsName); + if (result) { + const cls = result[1]; + for (const sup of cls.extends) { + yield* getAnalyzedClassMembers(context, sup, memQuery); + } + } + } +} + + diff --git a/server/src/providers/completion.ts b/server/src/providers/completion.ts index 52c1718..3587dd9 100644 --- a/server/src/providers/completion.ts +++ b/server/src/providers/completion.ts @@ -27,6 +27,7 @@ import { normalizeClassname, macroDefToDoc, showInternalForServer, + getAnalyzedDocument, } from "../utils/functions"; import { ServerSpec, @@ -36,7 +37,15 @@ import { compressedline, LanguageServerConfiguration, } from "../utils/types"; -import { documents, corePropertyParams, mppContinue } from "../utils/variables"; +import { + documents, + corePropertyParams, + mppContinue, +} from "../utils/variables"; +import { + getAnalyzedClassMembers, + getAnalyzedClasses +} from '../analyzer'; import * as ld from "../utils/languageDefinitions"; import structuredSystemVariables from "../documentation/structuredSystemVariables.json"; @@ -57,6 +66,8 @@ import storageKeywords from "../documentation/keywords/Storage.json"; import triggerKeywords from "../documentation/keywords/Trigger.json"; import xdataKeywords from "../documentation/keywords/XData.json"; import { TextDocument } from "vscode-languageserver-textdocument"; +import { localInfoPrefix } from "./hover"; +import { completeClass, completeMethod } from "../analyzer"; /** * ServerSpec's mapped to the XML assist schema cache for that server. @@ -564,68 +575,86 @@ class SchemaCache { * @param server The server that doc is associated with. * @param line The line of doc that we're in. */ -async function completionFullClassName( +async function* completionFullClassName( doc: TextDocument, parsed: compressedline[], server: ServerSpec, line: number, settings: LanguageServerConfiguration, -): Promise { - const result: CompletionItem[] = []; +): AsyncGenerator { + // Add locally available classes + const added = new Set(); + for await (const [uri, cls] of getAnalyzedClasses(URI.parse(doc.uri))) { + added.add(cls.name.content); + const item = makeClassCompletionItem( + [] /* I tried getImports() but it gives false imports */, + cls.name.content, + uri, + cls.deprecated, + ); + item.documentation = { + kind: MarkupKind.Markdown, + value: documaticHtmlToMarkdown(cls.doc), + }; + item.insertText = item.label; + item.label = localInfoPrefix + item.label; + yield item; + } // Get the list of imports for resolution const imports = await getImports(doc, parsed, line, server); - // Get all classes const querydata = { - query: `SELECT dcd.Name, dcd.Deprecated FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?) AS sod, %Dictionary.ClassDefinition AS dcd WHERE sod.Name = dcd.Name||'.cls'${ - !settings.completion.showDeprecated ? " AND dcd.Deprecated = 0" : "" - }`, + query: `SELECT dcd.Name, dcd.Deprecated FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?) AS sod, %Dictionary.ClassDefinition AS dcd WHERE sod.Name = dcd.Name||'.cls'${!settings.completion.showDeprecated ? " AND dcd.Deprecated = 0" : "" + }`, parameters: ["*.cls", 1, 1, 1, 1, 0, settings.completion.showGenerated ? 1 : 0], }; const respdata = await makeRESTRequest("POST", 1, "/action/query", server, querydata); if (respdata !== undefined && respdata.data.result.content.length > 0) { for (const clsobj of respdata.data.result.content) { - let displayname: string = clsobj.Name; - let compItem: CompletionItem; - if (imports.length > 0) { - // Resolve import - let sortText: string; - for (const imp of imports) { - if (displayname.indexOf(imp) === 0 && displayname.slice(imp.length + 1).indexOf(".") === -1) { - displayname = displayname.slice(imp.length + 1); - sortText = "%%%" + displayname; - break; - } - } - if (displayname.startsWith("%Library.")) { - // Use short form for %Library classes - displayname = "%" + displayname.slice(9); - } - compItem = { - label: displayname, - kind: CompletionItemKind.Class, - data: ["class", clsobj.Name, doc.uri], - sortText, - }; - } else { - if (displayname.startsWith("%Library.")) { - // Use short form for %Library classes - displayname = "%" + displayname.slice(9); - } - compItem = { - label: displayname, - kind: CompletionItemKind.Class, - data: ["class", clsobj.Name, doc.uri], - }; - } - if (clsobj.Deprecated) { - compItem.tags = [CompletionItemTag.Deprecated]; + const compItem: CompletionItem = makeClassCompletionItem(imports, clsobj.Name, doc.uri, clsobj.Deprecated); + if (added.has(clsobj.Name)) continue; + yield compItem; + } + } + + return; +} + +function makeClassCompletionItem(imports: string[], name: string, uri: TextDocument["uri"], deprecated: boolean) { + let displayName: string = name; + let sortText: string | null = null; + if (imports.length > 0) { + // Resolve import + for (const imp of imports) { + if (displayName.indexOf(imp) === 0 && displayName.slice(imp.length + 1).indexOf(".") === -1) { + displayName = displayName.slice(imp.length + 1); + sortText = "%%%" + displayName; + break; } - result.push(compItem); + } + if (displayName.startsWith("%Library.")) { + // Use short form for %Library classes + displayName = "%" + displayName.slice(9); + } + } else { + if (displayName.startsWith("%Library.")) { + // Use short form for %Library classes + displayName = "%" + displayName.slice(9); } } - return result; + const compItem: CompletionItem = { + label: displayName, + kind: CompletionItemKind.Class, + data: ["class", name, uri], + }; + if (sortText !== null) { + compItem.sortText = sortText; + } + if (deprecated) { + compItem.tags = [CompletionItemTag.Deprecated]; + } + return compItem; } /** @@ -638,9 +667,8 @@ async function completionPackage(server: ServerSpec, settings: LanguageServerCon // Get all the packages const querydata = { - query: `SELECT DISTINCT $PIECE(dcd.Name,'.',1,$LENGTH(dcd.Name,'.')-1) AS Package FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?) AS sod, %Dictionary.ClassDefinition AS dcd WHERE sod.Name = dcd.Name||'.cls'${ - !settings.completion.showDeprecated ? " AND dcd.Deprecated = 0" : "" - }`, + query: `SELECT DISTINCT $PIECE(dcd.Name,'.',1,$LENGTH(dcd.Name,'.')-1) AS Package FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?) AS sod, %Dictionary.ClassDefinition AS dcd WHERE sod.Name = dcd.Name||'.cls'${!settings.completion.showDeprecated ? " AND dcd.Deprecated = 0" : "" + }`, parameters: ["*.cls", 1, 1, 1, 1, 0, settings.completion.showGenerated ? 1 : 0], }; const respdata = await makeRESTRequest("POST", 1, "/action/query", server, querydata); @@ -756,13 +784,13 @@ async function globalsOrRoutines( server, isRoutine ? { - query: `SELECT DISTINCT $PIECE(Name,'.',1,$LENGTH(Name,'.')-1) AS Name FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,1,1,1,0,'NOT (Name %PATTERN ''.E1"."0.1"G"1N1".obj"'' AND $LENGTH(Name,''.'') > 3)')`, - parameters: [`${prefix.length ? `${prefix.slice(0, -1)}/` : ""}*.mac,*.int,*.obj`], - } + query: `SELECT DISTINCT $PIECE(Name,'.',1,$LENGTH(Name,'.')-1) AS Name FROM %Library.RoutineMgr_StudioOpenDialog(?,1,1,1,1,1,0,'NOT (Name %PATTERN ''.E1"."0.1"G"1N1".obj"'' AND $LENGTH(Name,''.'') > 3)')`, + parameters: [`${prefix.length ? `${prefix.slice(0, -1)}/` : ""}*.mac,*.int,*.obj`], + } : { - query: "SELECT Name FROM %SYS.GlobalQuery_NameSpaceList(,?,?,,,1,0)", - parameters: [`${prefix}*`, (await showInternalForServer(server)) ? 1 : 0], - }, + query: "SELECT Name FROM %SYS.GlobalQuery_NameSpaceList(,?,?,,,1,0)", + parameters: [`${prefix}*`, (await showInternalForServer(server)) ? 1 : 0], + }, ); if (Array.isArray(respdata?.data?.result?.content) && respdata.data.result.content.length > 0) { return respdata.data.result.content.map((item: { Name: string }) => { @@ -793,6 +821,7 @@ export async function onCompletion(params: CompletionParams): Promise 0) { - // We got data back - - for (const clsobj of respdata.data.result.content) { - result.push({ - label: clsobj.Name.slice(filter.length), - kind: CompletionItemKind.Class, - data: ["class", clsobj.Name, doc.uri], - tags: clsobj.Deprecated ? [CompletionItemTag.Deprecated] : undefined, - }); - } + const filter = prevtokentype === "system" ? "%SYSTEM." : prevtokentext; + for await (const item of completionPartialClassName(filter, settings, server, doc)) { + result.push(item); } } else if (globalOrRoutineMatch && triggerlang == ld.cos_langindex) { // This might be a routine or global @@ -1304,21 +1352,41 @@ export async function onCompletion(params: CompletionParams): Promise(); + for await (const [_uri, mem] of getAnalyzedClassMembers(URI.parse(params.textDocument.uri), membercontext.baseclass)) { + if (mem.kind.tag === "parameter") { + const name = quoteUDLIdentifier(mem.name.content, 1); + added.add(name); + result.push({ + label: "#" + name, + kind: CompletionItemKind.Constant, + data: "member", + documentation: { + kind: MarkupKind.Markdown, + value: documaticHtmlToMarkdown(mem.doc), + }, + sortText: name, + insertText: name, + detail: mem.kind.value.t, + tags: mem.deprecated ? [CompletionItemTag.Deprecated] : [], + }); + } + } // Query the server to get the names and descriptions of all parameters const data: QueryData = { - query: `SELECT Name, Description, Origin, Type, Deprecated FROM %Dictionary.CompiledParameter WHERE Parent = ?${ - membercontext.context == "instance" - ? " AND (parent->ClassType IS NULL OR parent->ClassType != 'datatype')" - : "" - }${internalStr}${deprecatedStr}`, + query: `SELECT Name, Description, Origin, Type, Deprecated FROM %Dictionary.CompiledParameter WHERE Parent = ?${membercontext.context == "instance" + ? " AND (parent->ClassType IS NULL OR parent->ClassType != 'datatype')" + : "" + }${internalStr}${deprecatedStr}`, parameters: [membercontext.baseclass], }; const respdata = await makeRESTRequest("POST", 1, "/action/query", server, data); if (Array.isArray(respdata?.data?.result?.content) && respdata.data.result.content.length > 0) { // We got data back - for (const memobj of respdata.data.result.content) { const quotedname = quoteUDLIdentifier(memobj.Name, 1); + if (added.has(quotedname)) continue; const item: CompletionItem = { label: "#" + quotedname, kind: CompletionItemKind.Constant, @@ -1353,6 +1421,43 @@ export async function onCompletion(params: CompletionParams): Promise(); + for await (const [_uri, mem] of getAnalyzedClassMembers(URI.parse(params.textDocument.uri), membercontext.baseclass)) { + const name = quoteUDLIdentifier(mem.name.content, 1); + added.add(name); + const item: CompletionItem = { + label: name, + kind: CompletionItemKind.Property, + data: "member", + documentation: { + kind: MarkupKind.Markdown, + value: documaticHtmlToMarkdown(mem.doc), + }, + sortText: name, + insertText: name, + }; + if (mem.kind.tag === "classMethod" || mem.kind.tag === "method" || mem.kind.tag === "clientMethod") { + item.kind = CompletionItemKind.Method; + if (mem.kind.value.normal.length == 0 && !mem.kind.value.variadic) { + item.insertText += "()"; + } else { + item.textEdit = TextEdit.insert(params.position, name.replace(/\$/g, "//$") + "($0)"); + item.insertTextFormat = InsertTextFormat.Snippet; + item.command = { + title: "Show SignatureHelp", + command: "editor.action.triggerParameterHints", + }; + } + } else if (mem.kind.tag === "parameter") { + item.kind = CompletionItemKind.Constant; + item.insertText = "#" + name; + } + if (mem.deprecated) { + item.tags = [CompletionItemTag.Deprecated]; + } + result.push(item); + } + // Query the server to get the metadata of all appropriate class members const data: QueryData = { query: "", @@ -1421,6 +1526,7 @@ export async function onCompletion(params: CompletionParams): Promise { + filter += filter.endsWith(".") ? "" : "."; + const added = new Set(); + for await (const [_uri, cls] of getAnalyzedClasses(URI.parse(doc.uri))) { + if (!cls.name.content.startsWith(filter)) { + continue; + } + added.add(cls.name.content); + yield { + label: cls.name.content.slice(filter.length), + kind: CompletionItemKind.Class, + data: ["class", cls.name.content.slice(filter.length), doc.uri], + tags: cls.deprecated ? [CompletionItemTag.Deprecated] : undefined, + documentation: { + kind: MarkupKind.Markdown, + value: documaticHtmlToMarkdown(cls.doc), + }, + }; + } + + // Get all classes that match the filter + const querydata = { + query: `SELECT dcd.Name, dcd.Deprecated FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?,?) AS sod, %Dictionary.ClassDefinition AS dcd WHERE sod.Name = dcd.Name||'.cls'${!settings.completion.showDeprecated ? " AND dcd.Deprecated = 0" : ""}`, + parameters: ["*.cls", 1, 1, 1, 1, 0, settings.completion.showGenerated ? 1 : 0, `Name %STARTSWITH '${filter}'`], + }; + const respdata = await makeRESTRequest("POST", 1, "/action/query", server, querydata); + if (respdata !== undefined && respdata.data.result.content.length > 0) { + // We got data back + for (const clsobj of respdata.data.result.content) { + if (added.has(clsobj.Name)) continue; + yield { + label: clsobj.Name.slice(filter.length), + kind: CompletionItemKind.Class, + data: ["class", clsobj.Name, doc.uri], + tags: clsobj.Deprecated ? [CompletionItemTag.Deprecated] : undefined, + }; + } + } +} + export async function onCompletionResolve(item: CompletionItem): Promise { + if (item.documentation) return item; if (Array.isArray(item.data) && item.data[0] === "class") { // Get the description for this class from the server const server: ServerSpec = await getServerSpec(item.data[2]); @@ -2463,3 +2614,38 @@ export async function onCompletionResolve(item: CompletionItem): Promise { + for (const command of commands) { + if (matchCommand(prefix, command)) { + yield { + label: command.label, + kind: CompletionItemKind.Snippet, + insertText: command.insertText, + documentation: command.documentation.join("\n"), + }; + } + } +} + +function matchCommand(prefix: string, command: (typeof commands)[number]): boolean { + if (command.insertText?.toLowerCase().startsWith(prefix.toLowerCase())) { + return true; + } + for (const alias of command.alias) { + if (alias.toLowerCase().startsWith(prefix.toLowerCase())) { + return true; + } + } + if (command.label.toLowerCase().startsWith(prefix.toLowerCase())) { + return true; + } + return false; +} diff --git a/server/src/providers/definition.ts b/server/src/providers/definition.ts index 56703c5..493ee29 100644 --- a/server/src/providers/definition.ts +++ b/server/src/providers/definition.ts @@ -17,10 +17,21 @@ import { isClassMember, memberRegex, urlMapAttribute, + fullRange, } from "../utils/functions"; import { ServerSpec, QueryData, compressedline } from "../utils/types"; -import { documents, corePropertyParams, classMemberTypes, mppContinue } from "../utils/variables"; +import { + documents, + corePropertyParams, + classMemberTypes, + mppContinue, +} from "../utils/variables"; +import { + getAnalyzedClass, + getAnalyzedClassMember +} from '../analyzer'; import * as ld from "../utils/languageDefinitions"; +import { URI } from 'vscode-uri'; /** * The maximum number of lines to include in the `targetRange` property @@ -28,6 +39,34 @@ import * as ld from "../utils/languageDefinitions"; */ const definitionTargetRangeMaxLines: number = 10; +async function lookupClassMember(context: URI, clsName: string, memName: string, originSelectionRange: Range): Promise { + const uri_mem = await getAnalyzedClassMember(context, clsName, memName); + if (!uri_mem) { + return null; + } + const [targetUri, memInfo] = uri_mem; + const targetRange = Range.create( + Number(memInfo.before.line), + Number(memInfo.before.character), + Number(memInfo.after.line), + Number(memInfo.after.character), + ); // the member definition + const targetSelectionRange = Range.create( + Number(memInfo.name.before.line), + Number(memInfo.name.before.character), + Number(memInfo.name.after.line), + Number(memInfo.name.after.character), + ); // the member name + return [ + { + targetUri, + targetRange, + originSelectionRange, + targetSelectionRange, + }, + ]; +} + /** Return a `LocationLink` for class member `memberName` in class `cls` */ async function classMemberLocationLink( uri: string, @@ -37,6 +76,11 @@ async function classMemberLocationLink( memberRange: Range, server: ServerSpec, ): Promise { + const localResult = lookupClassMember(URI.parse(uri), cls, memberName, memberRange); + if (localResult) { + return localResult; + } + const targetrange = Range.create(0, 0, 0, 0); let targetselrange = Range.create(0, 0, 0, 0); const newuri = await createDefinitionUri(uri, cls, ".cls"); @@ -108,6 +152,25 @@ async function classLocationLink( range: Range, server: ServerSpec, ): Promise { + const uri_cls = await getAnalyzedClass(URI.parse(uri), cls); + if (uri_cls) { + const [targetUri, clsInfo] = uri_cls; + const targetRange = fullRange; + const targetSelectionRange = Range.create( + Number(clsInfo.name.before.line), + Number(clsInfo.name.before.character), + Number(clsInfo.name.after.line), + Number(clsInfo.name.after.character), + ); // the class name + return [ + { + targetUri, + targetRange, + originSelectionRange: range, + targetSelectionRange, + }, + ]; + } // Get the uri of the target class const newuri = await createDefinitionUri(uri, cls, ".cls"); if (newuri != "") { @@ -313,7 +376,7 @@ export async function onDefinition(params: TextDocumentPositionParams) { parsed[macrodefline][parsed[macrodefline].length - 1].p, macrodefline, parsed[macrodefline][parsed[macrodefline].length - 1].p + - parsed[macrodefline][parsed[macrodefline].length - 1].c, + parsed[macrodefline][parsed[macrodefline].length - 1].c, ), ), ) @@ -452,6 +515,11 @@ export async function onDefinition(params: TextDocumentPositionParams) { return null; } + const localResult = lookupClassMember(URI.parse(params.textDocument.uri), membercontext.baseclass, unquotedname, memberrange); + if (localResult) { + return localResult; + } + let memberKeywords = parsed[params.position.line][i].s == ld.cos_prop_attrindex ? "Parameter" @@ -1174,7 +1242,7 @@ export async function onDefinition(params: TextDocumentPositionParams) { parsed[ln][0].l == ld.cls_langindex && parsed[ln][0].s == ld.cls_keyword_attrindex && doc.getText(Range.create(ln, parsed[ln][0].p, ln, parsed[ln][0].p + parsed[ln][0].c)).toLowerCase() == - "class" + "class" ) { // This is the class definition line let seenExtends = false, diff --git a/server/src/providers/diagnostic.ts b/server/src/providers/diagnostic.ts index f599bd1..7ff85b2 100644 --- a/server/src/providers/diagnostic.ts +++ b/server/src/providers/diagnostic.ts @@ -7,6 +7,8 @@ import { DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportKind, + WorkspaceDiagnosticReport, + WorkspaceDocumentDiagnosticReport, } from "vscode-languageserver"; import { @@ -19,12 +21,15 @@ import { normalizeClassname, quoteUDLIdentifier, isClassMember, + getAnalyzedDocument, } from "../utils/functions"; -import { zutilFunctions, lexerLanguages, documents } from "../utils/variables"; +import { zutilFunctions, lexerLanguages, documents, analyzedDocuments } from "../utils/variables"; import { ServerSpec, StudioOpenDialogFile, QueryData } from "../utils/types"; import * as ld from "../utils/languageDefinitions"; import parameterTypes from "../documentation/parameterTypes.json"; import sqlReservedWords from "../documentation/sqlReservedWords.json"; +import * as analyzer from "../analyzer"; +import { URI } from 'vscode-uri'; /** * Helper method that appends `range` to value of `key` in `map` @@ -59,11 +64,20 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise { return !(settings.diagnostics.suppressSyntaxErrors).includes( @@ -165,7 +179,7 @@ export async function onDiagnostics(params: DocumentDiagnosticParams): Promise { + const items: WorkspaceDocumentDiagnosticReport[] = []; + const uris = [...analyzedDocuments.keys()]; + for (const uri of uris) { + const res = await getAnalyzedDocument(uri); + if ("error" in res) { + items.push({ + kind: "full", + uri, + version: null, + items: res.error, + }); + } + } + return { items }; +} diff --git a/server/src/providers/documentSymbol.ts b/server/src/providers/documentSymbol.ts index 0c5f921..710d8b4 100644 --- a/server/src/providers/documentSymbol.ts +++ b/server/src/providers/documentSymbol.ts @@ -7,10 +7,20 @@ import { SymbolTag, } from "vscode-languageserver/node"; import { TextDocument } from "vscode-languageserver-textdocument"; -import { findFullRange, getParsedDocument, isClassMember, labelIsProcedureBlock, prevToken } from "../utils/functions"; +import { + findFullRange, + fullRange, + getAnalyzedDocument, + getParsedDocument, + isClassMember, + labelIsProcedureBlock, + prevToken, +} from "../utils/functions"; import { documents, mppContinue } from "../utils/variables"; import * as ld from "../utils/languageDefinitions"; import { compressedline } from "../utils/types"; +import { memberKindToSymbolKind } from "./workspaceSymbol"; +import { localInfoPrefix } from "./hover"; /** Loop through the class from this line until the next class member or the end of the class */ function processMember( @@ -64,7 +74,7 @@ function processMember( return { deprecated, lastNonEmpty }; } -export async function onDocumentSymbol(params: DocumentSymbolParams) { +export async function onDocumentSymbol(params: DocumentSymbolParams): Promise { const doc = documents.get(params.textDocument.uri); if (doc === undefined) { return null; @@ -76,6 +86,27 @@ export async function onDocumentSymbol(params: DocumentSymbolParams) { const result: DocumentSymbol[] = []; if (doc.languageId === "objectscript-class") { + // Try returning w/ analyzedClass + { + const cls = await getAnalyzedDocument(params.textDocument.uri); + if (cls !== undefined && !("error" in cls)) { + return [{ + name: cls.name.content, + kind: SymbolKind.Class, + range: fullRange, + selectionRange: Range.create(cls.name.before, cls.name.after), + tags: cls.deprecated ? [SymbolTag.Deprecated] : [], + children: cls.members.map((mem) => ({ + name: mem.name.content, + kind: memberKindToSymbolKind(mem.kind.tag), + range: Range.create(mem.before, mem.after), + selectionRange: Range.create(mem.name.before, mem.name.after), + tags: cls.deprecated || mem.deprecated ? [SymbolTag.Deprecated] : [], + })), + }]; + } + } + // Loop through the file and look for the class definition and class members const cls: DocumentSymbol = { @@ -117,7 +148,7 @@ export async function onDocumentSymbol(params: DocumentSymbolParams) { 0, lastnonempty, parsed[lastnonempty][parsed[lastnonempty].length - 1].p + - parsed[lastnonempty][parsed[lastnonempty].length - 1].c, + parsed[lastnonempty][parsed[lastnonempty].length - 1].c, ); // Determine if this class is Deprecated @@ -181,7 +212,7 @@ export async function onDocumentSymbol(params: DocumentSymbolParams) { 0, lastNonEmpty, parsed[lastNonEmpty][parsed[lastNonEmpty].length - 1].p + - parsed[lastNonEmpty][parsed[lastNonEmpty].length - 1].c, + parsed[lastNonEmpty][parsed[lastNonEmpty].length - 1].c, ), selectionRange: Range.create(line, parsed[line][1].p, line, parsed[line][1].p + parsed[line][1].c), tags: deprecated ? [SymbolTag.Deprecated] : undefined, @@ -416,7 +447,7 @@ export async function onDocumentSymbol(params: DocumentSymbolParams) { parsed[line][tkn + 1].l == ld.html_langindex && parsed[line][tkn + 1].s == ld.html_tag_attrindex && doc.getText(Range.create(line, parsed[line][tkn].p, line, parsed[line][tkn].p + parsed[line][tkn].c)) === - "<" && + "<" && doc .getText( Range.create(line, parsed[line][tkn + 1].p, line, parsed[line][tkn + 1].p + parsed[line][tkn + 1].c), diff --git a/server/src/providers/hover.ts b/server/src/providers/hover.ts index f054f3b..5f095dc 100644 --- a/server/src/providers/hover.ts +++ b/server/src/providers/hover.ts @@ -21,7 +21,15 @@ import { urlMapAttribute, } from "../utils/functions"; import { ServerSpec, QueryData, CommandDoc, KeywordDoc } from "../utils/types"; -import { documents, corePropertyParams, mppContinue } from "../utils/variables"; +import { + documents, + corePropertyParams, + mppContinue, +} from "../utils/variables"; +import { + getAnalyzedClass, + getAnalyzedClassMember +} from '../analyzer'; import * as ld from "../utils/languageDefinitions"; import commands from "../documentation/commands.json"; @@ -43,6 +51,8 @@ import queryKeywords from "../documentation/keywords/Query.json"; import storageKeywords from "../documentation/keywords/Storage.json"; import triggerKeywords from "../documentation/keywords/Trigger.json"; import xdataKeywords from "../documentation/keywords/XData.json"; +import { MemberInfo, NormalArg, ArgMode } from "../analyzer"; +import { URI } from 'vscode-uri'; function documaticLink(server: ServerSpec, cls: string): string { return `[${cls}](${server.scheme}://${server.host}:${server.port}${server.pathPrefix}/csp/documatic/%25CSP.Documatic.cls?LIBRARY=${encodeURIComponent( @@ -54,6 +64,7 @@ function markupValue(header: string, body?: string): string { return body?.trim().length ? [header, "***", body].join("\n") : header; } +export const localInfoPrefix = `[📁] `; export async function onHover(params: TextDocumentPositionParams): Promise { const doc = documents.get(params.textDocument.uri); if (doc === undefined) { @@ -114,6 +125,20 @@ export async function onHover(params: TextDocumentPositionParams): Promise 0) { // We got data back - const header = `(**${normalizedcls}**) **${param}**${ - respdata.data.result.content[0].Type != "" ? ` As **${respdata.data.result.content[0].Type}**` : "" - }`; + const header = `(**${normalizedcls}**) **${param}**${respdata.data.result.content[0].Type != "" ? ` As **${respdata.data.result.content[0].Type}**` : "" + }`; return { contents: { kind: MarkupKind.Markdown, @@ -1402,3 +1439,46 @@ export async function onHover(params: TextDocumentPositionParams): Promise**${memberInfo.name.content}**`; + const { kind } = memberInfo; + if (kind.tag === "classMethod" || kind.tag === "clientMethod" || kind.tag === "method") { + const { normal, variadic, t } = kind.value; + const argList = normal.map(prettifyNormalArg).concat(variadic ? [] : []).join(", "); + content += `(${argList})`; + if (t) { + content += ` As ${t}`; + } + } else if (kind.tag === "property" || kind.tag === "relationship") { + if (kind.value) { + content += ` As ${kind.value}`; + } + } else if (kind.tag === "parameter") { + const value = kind.value; + if (value.t) { + content += ` As ${value.t}`; + } + if (value.v) { + content += ` = ${value.v}`; + } + } + return content; +} + +function hoverBodyFromMemberInfo(memberInfo: MemberInfo): string { + let content = ""; + content += memberInfo.doc; + return documaticHtmlToMarkdown(content); +} + +export const prettifyNormalArg = (arg: NormalArg): string => { + let string = ""; + if (arg.mode != ArgMode.default) { + string += "&"; + } + string += arg.name; + if (arg.t) { + string += ` As ${arg.t}`; + } + return string; +}; diff --git a/server/src/providers/signatureHelp.ts b/server/src/providers/signatureHelp.ts index 6670418..9677995 100644 --- a/server/src/providers/signatureHelp.ts +++ b/server/src/providers/signatureHelp.ts @@ -24,7 +24,10 @@ import { } from "../utils/functions"; import { ServerSpec, SignatureHelpDocCache, SignatureHelpMacroContext } from "../utils/types"; import { documents } from "../utils/variables"; +import { getAnalyzedClassMember } from '../analyzer'; import * as ld from "../utils/languageDefinitions"; +import { prettifyNormalArg } from "./hover"; +import { URI } from 'vscode-uri'; /** * Cache of the macro context info required to do a macro expansion when the selected parameter changes. @@ -198,7 +201,7 @@ export async function onSignatureHelp(params: SignatureHelpParams): Promise 0) { // We got data back @@ -610,19 +628,38 @@ export async function onSignatureHelp(params: SignatureHelpParams): Promise 0) { // We got data back @@ -737,3 +774,37 @@ export async function onSignatureHelp(params: SignatureHelpParams): Promise { + const uri_mem = (await getAnalyzedClassMember(context, clsName, memName)) ?? (memName != "%New" ? null : await getAnalyzedClassMember(context, clsName, "%OnNew")); + if (!uri_mem) { + return null; + } + const [_uri, mem] = uri_mem; + if (mem.kind.tag === "method" || mem.kind.tag === "classMethod" || mem.kind.tag === "clientMethod") { + const method = mem.kind.value; + const out = ["%Open", "%OpenId"].includes(memName) ? clsName : method.t; + const sig: SignatureInformation = { + label: "(" + method.normal.map(prettifyNormalArg).join(", ") + ")" + (out ? " As " + out : ""), + parameters: method.normal.map( + (arg): ParameterInformation => ({ + label: arg.name, + }), + ), + }; + if (showingDoc) { + signatureHelpDocumentationCache = { + type: "method", + doc: { + kind: MarkupKind.Markdown, + value: documaticHtmlToMarkdown(mem.doc), + }, + }; + sig.documentation = signatureHelpDocumentationCache.doc; + } + return { + signatures: [sig], + activeSignature: 0, + }; + } +} diff --git a/server/src/providers/workspaceSymbol.ts b/server/src/providers/workspaceSymbol.ts new file mode 100644 index 0000000..40e6cb3 --- /dev/null +++ b/server/src/providers/workspaceSymbol.ts @@ -0,0 +1,66 @@ +import { WorkspaceSymbolParams, WorkspaceSymbol, SymbolKind, SymbolTag, Range } from "vscode-languageserver"; +import { MemberInfo } from "../analyzer"; +import { connection } from "../utils/variables"; +import { getAnalyzedClasses } from '../analyzer'; +import { localInfoPrefix } from "./hover"; +import { URI } from 'vscode-uri'; + +export const onWorkspaceSymbol = async (params: WorkspaceSymbolParams): Promise => { + const output: WorkspaceSymbol[] = []; + const query = params.query.toLowerCase(); + for (const folder of await connection.workspace.getWorkspaceFolders()) { + for await (const [uri, cls] of getAnalyzedClasses(URI.parse(folder.uri))) { + const clsMatch = cls.name.content.toLowerCase().startsWith(query); + if (clsMatch) { + output.push({ + location: { uri, range: Range.create(cls.name.before, cls.name.after) }, + name: localInfoPrefix + cls.name.content, + kind: SymbolKind.Class, + tags: cls.deprecated ? [SymbolTag.Deprecated] : [], + }); + } + for (const mem of cls.members) { + const kind = memberKindToSymbolKind(mem.kind.tag); + if (kind !== null && (clsMatch || mem.name.content.toLowerCase().startsWith(query))) { + output.push({ + location: { uri, range: Range.create(mem.name.before, mem.name.after) }, + name: localInfoPrefix + mem.name.content, + kind, + tags: cls.deprecated || mem.deprecated ? [SymbolTag.Deprecated] : [], + }); + } + } + } + } + return output; +}; + +export function memberKindToSymbolKind(kind: MemberInfo["kind"]["tag"]): SymbolKind | null { + switch (kind) { + case "method": + case "classMethod": + case "clientMethod": + return SymbolKind.Method; + case "query": + return SymbolKind.Function; + case "trigger": + return SymbolKind.Event; + case "parameter": + return SymbolKind.Constant; + case "index": + return SymbolKind.Array; + case "foreignKey": + return SymbolKind.Key; + case "xData": + return SymbolKind.Struct; + case "storage": + return SymbolKind.Object; + case "projection": + return SymbolKind.Interface; + case "property": + case "relationship": + return SymbolKind.Property; + default: + throw new Error(`Unexpected keyword: ${kind}`); + } +} diff --git a/server/src/server.ts b/server/src/server.ts index 2e11a0e..d3970fb 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1,4 +1,9 @@ -import { DidChangeConfigurationNotification, TextDocumentSyncKind, CodeActionKind } from "vscode-languageserver/node"; +import { + DidChangeConfigurationNotification, + TextDocumentSyncKind, + CodeActionKind, + WorkspaceFolder, +} from "vscode-languageserver/node"; import { URI } from "vscode-uri"; import { onPrepare, onSubtypes, onSupertypes } from "./providers/typeHierarchy"; @@ -25,11 +30,12 @@ import { onHover } from "./providers/hover"; import { onCompletion, onCompletionResolve, schemaCaches } from "./providers/completion"; import { onSignatureHelp } from "./providers/signatureHelp"; import { onDocumentFormatting, onDocumentRangeFormatting } from "./providers/formatting"; -import { onDiagnostics } from "./providers/diagnostic"; +import { onDiagnostics, onWorkspaceDiagnostics } from "./providers/diagnostic"; import { onSemanticTokens, onSemanticTokensDelta } from "./providers/semanticTokens"; - +import { onWorkspaceSymbol } from "./providers/workspaceSymbol"; import { LanguageServerConfiguration, ServerSpec } from "./utils/types"; import { + analyzedDocuments, connection, documents, languageServerSettings, @@ -39,8 +45,10 @@ import { } from "./utils/variables"; import { parseDocument, getLegend } from "./parse/parse"; import { isolateEmbeddedLanguage, languageAtPosition } from "./providers/requestForwarding"; +import { analyzeCls } from "./analyzer"; -connection.onInitialize(() => { +connection.onInitialize((params) => { + analyzeWorkspaceFolders(params.workspaceFolders ?? []); return { capabilities: { textDocumentSync: TextDocumentSyncKind.Full, @@ -63,6 +71,7 @@ connection.onInitialize(() => { }, }, documentSymbolProvider: true, + workspaceSymbolProvider: true, foldingRangeProvider: true, renameProvider: { prepareProvider: true, @@ -79,7 +88,7 @@ connection.onInitialize(() => { typeHierarchyProvider: true, diagnosticProvider: { interFileDependencies: false, - workspaceDiagnostics: false, + workspaceDiagnostics: true, }, }, }; @@ -129,15 +138,16 @@ documents.onDidClose((e) => { documents.onDidChangeContent(async (change) => { // Clear the parsedDocuments value so we know to wait for an update elsewhere parsedDocuments.set(change.document.uri, undefined); + analyzedDocuments.set(change.document.uri, undefined); const path = URI.parse(change.document.uri).path; + const fsPath = URI.parse(change.document.uri).fsPath; + const fileText = change.document.getText(); parsedDocuments.set( change.document.uri, - parseDocument( - change.document.languageId, - path.slice(path.lastIndexOf(".") + 1).toLowerCase(), - change.document.getText(), - ).compressedlinearray, + parseDocument(change.document.languageId, path.slice(path.lastIndexOf(".") + 1).toLowerCase(), fileText) + .compressedlinearray, ); + analyzedDocuments.set(change.document.uri, await analyzeCls(fsPath, fileText)); }); connection.onDocumentFormatting(onDocumentFormatting); @@ -188,6 +198,8 @@ connection.onNotification("intersystems/server/connectionChange", () => { connection.onDocumentSymbol(onDocumentSymbol); +connection.onWorkspaceSymbol(onWorkspaceSymbol); + connection.onFoldingRanges(onFoldingRanges); connection.onPrepareRename(onPrepareRename); @@ -234,6 +246,27 @@ connection.onRequest("intersystems/embedded/isolateEmbeddedLanguage", isolateEmb connection.languages.diagnostics.on(onDiagnostics); +connection.languages.diagnostics.onWorkspace(onWorkspaceDiagnostics); + documents.listen(connection); connection.listen(); + +import * as fs from "fs"; +import * as path from "path"; +async function analyzeWorkspaceFolders(folders: WorkspaceFolder[]) { + for (const folder of folders) { + const folderURI = URI.parse(folder.uri); + if (folderURI.scheme !== "file") continue; + for (const file of fs.readdirSync(folderURI.fsPath, { recursive: true, withFileTypes: true })) { + if (!(file.isFile() && file.name.endsWith(".cls"))) { + continue; + } + const filePath = path.join(file.parentPath, file.name); + const fileURI = URI.file(filePath).toString(); + const fileString = fs.readFileSync(filePath, "utf-8"); + analyzedDocuments.set(fileURI, undefined); + analyzedDocuments.set(fileURI, await analyzeCls(filePath, fileString, folder.uri)); + } + } +} diff --git a/server/src/utils/functions.ts b/server/src/utils/functions.ts index a1f7e8c..a25f581 100644 --- a/server/src/utils/functions.ts +++ b/server/src/utils/functions.ts @@ -1,4 +1,4 @@ -import { MarkupContent, MarkupKind, Position, Range } from "vscode-languageserver"; +import { Diagnostic, MarkupContent, MarkupKind, Position, Range, uinteger } from "vscode-languageserver"; import { TextDocument } from "vscode-languageserver-textdocument"; import { URI } from "vscode-uri"; import { parse } from "node-html-parser"; @@ -22,6 +22,7 @@ import { languageServerSettings, documents, classMemberTypes, + analyzedDocuments, } from "./variables"; import * as ld from "./languageDefinitions"; @@ -32,6 +33,7 @@ import systemVariables from "../documentation/systemVariables.json"; // Initialize turndown and tune it for Documatic HTML import { default as TurndownService } from "turndown"; +import { ClassInfo } from "../analyzer"; const turndown = new TurndownService({ codeBlockStyle: "fenced", blankReplacement: (content, node: HTMLElement) => (node.nodeName == "SPAN" ? node.outerHTML : ""), @@ -3029,6 +3031,22 @@ export async function getParsedDocument(uri: string): Promise { + if (!analyzedDocuments.has(uri)) { + return undefined; + } + const start = Date.now(); + function wait(resolve: (value: ClassInfo | { error: Diagnostic[] }) => void) { + const result = analyzedDocuments.get(uri); + if (result != undefined || Date.now() - start >= 5000) { + resolve(result); + } else { + setTimeout(wait, 25, resolve); + } + } + return new Promise(wait); +} + /** * Check if label on `line` of `doc` is a procedure block. * @@ -3507,3 +3525,5 @@ export async function showInternalForServer(server: ServerSpec): Promise = new Map(); +/** + * TextDocument URI's mapped to the analyzed representation of the document. + */ +export const analyzedDocuments: Map = new Map(); + /** * Node IPC connection between the server and client. */