diff --git a/.vscode/launch.json b/.vscode/launch.json index 36d46cd..4bdd7fa 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -23,16 +23,6 @@ "args": [ "--extensionDevelopmentPath=${workspaceFolder}" ] - }, - { - "name": "Extension Tests", - "type": "extensionHost", - "request": "launch", - "preLaunchTask": "build", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/test/suite/index" - ] } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bb1562d..921d7de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@types/mocha": "^10.0.1", "@types/node": "^22.20.5", "@types/vscode": "^1.77.0", - "@vscode/test-electron": "^2.2.2", "eslint": "^10.14.0", "glob": "^14.0.3", "globals": "^17.13.0", @@ -361,23 +360,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@vscode/test-electron": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", - "integrity": "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "jszip": "^3.10.1", - "ora": "^8.1.0", - "semver": "^7.6.2" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -622,16 +604,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -849,35 +821,6 @@ "node": ">=6.0" } }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -907,13 +850,6 @@ "dev": true, "license": "MIT" }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -969,13 +905,6 @@ "dev": true, "license": "ISC" }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, "node_modules/enhanced-resolve": { "version": "5.26.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.26.0.tgz", @@ -1318,19 +1247,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-east-asian-width": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", - "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glob": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-14.0.3.tgz", @@ -1420,34 +1336,6 @@ "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", "dev": true }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1457,13 +1345,6 @@ "node": ">= 4" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true, - "license": "MIT" - }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", @@ -1494,13 +1375,6 @@ "node": ">=0.8.19" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/interpret": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", @@ -1548,19 +1422,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-path-inside": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", @@ -1598,13 +1459,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1671,19 +1525,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/jszip": { - "version": "3.10.2", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.2.tgz", - "integrity": "sha512-3l+rb15IOWtUhU0H5MFqES/T6Kh7abYwjosBey/vD6hDt8zoEffkSC5Ws5SGtgVw3gBx2NEbhTeSW1+kWkpyTQ==", - "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, "node_modules/keyv": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", @@ -1716,16 +1557,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1768,19 +1599,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimatch": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.3.tgz", @@ -1934,22 +1752,6 @@ "node": ">=18" } }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -1967,115 +1769,6 @@ "node": ">= 0.8.0" } }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz", - "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2116,13 +1809,6 @@ "node": ">=6" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2252,13 +1938,6 @@ "node": ">= 0.8.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2286,22 +1965,6 @@ "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", "dev": true }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/readdirp": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", @@ -2383,30 +2046,6 @@ "node": ">=8" } }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/schema-utils": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.8.1.tgz", @@ -2475,19 +2114,6 @@ "dev": true, "license": "MIT" }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/serialize-javascript": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.4.tgz", @@ -2497,13 +2123,6 @@ "node": ">=20.0.0" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true, - "license": "MIT" - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -2540,19 +2159,6 @@ "node": ">=8" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2574,76 +2180,6 @@ "source-map": "^0.6.0" } }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz", - "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/strip-json-comments": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", @@ -2790,13 +2326,6 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, "node_modules/watchpack": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.6.3.tgz", diff --git a/package.json b/package.json index a4761bb..bb6ff87 100644 --- a/package.json +++ b/package.json @@ -339,7 +339,7 @@ "package": "webpack --mode production --devtool hidden-source-map", "lint": "eslint .", "pretest": "npm run lint", - "test": "node ./test/runTest.js", + "test": "npm run test:unit", "package:test": "vsce package --pre-release --out ./package", "test:unit": "mocha --ui tdd test/unit" }, @@ -348,7 +348,6 @@ "@types/mocha": "^10.0.1", "@types/node": "^22.20.5", "@types/vscode": "^1.77.0", - "@vscode/test-electron": "^2.2.2", "eslint": "^10.14.0", "glob": "^14.0.3", "globals": "^17.13.0", diff --git a/test/runTest.js b/test/runTest.js deleted file mode 100644 index 570e697..0000000 --- a/test/runTest.js +++ /dev/null @@ -1,23 +0,0 @@ -const path = require('path'); - -const { runTests } = require('@vscode/test-electron'); - -async function main() { - try { - // The folder containing the Extension Manifest package.json - // Passed to `--extensionDevelopmentPath` - const extensionDevelopmentPath = path.resolve(__dirname, '../'); - - // The path to the extension test script - // Passed to --extensionTestsPath - const extensionTestsPath = path.resolve(__dirname, './suite/index'); - - // Download VS Code, unzip it and run the integration test - await runTests({ extensionDevelopmentPath, extensionTestsPath }); - } catch (err) { - console.error('Failed to run tests', err); - process.exit(1); - } -} - -main(); diff --git a/test/suite/extension.test.js b/test/suite/extension.test.js deleted file mode 100644 index 69ead83..0000000 --- a/test/suite/extension.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const assert = require('assert'); - -// You can import and use all API from the 'vscode' module -// as well as import your extension to test it -const vscode = require('vscode'); -// const myExtension = require('../extension'); - -suite('Extension Test Suite', () => { - vscode.window.showInformationMessage('Start all tests.'); - - test('Sample test', () => { - assert.strictEqual(-1, [1, 2, 3].indexOf(5)); - assert.strictEqual(-1, [1, 2, 3].indexOf(0)); - }); -}); diff --git a/test/suite/index.js b/test/suite/index.js deleted file mode 100644 index 0e14343..0000000 --- a/test/suite/index.js +++ /dev/null @@ -1,37 +0,0 @@ -const path = require('path'); -const Mocha = require('mocha'); -const { glob } = require('glob'); - -async function run() { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd', - color: true - }); - - const testsRoot = path.resolve(__dirname, '..'); - const files = await glob('**/**.test.js', { cwd: testsRoot }); - - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - - return new Promise((c, e) => { - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - console.error(err); - e(err); - } - }); -} - -module.exports = { - run -}; diff --git a/test/unit/api.test.js b/test/unit/api.test.js new file mode 100644 index 0000000..e180c6d --- /dev/null +++ b/test/unit/api.test.js @@ -0,0 +1,121 @@ +require('./helpers/vscode') +const assert = require('assert') +const https = require('https') +const { EventEmitter } = require('events') +const devops = require('../../lib/data/api') + +suite('DevOps.rest', () => { + + const originalRequest = https.request + let requests + let responses + + // Each call to https.request answers with the next queued response. + function respond(statusCode, body) { + responses.push({ statusCode, body: typeof body === 'string' ? body : JSON.stringify(body) }) + } + + setup(() => { + requests = [] + responses = [] + https.request = (options, callback) => { + const request = new EventEmitter() + request.write = data => options.written = data + request.end = () => { + requests.push(options) + const { statusCode, body } = responses.shift() ?? { statusCode: 200, body: '{}' } + const response = new EventEmitter() + response.statusCode = statusCode + response.headers = {} + callback(response) + response.emit('data', Buffer.from(body)) + response.emit('end') + } + return request + } + }) + + teardown(() => { + https.request = originalRequest + }) + + test('scope None calls the domain without an organization', async () => { + respond(200, { value: 1 }) + const result = await devops.get({ scope: 'None', domain: 'app.vssps.visualstudio.com', api: '_apis/profile?api-version=6.0' }) + + assert.deepStrictEqual(result, { value: 1 }) + assert.strictEqual(requests[0].hostname, 'app.vssps.visualstudio.com') + assert.strictEqual(requests[0].method, 'GET') + assert.strictEqual(requests[0].path, '/_apis/profile?api-version=6.0') + assert.strictEqual(requests[0].headers.Authorization, 'Bearer test-token') + }) + + test('merges the query object with the query of the api string', async () => { + await devops.get({ scope: 'None', domain: 'd', api: '/_apis/x?api-version=7.0', query: { mine: true } }) + assert.strictEqual(requests[0].path, '/_apis/x?mine=true&api-version=7.0') + }) + + test('builds organization, project and team paths', async () => { + await devops.get({ domain: 'd', api: '_apis/x', organization: 'org' }) + await devops.get({ domain: 'd', api: '_apis/x', organization: 'org', project: 'proj' }) + await devops.get({ domain: 'd', api: '_apis/x', organization: 'org', project: 'proj', team: 'team' }) + + assert.deepStrictEqual(requests.map(r => r.path), [ + '/org/_apis/x?', + '/org/proj/_apis/x?', + '/org/proj/team/_apis/x?' + ]) + }) + + test('encodes spaces in the path', async () => { + await devops.get({ domain: 'd', api: '_apis/x', organization: 'org', project: 'My Project' }) + assert.strictEqual(requests[0].path, '/org/My%20Project/_apis/x?') + }) + + test('sends the body as json on post', async () => { + await devops.post({ domain: 'd', api: '_apis/x', organization: 'org', body: { name: 'repo' } }) + + assert.strictEqual(requests[0].method, 'POST') + assert.strictEqual(requests[0].headers['Content-Type'], 'application/json; charset=utf-8') + assert.strictEqual(requests[0].written.toString(), '{"name":"repo"}') + }) + + test('get never sends a body', async () => { + await devops.get({ domain: 'd', api: '_apis/x', organization: 'org', body: { ignored: true } }) + + assert.strictEqual(requests[0].written, undefined) + assert.strictEqual(requests[0].headers['Content-Type'], 'application/x-www-form-urlencoded; charset=utf-8') + }) + + test('strips a byte order mark from the response', async () => { + respond(200, '{"ok":true}') + assert.deepStrictEqual(await devops.get({ scope: 'None', domain: 'd', api: 'x' }), { ok: true }) + }) + + test('rejects with the message Azure DevOps returns on errors', async () => { + respond(404, { message: 'Project not found' }) + await assert.rejects(devops.get({ scope: 'None', domain: 'd', api: 'x' }), /Project not found/) + }) + + test('rejects with the status code when the error has no message', async () => { + respond(500, {}) + await assert.rejects(devops.get({ scope: 'None', domain: 'd', api: 'x' }), /HTTP 500/) + }) + + test('rejects on a response that is not json', async () => { + respond(200, 'login') + await assert.rejects(devops.get({ scope: 'None', domain: 'd', api: 'x' }), /Unexpected response \(HTTP 200\)/) + }) + + test('uses the organization of the current user when none is given', async () => { + respond(200, { id: 'id', displayName: 'User', publicAlias: 'alias', emailAddress: 'User@Example.com' }) + respond(200, { value: [{ accountName: 'first' }, { accountName: 'second' }] }) + respond(200, {}) + + await devops.get({ domain: 'dev.azure.com', api: '_apis/projects', scope: 'organization' }) + + assert.strictEqual(requests[1].path, '/_apis/accounts?memberId=alias&api-version=6.0') + assert.strictEqual(requests[2].path, '/first/_apis/projects?') + }) + +}) diff --git a/test/unit/helpers/vscode.js b/test/unit/helpers/vscode.js new file mode 100644 index 0000000..3878194 --- /dev/null +++ b/test/unit/helpers/vscode.js @@ -0,0 +1,26 @@ +const Module = require('module') + +// Minimal stand-in for the 'vscode' module, which only exists inside the extension host. +// Require this before any module from lib/ that depends on vscode. +const vscode = { + settings: {}, + workspace: { + getConfiguration: () => ({ + get: key => vscode.settings[key], + update: async (key, value) => { vscode.settings[key] = value } + }) + }, + window: { + createOutputChannel: () => ({ appendLine: () => { } }) + }, + authentication: { + getSession: async () => ({ accessToken: 'test-token' }) + } +} + +const load = Module._load +Module._load = function (request, ...args) { + return request === 'vscode' ? vscode : load.call(this, request, ...args) +} + +module.exports = vscode diff --git a/test/unit/project.test.js b/test/unit/project.test.js new file mode 100644 index 0000000..612004f --- /dev/null +++ b/test/unit/project.test.js @@ -0,0 +1,104 @@ +require('./helpers/vscode') +const assert = require('assert') +const fs = require('fs') +const os = require('os') +const path = require('path') +const Project = require('../../lib/data/project') + +suite('Project', () => { + + const originalHomedir = os.homedir + let directory + + setup(() => { + directory = fs.mkdtempSync(path.join(os.tmpdir(), 'devops-project-')) + os.homedir = () => directory + }) + + teardown(() => { + os.homedir = originalHomedir + Project.customPath = null + fs.rmSync(directory, { recursive: true, force: true }) + }) + + test('defaults to git/repos in the home directory', () => { + assert.strictEqual(Project.defaultPath, path.join(directory, 'git', 'repos')) + }) + + test('replaces {{HOME_DIR}} and creates the custom path', () => { + Project.customPath = '{{HOME_DIR}}/projects' + + assert.strictEqual(Project.customPath, `${directory}/projects`) + assert.ok(fs.existsSync(Project.customPath)) + }) + + test('an empty custom path is not created', () => { + Project.customPath = '' + assert.strictEqual(Project.customPath, '') + }) + + test('places the project below the organization in upper case', () => { + const project = new Project({ id: '1', name: 'Proj' }, 'myorg') + assert.strictEqual(project.path, path.join(directory, 'git', 'repos', 'MYORG', 'Proj')) + }) + + test('uses the custom path when set', () => { + Project.customPath = path.join(directory, 'custom') + const project = new Project({ id: '1', name: 'Proj' }, 'myorg') + assert.strictEqual(project.path, path.join(directory, 'custom', 'MYORG', 'Proj')) + }) + + test('rejects an empty repository name', async () => { + const project = new Project({ id: '1', name: 'Proj' }, 'myorg') + await assert.rejects(project.createRepository(''), /Not a valid Repository Name/) + }) + +}) + +suite('Project.getResources', () => { + + let project + let calls + + class Resource { + static async from(context, refresh, ttl) { + calls.push({ context, refresh, ttl }) + return [`loaded ${calls.length}`] + } + } + + setup(() => { + calls = [] + project = new Project({ id: '1', name: 'Proj' }, 'myorg') + }) + + test('loads once and serves later calls from memory', async () => { + assert.deepStrictEqual(await project.getResources(Resource), ['loaded 1']) + assert.deepStrictEqual(await project.getResources(Resource), ['loaded 1']) + assert.strictEqual(calls.length, 1) + assert.strictEqual(calls[0].context, project) + }) + + test('refresh reloads and passes the flag on', async () => { + await project.getResources(Resource) + assert.deepStrictEqual(await project.getResources(Resource, true), ['loaded 2']) + assert.strictEqual(calls[1].refresh, true) + }) + + test('reloads after the ttl expired', async () => { + await project.getResources(Resource, false, -1) + await project.getResources(Resource, false, -1) + assert.strictEqual(calls.length, 2) + }) + + test('keeps resources of different contexts apart', async () => { + const repository = { id: 'repo' } + await project.getResources(Resource) + await project.getResources(Resource, false, 30, repository) + await project.getResources(Resource, false, 30, repository) + + assert.strictEqual(calls.length, 2) + assert.strictEqual(calls[1].context, repository) + }) + +})