From 2c3d3026773be00e0676ae1e616e0f88efbe1a4e Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Tue, 10 Feb 2026 14:31:03 -0500 Subject: [PATCH 01/11] reorganizes unit tests adds support for view elm as json --- .vscode/launch.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index 1b99d88..124c277 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,5 +14,20 @@ "outFiles": ["${workspaceFolder}/dist/**/*.js"], "preLaunchTask": "npm: watch" } + // ,{ + // "name": "Extension Tests", + // "type": "extensionHost", + // "request": "launch", + // "args": [ + // "${workspaceFolder}/tests/empty", + // "--extensionDevelopmentPath=${workspaceFolder}", + // "--extensionTestsPath=${workspaceFolder}/dist/__test__/suite/index.js", + // "--disable-extensions", + // "--new-window" + // ], + // "outFiles": ["${workspaceFolder}/dist/__test__/**/*.js"], + // "preLaunchTask": "npm: pretest", + // "outputCapture": "std" + // } ] } From 1d4e892174929d1760fe8bcf36e68e03e5690402 Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Tue, 10 Feb 2026 14:43:36 -0500 Subject: [PATCH 02/11] removes unused launch settings --- .vscode/launch.json | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 124c277..1b99d88 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,20 +14,5 @@ "outFiles": ["${workspaceFolder}/dist/**/*.js"], "preLaunchTask": "npm: watch" } - // ,{ - // "name": "Extension Tests", - // "type": "extensionHost", - // "request": "launch", - // "args": [ - // "${workspaceFolder}/tests/empty", - // "--extensionDevelopmentPath=${workspaceFolder}", - // "--extensionTestsPath=${workspaceFolder}/dist/__test__/suite/index.js", - // "--disable-extensions", - // "--new-window" - // ], - // "outFiles": ["${workspaceFolder}/dist/__test__/**/*.js"], - // "preLaunchTask": "npm: pretest", - // "outputCapture": "std" - // } ] } From 6f3b065e9545cd734648a902b8395feeda32a62b Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Thu, 19 Feb 2026 21:44:55 -0500 Subject: [PATCH 03/11] adds support for selective cql execution --- .gitignore | 3 +- .vscode-test.js | 11 +- .vscode/extensions.json | 34 +- .vscode/launch.json | 12 +- package-lock.json | 1790 +++++++++++++---- package.json | 29 +- .../input/cql/SimpleMeasure.cql | 11 + .../test-workspace/input/cql/cql-options.json | 19 + .../SimpleMeasure/1111/Patient-1111.json | 168 ++ .../suite/{ => extension}/extension.test.ts | 0 .../suite/helpers/file-helpers.test.ts | 11 +- src/__test__/suite/index.ts | 40 - src/commands.ts | 57 - src/commands/README.md | 11 + src/commands/commands.ts | 59 + src/commands/execute-cql.ts | 372 ++++ src/commands/log-files.ts | 90 + src/commands/view-elm.ts | 27 + src/cql-language-server/cqlLanguageClient.ts | 196 ++ .../languageServerStarter.ts | 58 +- src/cql-service/README.md | 13 + src/cql-service/cqlService.executeCql.ts | 103 + src/cql-service/cqlService.getElm.ts | 7 + src/cqlLanguageClient.ts | 223 -- src/executeCql.ts | 258 --- src/extension.ts | 299 +-- src/{ => java-support}/findJavaRuntimes.ts | 0 .../javaServiceInstaller.ts | 6 +- src/{ => java-support}/requirements.ts | 2 +- src/log-services/logger.ts | 48 + src/log-services/multi-transport-logger.ts | 115 ++ src/log.ts | 27 - .../file-helpers.ts => utils/file-utils.ts} | 0 33 files changed, 2779 insertions(+), 1320 deletions(-) create mode 100644 src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql create mode 100644 src/__test__/resources/test-workspace/input/cql/cql-options.json create mode 100644 src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/Patient-1111.json rename src/__test__/suite/{ => extension}/extension.test.ts (100%) delete mode 100644 src/__test__/suite/index.ts delete mode 100644 src/commands.ts create mode 100644 src/commands/README.md create mode 100644 src/commands/commands.ts create mode 100644 src/commands/execute-cql.ts create mode 100644 src/commands/log-files.ts create mode 100644 src/commands/view-elm.ts create mode 100644 src/cql-language-server/cqlLanguageClient.ts rename src/{ => cql-language-server}/languageServerStarter.ts (88%) create mode 100644 src/cql-service/README.md create mode 100644 src/cql-service/cqlService.executeCql.ts create mode 100644 src/cql-service/cqlService.getElm.ts delete mode 100644 src/cqlLanguageClient.ts delete mode 100644 src/executeCql.ts rename src/{ => java-support}/findJavaRuntimes.ts (100%) rename src/{ => java-support}/javaServiceInstaller.ts (96%) rename src/{ => java-support}/requirements.ts (98%) create mode 100644 src/log-services/logger.ts create mode 100644 src/log-services/multi-transport-logger.ts delete mode 100644 src/log.ts rename src/{helpers/file-helpers.ts => utils/file-utils.ts} (100%) diff --git a/.gitignore b/.gitignore index 99d757e..d42f703 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ server target dist bin -.vscode-test \ No newline at end of file +.vscode-test +src/__test__/resources/test-workspace/input/tests/results \ No newline at end of file diff --git a/.vscode-test.js b/.vscode-test.js index d99f25e..d112120 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -3,5 +3,14 @@ const { defineConfig } = require('@vscode/test-cli'); module.exports = defineConfig({ label: 'Tests (Empty Folder)', files: 'dist/__test__/**/*.test.js', - launchArgs: ['tests/empty', '--new-window', '--disable-extensions'], + workspaceFolder: './src/__test__/resources/test-workspace', + launchArgs: [ + 'tests/empty', + '--new-window', + '--disable-extensions', + '--disable-updates', + '--skip-welcome', + '--skip-release-notes', + '--disable-workspace-trust', + ], }); diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b789f43..0801f30 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,18 +1,18 @@ { - // See https://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "dbaeumer.vscode-eslint", - "streetsidesoftware.code-spell-checker", - "streetsidesoftware.code-spell-checker-medical-terms", - "streetsidesoftware.code-spell-checker-scientific-terms", - "sonarsource.sonarlint-vscode", - "esbenp.prettier-vscode", - "connor4312.esbuild-problem-matchers" - ], - "unwantedRecommendations": [ - "ms-vscode.vscode-typescript-tslint-plugin", - "eg2.tslint", - "eg2.vscode-npm-script", - ] -} \ No newline at end of file + // See https://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "dbaeumer.vscode-eslint", + "streetsidesoftware.code-spell-checker", + "streetsidesoftware.code-spell-checker-medical-terms", + "streetsidesoftware.code-spell-checker-scientific-terms", + "sonarsource.sonarlint-vscode", + "esbenp.prettier-vscode", + "connor4312.esbuild-problem-matchers" + ], + "unwantedRecommendations": [ + "ms-vscode.vscode-typescript-tslint-plugin", + "eg2.tslint", + "eg2.vscode-npm-script" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index 1b99d88..c6b355c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,17 @@ "type": "extensionHost", "request": "launch", "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--disable-extensions"], + "args": [ + "${workspaceFolder}/src/__test__/resources/test-workspace", + "--extensionDevelopmentPath=${workspaceFolder}", + "--disable-extensions", + "--new-window", + "--disable-extensions", + "--disable-updates", + "--skip-welcome", + "--skip-release-notes", + "--disable-workspace-trust" + ], "outFiles": ["${workspaceFolder}/dist/**/*.js"], "preLaunchTask": "npm: watch" } diff --git a/package-lock.json b/package-lock.json index 75aabdf..af860dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,12 +15,14 @@ "glob": "^10.5.0", "lodash": "^4.17.23", "node-fetch": "2.6.7", + "pino": "^10.3.1", "tslib": "^2.4.0", "vscode-languageclient": "^7.0.0", "vscode-uri": "^3.0.8", "winreg": "^1.2.4", "winston": "^3.8.1", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "winston-transport-vscode": "^0.1.0" }, "devDependencies": { "@types/chai": "^5.2.3", @@ -33,10 +35,10 @@ "@types/node-fetch": "^2.6.2", "@types/vscode": "^1.73.0", "@types/winreg": "^1.2.31", - "@vscode/test-cli": "^0.0.4", + "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.3.6", "chai": "4.5", - "mocha": "^10.2.0", + "mocha": "^11.7.5", "mock-fs": "^5.5.0", "prettier": "^3.3.3", "typescript": "^5.3.2" @@ -45,10 +47,21 @@ "vscode": ">=1.75.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -159,6 +172,50 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -221,6 +278,13 @@ "@types/node": "*" } }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/lodash": { "version": "4.14.183", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.183.tgz", @@ -260,6 +324,12 @@ "form-data": "^3.0.0" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, "node_modules/@types/vscode": { "version": "1.85.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.85.0.tgz", @@ -273,21 +343,27 @@ "dev": true }, "node_modules/@vscode/test-cli": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.4.tgz", - "integrity": "sha512-Tx0tfbxeSb2Xlo+jpd+GJrNLgKQHobhRHrYvOipZRZQYWZ82sKiK02VY09UjU1Czc/YnZnqyAnjUfaVGl3h09w==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.12.tgz", + "integrity": "sha512-iYN0fDg29+a2Xelle/Y56Xvv7Nc8Thzq4VwpzAF/SIE6918rDicqfsQxV6w1ttr2+SOm+10laGuY9FG2ptEKsQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/mocha": "^10.0.2", - "chokidar": "^3.5.3", + "@types/mocha": "^10.0.10", + "c8": "^10.1.3", + "chokidar": "^3.6.0", + "enhanced-resolve": "^5.18.3", "glob": "^10.3.10", "minimatch": "^9.0.3", - "mocha": "^10.2.0", - "supports-color": "^9.4.0", + "mocha": "^11.7.4", + "supports-color": "^10.2.2", "yargs": "^17.7.2" }, "bin": { "vscode-test": "out/bin.mjs" + }, + "engines": { + "node": ">=18" } }, "node_modules/@vscode/test-cli/node_modules/brace-expansion": { @@ -314,59 +390,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@vscode/test-cli/node_modules/supports-color": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", - "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/@vscode/test-cli/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "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/@vscode/test-cli/node_modules/yargs/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==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@vscode/test-cli/node_modules/yargs/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==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/@vscode/test-electron": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", @@ -394,16 +417,6 @@ "node": ">= 6.0.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -427,10 +440,11 @@ } }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -443,7 +457,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/assertion-error": { "version": "1.1.0", @@ -466,18 +481,31 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/brace-expansion": { @@ -506,13 +534,63 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/c8": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -544,6 +622,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -555,6 +634,19 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -569,16 +661,11 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -591,31 +678,26 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "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==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/color": { @@ -691,6 +773,13 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "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", @@ -734,6 +823,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -764,15 +854,30 @@ } }, "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -789,6 +894,69 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -803,6 +971,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -869,6 +1038,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -885,6 +1055,7 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -910,13 +1081,16 @@ } }, "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -936,18 +1110,13 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -956,6 +1125,16 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -975,6 +1154,45 @@ "node": "*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -996,6 +1214,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", @@ -1020,6 +1251,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -1030,15 +1274,59 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -1054,6 +1342,13 @@ "node": ">=0.10.0" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -1087,16 +1382,6 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1112,6 +1397,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -1124,6 +1410,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1141,6 +1428,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1158,11 +1446,22 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1173,34 +1472,87 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "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 + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, - "engines": { - "node": ">=10" + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, - "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 - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -1217,10 +1569,11 @@ } }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1267,6 +1620,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -1288,6 +1642,7 @@ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -1300,15 +1655,20 @@ } }, "node_modules/logform": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", - "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", "dependencies": { - "@colors/colors": "1.5.0", + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" } }, "node_modules/loupe": { @@ -1332,6 +1692,32 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1374,31 +1760,32 @@ } }, "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", - "glob": "^8.1.0", + "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "bin": { @@ -1406,51 +1793,63 @@ "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/mocha/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">=12" + "node": ">= 14.16.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://paulmillr.com/funding/" } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/mocha/node_modules/supports-color": { @@ -1458,6 +1857,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1516,6 +1916,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1528,13 +1929,13 @@ "node": ">= 6" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, "node_modules/one-time": { @@ -1550,6 +1951,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -1565,6 +1967,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -1600,6 +2003,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1644,11 +2048,19 @@ "node": "*" } }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1656,6 +2068,43 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, "node_modules/prettier": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", @@ -1677,6 +2126,28 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -1713,6 +2184,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -1720,6 +2192,15 @@ "node": ">=8.10.0" } }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -1826,6 +2307,24 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -1904,6 +2403,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1912,15 +2412,71 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">=8" + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/text-hex": { @@ -1928,6 +2484,18 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1947,9 +2515,13 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } }, "node_modules/tslib": { "version": "2.4.0", @@ -1992,6 +2564,21 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/vscode-jsonrpc": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", @@ -2069,6 +2656,7 @@ "version": "3.8.1", "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.1.tgz", "integrity": "sha512-r+6YAiCR4uI3N8eQNOg8k3P3PqwAm20cLKlzVD9E66Ch39+LZC+VH1UKf9JemQj2B3QoUHfKD7Poewn0Pr3Y1w==", + "peer": true, "dependencies": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", @@ -2103,22 +2691,41 @@ } }, "node_modules/winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "logform": "^2.7.0", + "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" }, "engines": { - "node": ">= 6.4.0" + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport-vscode": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/winston-transport-vscode/-/winston-transport-vscode-0.1.0.tgz", + "integrity": "sha512-iHJEJP5vinrVxMId+gWN00kUR4haP+VMY5pydB53Ug3ZyXZ0EmWZp46hFJQtFQGP+BnxdCA0UElLjUz8QQPEGw==", + "license": "Apache-2.0", + "dependencies": { + "logform": "^2.6.0", + "triple-beam": "^1.4.1", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "winston": ">=3.0.0" } }, "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2142,9 +2749,9 @@ } }, "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, @@ -2153,6 +2760,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2183,12 +2791,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -2204,31 +2806,32 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { @@ -2236,6 +2839,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -2251,6 +2855,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -2260,10 +2865,16 @@ } }, "dependencies": { + "@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true + }, "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==" }, "@dabh/diagnostics": { "version": "2.0.3", @@ -2333,6 +2944,39 @@ } } }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" + }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2384,6 +3028,12 @@ "@types/node": "*" } }, + "@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, "@types/lodash": { "version": "4.14.183", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.183.tgz", @@ -2418,9 +3068,14 @@ "dev": true, "requires": { "@types/node": "*", - "form-data": "^3.0.0" + "form-data": "^4.0.5" } }, + "@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, "@types/vscode": { "version": "1.85.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.85.0.tgz", @@ -2434,17 +3089,19 @@ "dev": true }, "@vscode/test-cli": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.4.tgz", - "integrity": "sha512-Tx0tfbxeSb2Xlo+jpd+GJrNLgKQHobhRHrYvOipZRZQYWZ82sKiK02VY09UjU1Czc/YnZnqyAnjUfaVGl3h09w==", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@vscode/test-cli/-/test-cli-0.0.12.tgz", + "integrity": "sha512-iYN0fDg29+a2Xelle/Y56Xvv7Nc8Thzq4VwpzAF/SIE6918rDicqfsQxV6w1ttr2+SOm+10laGuY9FG2ptEKsQ==", "dev": true, "requires": { - "@types/mocha": "^10.0.2", - "chokidar": "^3.5.3", + "@types/mocha": "^10.0.10", + "c8": "^10.1.3", + "chokidar": "^3.6.0", + "enhanced-resolve": "^5.18.3", "glob": "^10.3.10", "minimatch": "^9.0.3", - "mocha": "^10.2.0", - "supports-color": "^9.4.0", + "mocha": "^11.7.4", + "supports-color": "^10.2.2", "yargs": "^17.7.2" }, "dependencies": { @@ -2465,46 +3122,6 @@ "requires": { "brace-expansion": "^2.0.1" } - }, - "supports-color": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", - "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", - "dev": true - }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "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" - }, - "dependencies": { - "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==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "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==", - "dev": true - } - } } } }, @@ -2529,12 +3146,6 @@ "debug": "4" } }, - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2549,9 +3160,9 @@ } }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -2581,15 +3192,20 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true }, "brace-expansion": { @@ -2616,6 +3232,35 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "c8": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -2645,6 +3290,17 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "check-error": { @@ -2657,9 +3313,9 @@ } }, "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "requires": { "anymatch": "~3.1.2", @@ -2670,27 +3326,16 @@ "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } } }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "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==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -2765,6 +3410,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -2812,11 +3463,22 @@ "dev": true }, "diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", "dev": true }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -2832,6 +3494,49 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, + "enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + } + }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2921,13 +3626,15 @@ } }, "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, @@ -2941,19 +3648,19 @@ "universalify": "^0.1.0" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2966,6 +3673,34 @@ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, + "get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + } + }, "glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -2997,6 +3732,21 @@ } } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -3008,6 +3758,30 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -3022,6 +3796,12 @@ "parse-passwd": "^1.0.0" } }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -3049,16 +3829,6 @@ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3104,6 +3874,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3132,6 +3908,44 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true + }, + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, "jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -3142,9 +3956,9 @@ } }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -3209,11 +4023,12 @@ } }, "logform": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz", - "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", "requires": { - "@colors/colors": "1.5.0", + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", @@ -3237,6 +4052,21 @@ "yallist": "^4.0.0" } }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true + }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3266,64 +4096,67 @@ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==" }, "mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", "dev": true, "requires": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", - "glob": "^8.1.0", + "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "dependencies": { "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "requires": { "balanced-match": "^1.0.0" } }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "readdirp": "^4.0.1" } }, "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } }, + "readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true + }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -3370,14 +4203,10 @@ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } + "on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" }, "one-time": { "version": "1.0.0", @@ -3454,12 +4283,49 @@ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, + "picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "requires": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + } + }, + "pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "requires": { + "split2": "^4.0.0" + } + }, + "pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" + }, "prettier": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", @@ -3472,6 +4338,16 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==" + }, + "quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -3513,6 +4389,11 @@ "picomatch": "^2.2.1" } }, + "real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3579,6 +4460,19 @@ "is-arrayish": "^0.3.1" } }, + "sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "requires": { + "atomic-sleep": "^1.0.0" + } + }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -3642,12 +4536,46 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true + }, + "tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true + }, + "test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "text-hex": { @@ -3655,6 +4583,14 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, + "thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "requires": { + "real-require": "^0.2.0" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3670,9 +4606,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==" }, "tslib": { "version": "2.4.0", @@ -3701,6 +4637,17 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + } + }, "vscode-jsonrpc": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", @@ -3766,6 +4713,7 @@ "version": "3.8.1", "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.1.tgz", "integrity": "sha512-r+6YAiCR4uI3N8eQNOg8k3P3PqwAm20cLKlzVD9E66Ch39+LZC+VH1UKf9JemQj2B3QoUHfKD7Poewn0Pr3Y1w==", + "peer": true, "requires": { "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", @@ -3803,19 +4751,19 @@ } }, "winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", "requires": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "logform": "^2.7.0", + "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" }, "dependencies": { "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -3824,10 +4772,20 @@ } } }, + "winston-transport-vscode": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/winston-transport-vscode/-/winston-transport-vscode-0.1.0.tgz", + "integrity": "sha512-iHJEJP5vinrVxMId+gWN00kUR4haP+VMY5pydB53Ug3ZyXZ0EmWZp46hFJQtFQGP+BnxdCA0UElLjUz8QQPEGw==", + "requires": { + "logform": "^2.6.0", + "triple-beam": "^1.4.1", + "winston-transport": "^4.7.0" + } + }, "workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true }, "wrap-ansi": { @@ -3851,12 +4809,6 @@ "strip-ansi": "^6.0.0" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -3869,24 +4821,24 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yargs-unparser": { diff --git a/package.json b/package.json index 933198a..45be0b1 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,9 @@ "Snippets" ], "main": "./dist/extension", + "activationEvents": [ + "workspaceContains:**/*.cql" + ], "contributes": { "languages": [ { @@ -97,6 +100,16 @@ "command": "cql.action.executeCql", "title": "Execute CQL", "category": "CQL" + }, + { + "command": "cql.action.executeCql.selectLibraries", + "title": "Execute CQL - Select Libraries", + "category": "CQL" + }, + { + "command": "cql.action.executeCql.selectTestCases", + "title": "Execute CQL - Select Test Cases", + "category": "CQL" } ], "menus": { @@ -106,6 +119,11 @@ "when": "editorLangId == cql", "group": "1_cqlactions@1.execute@1" }, + { + "command": "cql.action.executeCql.selectTestCases", + "when": "editorLangId == cql", + "group": "1_cqlactions@1.execute@3" + }, { "command": "cql.action.viewElm.xml", "when": "editorLangId == cql", @@ -122,6 +140,9 @@ "resolutions": { "color-name": "1.1.3" }, + "overrides": { + "form-data": "^4.0.5" + }, "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", @@ -147,10 +168,10 @@ "@types/node-fetch": "^2.6.2", "@types/vscode": "^1.73.0", "@types/winreg": "^1.2.31", - "@vscode/test-cli": "^0.0.4", + "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.3.6", "chai": "4.5", - "mocha": "^10.2.0", + "mocha": "^11.7.5", "mock-fs": "^5.5.0", "prettier": "^3.3.3", "typescript": "^5.3.2" @@ -162,12 +183,14 @@ "glob": "^10.5.0", "lodash": "^4.17.23", "node-fetch": "2.6.7", + "pino": "^10.3.1", "tslib": "^2.4.0", "vscode-languageclient": "^7.0.0", "vscode-uri": "^3.0.8", "winreg": "^1.2.4", "winston": "^3.8.1", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "winston-transport-vscode": "^0.1.0" }, "prettier": { "printWidth": 100, diff --git a/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql b/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql new file mode 100644 index 0000000..3499e75 --- /dev/null +++ b/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql @@ -0,0 +1,11 @@ +library SimpleMeasure version '1.0.000' + +using QICore version '6.0.0' + +parameter "Measurement Period" Interval + default Interval[@2026-01-01T00:00:00.000Z, @2027-01-01T00:00:00.000Z) + +context Patient + +define "Patient Name": + Patient.name diff --git a/src/__test__/resources/test-workspace/input/cql/cql-options.json b/src/__test__/resources/test-workspace/input/cql/cql-options.json new file mode 100644 index 0000000..5145c34 --- /dev/null +++ b/src/__test__/resources/test-workspace/input/cql/cql-options.json @@ -0,0 +1,19 @@ +{ + "options": [ + "EnableAnnotations", + "EnableResultTypes", + "EnableLocators", + "DisableListDemotion", + "DisableListPromotion" + ], + "formats": [ + "XML", + "JSON" + ], + "validateUnits": true, + "verifyOnly": false, + "errorLevel": "Info", + "signatureLevel": "All", + "analyzeDataRequirements": false, + "collapseDataRequirements": false +} \ No newline at end of file diff --git a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/Patient-1111.json b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/Patient-1111.json new file mode 100644 index 0000000..d974442 --- /dev/null +++ b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/Patient-1111.json @@ -0,0 +1,168 @@ +{ + "resourceType": "Patient", + "id": "1111", + "meta": { + "profile": [ + "http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-patient" + ] + }, + "text": { + "status": "generated", + "div": "

Jim Chalmers male, DoB: 1974-12-25 ( Medical record number/12345\u00a0(use:\u00a0USUAL,\u00a0period:\u00a02001-05-06 --> (ongoing)))


Active:trueDeceased:false
Alt Names:
  • Peter James Chalmers (OFFICIAL)
  • Peter James Windsor (MAIDEN)
Contact Details:
  • ph: (03) 5555 6473(WORK)
  • ph: (03) 3410 5613(MOBILE)
  • ph: (03) 5555 8834(OLD)
  • 534 Erewhon St PeasantVille, Utah 84414(HOME)
Next-of-Kin:
  • Bénédicte du Marché (female)
  • 534 Erewhon St PleasantVille VT 3999 (HOME)
  • +33 (237) 998327
  • Valid Period: 2012 --> (ongoing)
Links:
" + }, + "identifier": [ + { + "use": "usual", + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR" + } + ] + }, + "system": "urn:oid:1.2.36.146.595.217.0.1", + "value": "12345", + "period": { + "start": "2001-05-06" + }, + "assigner": { + "display": "Acme Healthcare" + } + } + ], + "active": true, + "name": [ + { + "use": "official", + "family": "Chalmers", + "given": [ + "Peter", + "James" + ] + }, + { + "use": "usual", + "family": "Chalmers", + "given": [ + "Jim" + ] + }, + { + "use": "maiden", + "family": "Windsor", + "given": [ + "Peter", + "James" + ], + "period": { + "end": "2002" + } + } + ], + "telecom": [ + { + "system": "phone", + "value": "(03) 5555 6473", + "use": "work", + "rank": 1 + }, + { + "system": "phone", + "value": "(03) 3410 5613", + "use": "mobile", + "rank": 2 + }, + { + "system": "phone", + "value": "(03) 5555 8834", + "use": "old", + "period": { + "end": "2014" + } + } + ], + "gender": "male", + "birthDate": "1974-12-25", + "_birthDate": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime", + "valueDateTime": "1974-12-25T14:35:45-05:00" + } + ] + }, + "deceasedBoolean": false, + "address": [ + { + "use": "home", + "type": "both", + "text": "534 Erewhon St PeasantVille, Utah 84414", + "line": [ + "534 Erewhon St" + ], + "city": "PleasantVille", + "district": "Rainbow", + "state": "UT", + "postalCode": "84414", + "period": { + "start": "1974-12-25" + } + } + ], + "contact": [ + { + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "N" + } + ] + } + ], + "name": { + "family": "du Marché", + "_family": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix", + "valueString": "VV" + } + ] + }, + "given": [ + "Bénédicte" + ] + }, + "telecom": [ + { + "system": "phone", + "value": "+33 (237) 998327" + } + ], + "address": { + "use": "home", + "type": "both", + "line": [ + "534 Erewhon St" + ], + "city": "PleasantVille", + "district": "Rainbow", + "state": "VT", + "postalCode": "3999", + "period": { + "start": "1974-12-25" + } + }, + "gender": "female", + "period": { + "start": "2012" + } + } + ], + "managingOrganization": { + "reference": "Organization/example" + } +} \ No newline at end of file diff --git a/src/__test__/suite/extension.test.ts b/src/__test__/suite/extension/extension.test.ts similarity index 100% rename from src/__test__/suite/extension.test.ts rename to src/__test__/suite/extension/extension.test.ts diff --git a/src/__test__/suite/helpers/file-helpers.test.ts b/src/__test__/suite/helpers/file-helpers.test.ts index c1f86b5..2a4ca68 100644 --- a/src/__test__/suite/helpers/file-helpers.test.ts +++ b/src/__test__/suite/helpers/file-helpers.test.ts @@ -1,10 +1,9 @@ import { expect } from 'chai'; import * as fs from 'fs'; import mock from 'mock-fs'; -import { ensureExists } from '../../../helpers/file-helpers'; +import { ensureExists } from '../../../utils/file-utils'; suite('ensureExists() with mock-fs', () => { - teardown(() => { // Crucial: Restore the real file system after every test mock.restore(); @@ -15,7 +14,7 @@ suite('ensureExists() with mock-fs', () => { mock({}); const testPath = './new-folder'; - + ensureExists(testPath); // Verify the folder now exists in the virtual FS @@ -26,13 +25,13 @@ suite('ensureExists() with mock-fs', () => { test('should not throw an error if the directory already exists', () => { // Setup virtual FS with an existing directory mock({ - './existing-folder': {} + './existing-folder': {}, }); const testPath = './existing-folder'; - + // This should run without calling mkdirSync again/throwing error expect(() => ensureExists(testPath)).to.not.throw(); expect(fs.existsSync(testPath)).to.be.true; }); -}); \ No newline at end of file +}); diff --git a/src/__test__/suite/index.ts b/src/__test__/suite/index.ts deleted file mode 100644 index f840a66..0000000 --- a/src/__test__/suite/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { glob } from 'glob'; // Use named import for glob v10 -import Mocha from 'mocha'; -import * as path from 'path'; - -export async function run(): Promise { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd', - timeout: 50000, - }); - - const testsRoot = path.resolve(__dirname, '..'); - - try { - // glob v10 returns a Promise when no callback is provided - const files = await glob('**/*.test.js', { cwd: testsRoot }); - - // Add files to the test suite - files.forEach((f: string) => mocha.addFile(path.resolve(testsRoot, f))); - - return new Promise((resolve, reject) => { - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - reject(new Error(`${failures} tests failed.`)); - } else { - resolve(); - } - }); - } catch (err) { - console.error(err); - reject(err); - } - }); - } catch (err) { - // Catch errors from the glob search - throw err; - } -} \ No newline at end of file diff --git a/src/commands.ts b/src/commands.ts deleted file mode 100644 index 1a22497..0000000 --- a/src/commands.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * These are constants for the commands used by or implemented by this extension - * Commands that are defined by the vscode api are named accordingly, - * Commands implemented defined by this extension are prefixed "cql" - */ -export namespace Commands { - /** - * Open Browser - */ - export const OPEN_BROWSER = "vscode.open"; - - /** - * Execute Workspace Command - */ - export const EXECUTE_WORKSPACE_COMMAND = "cql.execute.workspaceCommand"; - - /** - * Open CQL Language Server Log file - */ - export const OPEN_SERVER_LOG = "cql.open.serverLog"; - - /** - * Open CQL client Log file - */ - export const OPEN_CLIENT_LOG = "cql.open.clientLog"; - - /** - * Open CQL log files side by side - */ - export const OPEN_LOGS = "cql.open.logs"; - - /* - * Show Output - */ - export const OPEN_OUTPUT = "cql.open.output"; - - /* - * View ELM for CQL - */ - // TODO: Shorten the command, the whole namespace isn't needed. - export const VIEW_ELM_COMMAND_XML = "cql.action.viewElm.xml"; - export const VIEW_ELM_COMMAND_JSON = "cql.action.viewElm.json"; - export const VIEW_ELM = "org.opencds.cqf.cql.ls.viewElm"; - - /* - * Execute CQL - * TODO: Deprecate once full debugging support exists - */ - export const EXECUTE_CQL_COMMAND = "cql.action.executeCql"; - export const EXECUTE_CQL = - "org.opencds.cqf.cql.ls.plugin.debug.startDebugSession"; - - /* - * Open settings.json - */ - export const OPEN_JSON_SETTINGS = "workbench.action.openSettingsJson"; -} diff --git a/src/commands/README.md b/src/commands/README.md new file mode 100644 index 0000000..48e67b6 --- /dev/null +++ b/src/commands/README.md @@ -0,0 +1,11 @@ +# Commands + +The commands modules are meant to be the 'bridge' between the VSCode UI and underlying CQL services. + +Command operations + +- are triggered by users interacting with the VSCode UI. +- are allowed to update the UI as needed + - to inform the user of the operation status + - show result from operations +- can use all windowing/logging capabilities provided by vscode diff --git a/src/commands/commands.ts b/src/commands/commands.ts new file mode 100644 index 0000000..cec9d62 --- /dev/null +++ b/src/commands/commands.ts @@ -0,0 +1,59 @@ +/** + * These are constants for the commands used by or implemented by this extension + * Commands that are defined by the vscode api are named accordingly, + * Commands implemented defined by this extension are prefixed "cql" + */ +export namespace Commands { + /** + * Open Browser + */ + export const OPEN_BROWSER = 'vscode.open'; + + /** + * Execute Workspace Command + */ + export const EXECUTE_WORKSPACE_COMMAND = 'cql.execute.workspaceCommand'; + + /** + * Open CQL Language Server Log file + */ + export const OPEN_SERVER_LOG = 'cql.open.serverLog'; + + /** + * Open CQL client Log file + */ + export const OPEN_CLIENT_LOG = 'cql.open.clientLog'; + + /** + * Open CQL log files side by side + */ + export const OPEN_LOGS = 'cql.open.logs'; + + /* + * Show Output + */ + export const OPEN_OUTPUT = 'cql.open.output'; + + /* + * View ELM for CQL + */ + // TODO: Shorten the command, the whole namespace isn't needed. + export const VIEW_ELM_COMMAND_XML = 'cql.action.viewElm.xml'; + export const VIEW_ELM_COMMAND_JSON = 'cql.action.viewElm.json'; + export const VIEW_ELM = 'org.opencds.cqf.cql.ls.viewElm'; + + /* + * Execute CQL + * TODO: Deprecate once full debugging support exists + */ + export const EXECUTE_CQL_COMMAND = 'cql.action.executeCql'; + export const EXECUTE_CQL = 'org.opencds.cqf.cql.ls.plugin.debug.startDebugSession'; + + export const EXECUTE_CQL_COMMAND_SELECT_LIBRARIES = 'cql.action.executeCql.selectLibraries'; + export const EXECUTE_CQL_COMMAND_SELECT_TEST_CASES = 'cql.action.executeCql.selectTestCases'; + + /* + * Open settings.json + */ + export const OPEN_JSON_SETTINGS = 'workbench.action.openSettingsJson'; +} diff --git a/src/commands/execute-cql.ts b/src/commands/execute-cql.ts new file mode 100644 index 0000000..0377fb4 --- /dev/null +++ b/src/commands/execute-cql.ts @@ -0,0 +1,372 @@ +import * as fse from 'fs-extra'; +import { glob } from 'glob'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { commands, ExtensionContext, Position, ProgressLocation, TextEditor, Uri, window, workspace } from 'vscode'; +import { Utils } from 'vscode-uri'; +import { Commands } from '../commands/commands'; +import { + executeCql, + TestCase, + TestCaseExclusion, + TestConfig, +} from '../cql-service/cqlService.executeCql'; +import * as log from '../log-services/logger'; + +interface CqlPaths { + libraryDirectoryPath: Uri; + projectDirectoryPath: Uri; + optionsPath: Uri; + resultDirectoryPath: Uri; + terminologyDirectoryPath: Uri; + testConfigPath: Uri; + testDirectoryPath: Uri; +} + +export function register(context: ExtensionContext): void { + context.subscriptions.push( + commands.registerCommand(Commands.EXECUTE_CQL_COMMAND, async (uri: Uri) => { + executeCQLFile(uri); + }), + commands.registerCommand(Commands.EXECUTE_CQL_COMMAND_SELECT_LIBRARIES, async (uri: Uri) => { + selectLibraries(); + }), + commands.registerCommand(Commands.EXECUTE_CQL_COMMAND_SELECT_TEST_CASES, async (uri: Uri) => { + selectTestCases(uri); + }), + ); +} + +export async function selectLibraries(): Promise { + const cqlPaths = getCqlPaths(); + if (!cqlPaths) { + window.showErrorMessage('Unable to determine needed CQL Paths.'); + return; + } + + const libraries = getLibraries(cqlPaths.libraryDirectoryPath); + const quickPickItems = libraries + .map(uri => ({ label: Utils.basename(uri), uri })) + .sort((a, b) => a.label.localeCompare(b.label)); + + const quickPick = window.createQuickPick<{ label: string; uri: Uri }>(); + if (quickPickItems.length > 0) { + quickPick.items = quickPickItems; + quickPick.canSelectMany = true; + quickPick.show(); + + quickPick.onDidAccept(async () => { + const selected = [...quickPick.selectedItems]; + quickPick.hide(); + + await window.withProgress( + { + location: ProgressLocation.Notification, + title: 'Executing CQL Libraries', + cancellable: false, + }, + async progress => { + const total = selected.length; + for (let i = 0; i < total; i++) { + const item = selected[i]; + progress.report({ + message: `(${i + 1}/${total}) ${item.label}`, + increment: (1 / total) * 100, + }); + await executeCQLFile(item.uri); + await new Promise(resolve => setTimeout(resolve, 500)); + } + }, + ); + }); + } +} + +export async function selectTestCases(cqlFileUri: Uri): Promise { + const quickPick = window.createQuickPick(); + + const libraryDirectory = Utils.dirname(cqlFileUri); + const libraryName = Utils.basename(cqlFileUri).replace('.cql', '').split('-')[0]; + const projectPath = workspace.getWorkspaceFolder(cqlFileUri)!.uri; + + const rootDir = Utils.resolvePath(projectPath); + const optionsPath = Utils.resolvePath(libraryDirectory, 'cql-options.json'); + const testPath = Utils.resolvePath(projectPath, 'input', 'tests'); + const resultPath = Utils.resolvePath(testPath, 'results'); + + const outputPath = Utils.resolvePath(resultPath, `${libraryName}.txt`); + fse.ensureFileSync(outputPath.fsPath); + const textDocument = await workspace.openTextDocument(outputPath); + const textEditor = await window.showTextDocument(textDocument); + + const testConfigPath = Utils.resolvePath(testPath, 'config.json'); + const testConfig = loadTestConfig(testConfigPath); + const excludedTestCases = getExcludedTestCases(libraryName, testConfig.testCasesToExclude); + + const testCases = getTestCases(testPath, libraryName, Array.from(excludedTestCases.keys())); + const namedTestCases = testCases.filter( + (testCase): testCase is Required => testCase.name !== undefined, + ); + const quickPickItems = namedTestCases.map(testCase => ({ label: testCase.name })); + + if (quickPickItems.length > 0) { + quickPick.items = quickPickItems; + quickPick.canSelectMany = true; + quickPick.show(); + + quickPick.onDidAccept(() => { + const selected = namedTestCases.filter(testCase => + quickPick.selectedItems.some(item => item.label === testCase.name), + ); + quickPick.hide(); + executeCQLFile(cqlFileUri, selected); + }); + } +} + +export async function executeCQLFile( + cqlFileUri: Uri, + testCases: Array | undefined = undefined, +): Promise { + if (!fs.existsSync(cqlFileUri.fsPath)) { + window.showInformationMessage('No library content found. Please save before executing.'); + return; + } + + const cqlPaths = getCqlPaths(); + if (!cqlPaths) { + window.showErrorMessage('Unable to determine needed CQL Paths.'); + return; + } + + const libraryName = Utils.basename(cqlFileUri).replace('.cql', '').split('-')[0]; + const outputPath = Utils.resolvePath(cqlPaths.resultDirectoryPath, `${libraryName}.txt`); + fse.ensureFileSync(outputPath.fsPath); + const textDocument = await workspace.openTextDocument(outputPath); + const textEditor = await window.showTextDocument(textDocument); + + const testConfig = loadTestConfig(cqlPaths.testConfigPath); + const excludedTestCases = getExcludedTestCases(libraryName, testConfig.testCasesToExclude); + + if (!testCases) { + testCases = getTestCases( + cqlPaths.testDirectoryPath, + libraryName, + Array.from(excludedTestCases.keys()), + ); + } + + // We didn't find any test cases, so we'll just execute an empty one + if (testCases.length === 0) { + testCases.push({}); + } + + const cqlMessage = `CQL: ${cqlPaths.libraryDirectoryPath.fsPath}`; + const terminologyMessage = fs.existsSync(cqlPaths.terminologyDirectoryPath.fsPath) + ? `Terminology: ${cqlPaths.terminologyDirectoryPath.fsPath}` + : `No terminology found at ${cqlPaths.terminologyDirectoryPath.fsPath}. Evaluation may fail if terminology is required.`; + + let testMessage = []; + if (testCases.length == 1 && testCases[0].name === null) { + testMessage.push( + `No data found at ${cqlPaths.testDirectoryPath.fsPath}. Evaluation may fail if data is required.`, + ); + } else { + testMessage.push(`Test cases:`); + for (let p of testCases) { + testMessage.push(`${p.name} - ${p.path?.fsPath}`); + } + } + + if (excludedTestCases.size > 0) { + testMessage.push('\nExcluded test cases:'); + for (const [testCase, reason] of excludedTestCases.entries()) { + testMessage.push(`${testCase} - ${reason}`); + } + } + + await insertLineAtEnd(textEditor, `${cqlMessage}`); + await insertLineAtEnd(textEditor, `${terminologyMessage}`); + await insertLineAtEnd(textEditor, `${testMessage.join('\n')}\n`); + + const startExecution = Date.now(); + + let fhirVersion = getFhirVersion(); + if (!fhirVersion) { + fhirVersion = 'R4'; + window.showInformationMessage('Unable to determine version of FHIR used. Defaulting to R4.'); + } + + const result: string | undefined = await executeCql( + cqlFileUri, + testCases, + cqlPaths.terminologyDirectoryPath, + fhirVersion, + cqlPaths.optionsPath, + cqlPaths.projectDirectoryPath, + ); + + const endExecution = Date.now(); + + await insertLineAtEnd(textEditor, result!); + await insertLineAtEnd( + textEditor, + `elapsed: ${((endExecution - startExecution) / 1000).toString()} seconds`, + ); +} + +function getCqlPaths(): CqlPaths | undefined { + const projectDirectoryPath = getWorkspacePath(); //workspace.getWorkspaceFolder(cqlFileUri)!.uri; + if (!projectDirectoryPath) { + window.showErrorMessage('Unable to determine path to project root.'); + return; + } + const libraryDirectoryPath = Utils.resolvePath(projectDirectoryPath, 'input', 'cql'); + const testDirectoryPath = Utils.resolvePath(projectDirectoryPath, 'input', 'tests'); + return { + projectDirectoryPath: projectDirectoryPath, + libraryDirectoryPath: libraryDirectoryPath, + optionsPath: Utils.resolvePath(libraryDirectoryPath, 'cql-options.json'), + resultDirectoryPath: Utils.resolvePath(testDirectoryPath, 'results'), + terminologyDirectoryPath: Utils.resolvePath( + projectDirectoryPath, + 'input', + 'vocabulary', + 'valueset', + ), + testConfigPath: Utils.resolvePath(testDirectoryPath, 'config.json'), + testDirectoryPath: testDirectoryPath, + }; +} + +function getExcludedTestCases( + libraryName: string, + testCasesToExclude: TestCaseExclusion[], +): Map { + let excludedTestCases = new Map(); + for (let excludedTestCase of testCasesToExclude) { + if (excludedTestCase.library == libraryName) { + excludedTestCases.set(excludedTestCase.testCase, excludedTestCase.reason); + } + } + return excludedTestCases; +} + +function getExecArgs( + libraryDirectory: Uri, + libraryName: string, + modelPath: Uri | null, + terminologyPath: Uri | null, + contextValue: string | null, + measurementPeriod: string, +): string[] { + // TODO: One day we might support other models and contexts + const modelType = 'FHIR'; + const contextType = 'Patient'; + + let args: string[] = []; + args.push(`-ln=${libraryName}`, `-lu=${libraryDirectory}`); + + if (modelPath) { + args.push(`-m=${modelType}`, `-mu=${modelPath}`); + } + + if (terminologyPath) { + args.push(`-t=${terminologyPath}`); + } + + if (contextValue) { + args.push(`-c=${contextType}`, `-cv=${contextValue}`); + } + + if (measurementPeriod && measurementPeriod !== '') { + args.push(`-p=${libraryName}."Measurement Period"`, `-pv=${measurementPeriod}`); + } + + return args; +} + +function getFhirVersion(): string | null { + const fhirVersionRegex = /using (FHIR|"FHIR") version '(\d(.|\d)*)'/; + const matches = window.activeTextEditor!.document.getText().match(fhirVersionRegex); + if (matches && matches.length > 2) { + const version = matches[2]; + if (version.startsWith('2')) { + return 'DSTU2'; + } else if (version.startsWith('3')) { + return 'DSTU3'; + } else if (version.startsWith('4')) { + return 'R4'; + } else if (version.startsWith('5')) { + return 'R5'; + } + } + + return null; +} + +function getLibraries(libraryPath: Uri): Array { + if (!fs.existsSync(libraryPath.fsPath)) { + log.warn(`unable to find libraries @ ${libraryPath.fsPath}`); + return []; + } + return glob + .sync(libraryPath.fsPath + `/**/*.cql`) + .filter(f => fs.statSync(f).isFile()) + .map(f => Uri.file(f)); +} + +/** + * Get the test cases to execute + * @param testPath the root path to look for test cases + * @returns a list of test cases to execute + */ +function getTestCases( + testPath: Uri, + libraryName: string, + testCasesToExclude: string[], +): Array { + if (!fs.existsSync(testPath.fsPath)) { + return []; + } + + let testCases: TestCase[] = []; + let directories = glob + .sync(testPath.fsPath + `/**/${libraryName}`) + .filter(d => fs.statSync(d).isDirectory()); + for (let dir of directories) { + let cases = fs + .readdirSync(dir) + .filter(d => fs.statSync(path.join(dir, d)).isDirectory() && !testCasesToExclude.includes(d)); + for (let c of cases) { + testCases.push({ name: c, path: Uri.file(path.join(dir, c)) }); + } + } + + return testCases; +} + +function getWorkspacePath(): Uri | undefined { + if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { + return workspace.workspaceFolders[0].uri; + } + return undefined; +} + +async function insertLineAtEnd(textEditor: TextEditor, text: string) { + const document = textEditor.document; + await textEditor.edit(editBuilder => { + editBuilder.insert(new Position(document.lineCount, 0), text + '\n'); + }); +} + +function loadTestConfig(testConfigPath: Uri): TestConfig { + try { + const jsonString = fs.readFileSync(testConfigPath.fsPath, 'utf-8'); + // Cast the parsed object to the User interface + return JSON.parse(jsonString) as TestConfig; + } catch (error) { + log.error('Error reading/parsing config file', error); + return { testCasesToExclude: [] }; + } +} diff --git a/src/commands/log-files.ts b/src/commands/log-files.ts new file mode 100644 index 0000000..a469e7e --- /dev/null +++ b/src/commands/log-files.ts @@ -0,0 +1,90 @@ +import { glob } from 'glob'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { commands, ExtensionContext, Uri, ViewColumn, window, workspace } from 'vscode'; +import { Commands } from '../commands/commands'; +import * as log from '../log-services/logger'; + +export function register(context: ExtensionContext, storageUri: Uri): void { + const workspacePath = path.resolve(storageUri.fsPath + '/cql_ls_ws'); + + context.subscriptions.push( + commands.registerCommand(Commands.OPEN_SERVER_LOG, (column: ViewColumn) => + openServerLogFile(workspacePath, column), + ), + commands.registerCommand(Commands.OPEN_CLIENT_LOG, (column: ViewColumn) => + openClientLogFile(column), + ), + commands.registerCommand(Commands.OPEN_LOGS, () => openLogs()), + ); +} + +async function openClientLogFile(column: ViewColumn = ViewColumn.Active): Promise { + const logFileDetails = log.getLogFileDetails(); + if (!logFileDetails) { + const message = 'Could not open CQL extension log file. Log file path has not been configured.'; + log.warn(message); + window.showWarningMessage(message); + return false; + } + + let logFile = ''; + try { + const files = await glob(`${logFileDetails.baseName}.*`, { + cwd: logFileDetails.directory, + posix: true, + }); + + if (files && files.length > 0) { + files.sort(); + const newestFile = files[files.length - 1]; + logFile = path.resolve(logFileDetails.directory, newestFile.toString()); + } + } catch (error) { + log.error('Glob error while looking for client logs:', error); + } + + return await openLogFile(logFile, 'Could not open CQL extension log file', column); +} + +async function openLogs() { + await commands.executeCommand(Commands.OPEN_CLIENT_LOG, ViewColumn.One); + await commands.executeCommand(Commands.OPEN_SERVER_LOG, ViewColumn.Two); +} + +function openLogFile( + logFile: string, + openingFailureWarning: string, + column: ViewColumn = ViewColumn.Active, +): Thenable { + if (!fs.existsSync(logFile)) { + log.warn(openingFailureWarning); + return window.showWarningMessage(openingFailureWarning).then(() => false); + } + + return workspace + .openTextDocument(logFile) + .then( + doc => { + if (!doc) { + return false; + } + return window.showTextDocument(doc, column).then(editor => !!editor); + }, + () => false, + ) + .then(didOpen => { + if (!didOpen) { + window.showWarningMessage(openingFailureWarning); + } + return didOpen; + }); +} + +function openServerLogFile( + workspacePath: string, + column: ViewColumn = ViewColumn.Active, +): Thenable { + const serverLogFile = path.join(workspacePath, '.metadata', '.log'); + return openLogFile(serverLogFile, 'Could not open CQL Language Server log file', column); +} diff --git a/src/commands/view-elm.ts b/src/commands/view-elm.ts new file mode 100644 index 0000000..d5be8f2 --- /dev/null +++ b/src/commands/view-elm.ts @@ -0,0 +1,27 @@ +import { commands, ExtensionContext, Uri, window, workspace } from 'vscode'; +import { getElm } from '../cql-service/cqlService.getElm'; +import * as log from '../log-services/logger'; +import { Commands } from './commands'; + +export function register(context: ExtensionContext): void { + context.subscriptions.push( + commands.registerCommand(Commands.VIEW_ELM_COMMAND_XML, async (uri: Uri) => { + viewElm(uri, 'xml'); + }), + commands.registerCommand(Commands.VIEW_ELM_COMMAND_JSON, async (uri: Uri) => { + viewElm(uri, 'json'); + }), + ); +} + +export async function viewElm(cqlFileUri: Uri, elmType: 'xml' | 'json' = 'xml') { + try { + log.debug(`attempting to get ELM from [${cqlFileUri}] as ${elmType}`); + const elm: string = await getElm(cqlFileUri, elmType); + workspace + .openTextDocument({ language: elmType, content: elm }) + .then(t => window.showTextDocument(t)); + } catch (error) { + window.showErrorMessage(`Error while converting ${cqlFileUri.fsPath} to ELM. err: ${error}`); + } +} diff --git a/src/cql-language-server/cqlLanguageClient.ts b/src/cql-language-server/cqlLanguageClient.ts new file mode 100644 index 0000000..3938f00 --- /dev/null +++ b/src/cql-language-server/cqlLanguageClient.ts @@ -0,0 +1,196 @@ +import { commands, ExtensionContext, window } from 'vscode'; +import { + CancellationToken, + ConfigurationParams, + ConfigurationRequest, + ExecuteCommandParams, + ExecuteCommandRequest, + LanguageClientOptions, + MessageType, + State, + StateChangeEvent, +} from 'vscode-languageclient'; +import { LanguageClient } from 'vscode-languageclient/node'; +import { Commands } from '../commands/commands'; +import { ClientStatus } from '../extension.api'; +import { RequirementsData } from '../java-support/requirements'; +import * as log from '../log-services/logger'; +import { + ActionableNotification, + ExecuteClientCommandRequest, + ProgressReportNotification, +} from '../protocol'; +import { statusBar } from '../statusBar'; +import { prepareExecutable } from './languageServerStarter'; + +export class CqlLanguageClient { + private languageClient: LanguageClient | undefined; + private status: ClientStatus = ClientStatus.Uninitialized; + extensionName = 'Language Support for CQL'; + + public async initialize( + context: ExtensionContext, + requirements: RequirementsData, + clientOptions: LanguageClientOptions, + workspacePath: string, + ): Promise { + if (this.status !== ClientStatus.Uninitialized) { + return; + } + + const serverOptions = prepareExecutable(requirements, context, workspacePath); + // Create the language client and start the client. + this.languageClient = new LanguageClient( + 'cql', + this.extensionName, + serverOptions, + clientOptions, + ); + + context.subscriptions.push( + this.languageClient.onDidChangeState((e: StateChangeEvent) => { + log.info( + `CqlLanguageClient's internal LanguageClient state changed from ${State[e.oldState]} to ${State[e.newState]}`, + ); + }), + ); + + this.languageClient.onReady().then(() => { + //log.info('language client is ready'); + this.status = ClientStatus.Started; + // this.languageClient.onNotification(StatusNotification.type, (report) => { + // switch (report.type) { + // case 'ServiceReady': + // break; + // case 'Started': + // this.status = ClientStatus.Started; + // statusBar.setReady(); + // break; + // case 'Error': + // this.status = ClientStatus.Error; + // statusBar.setError(); + // break; + // case 'Starting': + // case 'Message': + // // message goes to progress report instead + // break; + // } + // statusBar.updateTooltip(report.message); + // }); + + this.languageClient!.onNotification(ProgressReportNotification.type, _progress => { + // TODO: Support for long-running tasks + }); + + this.languageClient!.onNotification(ActionableNotification.type, notification => { + const titles = notification.commands!.map(a => a.title); + let show = null; + switch (notification.severity) { + case MessageType.Log: + logNotification(notification.message); + break; + case MessageType.Info: + show = window.showInformationMessage; + break; + case MessageType.Warning: + show = window.showWarningMessage; + break; + case MessageType.Error: + show = window.showErrorMessage; + break; + } + if (!show) { + return; + } + + show(notification.message, ...titles).then((selection: string | undefined) => { + for (const action of notification.commands!) { + if (action.title === selection) { + const args: any[] = action.arguments ? action.arguments : []; + commands.executeCommand(action.command, ...args); + break; + } + } + + return null; + }); + }); + + this.languageClient!.onRequest(ExecuteClientCommandRequest.type, params => { + return commands.executeCommand(params.command, ...params.arguments!); + }); + + this.languageClient!.onRequest(ConfigurationRequest.type, (_params: ConfigurationParams) => { + // TODO: This is a request for workspace configuration. In the context of the IG + // this ought to be the cql-options file at least. + + return null; + }); + + // TODO: Set this once we have the initialization signal from the LS. + statusBar.setReady(); + }); + + //this.registerCommands(context); + this.status = ClientStatus.Initialized; + } + + private registerCommands(context: ExtensionContext): void { + context.subscriptions.push( + commands.registerCommand(Commands.OPEN_OUTPUT, () => + this.languageClient!.outputChannel.show(), + ), + ); + } + + public async start() { + if (this.languageClient && this.status === ClientStatus.Initialized) { + //log.debug('attempting to start language client'); + await this.languageClient.start(); + this.status = ClientStatus.Starting; + } + } + + public async stop() { + if (this.languageClient) { + //log.debug('attempting to stop language client'); + await this.languageClient.stop(); + this.status = ClientStatus.Stopping; + } + } + + public getClient(): LanguageClient { + return this.languageClient!; + } + + public getClientStatus(): ClientStatus { + return this.status; + } +} + +function logNotification(message: string) { + return new Promise(() => { + log.info(message); + }); +} + +export const cqlLanguageClientInstance: CqlLanguageClient = new CqlLanguageClient(); + +export async function sendRequest( + command: string, + args: any[], + token: CancellationToken | undefined = undefined, +): Promise { + const params: ExecuteCommandParams = { + command, + arguments: args, + }; + if (token) { + return await cqlLanguageClientInstance + .getClient() + .sendRequest(ExecuteCommandRequest.type, params, token); + } + return await cqlLanguageClientInstance + .getClient() + .sendRequest(ExecuteCommandRequest.type, params); +} diff --git a/src/languageServerStarter.ts b/src/cql-language-server/languageServerStarter.ts similarity index 88% rename from src/languageServerStarter.ts rename to src/cql-language-server/languageServerStarter.ts index 1172a8e..3578011 100644 --- a/src/languageServerStarter.ts +++ b/src/cql-language-server/languageServerStarter.ts @@ -6,8 +6,8 @@ import { StreamInfo, TransportKind, } from 'vscode-languageclient/node'; -import { logger } from './log'; -import { RequirementsData } from './requirements'; +import { RequirementsData } from '../java-support/requirements'; +import * as log from '../log-services/logger'; import { ExtensionContext } from 'vscode'; @@ -17,6 +17,33 @@ const DEBUG = typeof v8debug === 'object' || startedInDebugMode(); export interface TransportExecutable extends Executable { transport: TransportKind; } + +export function awaitServerConnection(port: string): Thenable { + const addr = parseInt(port); + return new Promise((res, rej) => { + const server = net.createServer(stream => { + server.close(); + log.info('CQL LS connection established on port ' + addr); + res({ reader: stream, writer: stream }); + }); + server.on('error', rej); + server.listen(addr, () => { + server.removeListener('error', rej); + log.info('Awaiting CQL LS connection on port ' + addr); + }); + return server; + }); +} + +// If vscode is started with a debug flag this enables the java ls debug as well. +export function hasDebugFlag(args: string[]): boolean { + if (args) { + // See https://nodejs.org/en/docs/guides/debugging-getting-started/ + return args.some(arg => /^--inspect/.test(arg) || /^--debug/.test(arg)); + } + return false; +} + export function prepareExecutable( requirements: RequirementsData, context: ExtensionContext, @@ -28,28 +55,12 @@ export function prepareExecutable( executable.options = options; executable.command = path.resolve(requirements.java_requirements.java_home + '/bin/java'); executable.args = prepareParams(requirements, context, workspacePath); - logger.info(`Starting CQL server with: ${executable.command} ${executable.args.join(' ')}`); + log.info(`Starting CQL server with: ${executable.command} ${executable.args.join(' ')}`); executable.transport = TransportKind.stdio; return executable; } -export function awaitServerConnection(port: string): Thenable { - const addr = parseInt(port); - return new Promise((res, rej) => { - const server = net.createServer(stream => { - server.close(); - logger.info('CQL LS connection established on port ' + addr); - res({ reader: stream, writer: stream }); - }); - server.on('error', rej); - server.listen(addr, () => { - server.removeListener('error', rej); - logger.info('Awaiting CQL LS connection on port ' + addr); - }); - return server; - }); -} function prepareParams( requirements: RequirementsData, @@ -79,12 +90,3 @@ function startedInDebugMode(): boolean { const args = (process as any).execArgv as string[]; return hasDebugFlag(args); } - -// If vscode is started with a debug flag this enables the java ls debug as well. -export function hasDebugFlag(args: string[]): boolean { - if (args) { - // See https://nodejs.org/en/docs/guides/debugging-getting-started/ - return args.some(arg => /^--inspect/.test(arg) || /^--debug/.test(arg)); - } - return false; -} diff --git a/src/cql-service/README.md b/src/cql-service/README.md new file mode 100644 index 0000000..0ddfff8 --- /dev/null +++ b/src/cql-service/README.md @@ -0,0 +1,13 @@ +# CQL Service Modules + +The cqlService modules are intended to be the link between the VSCode extension and the external services that handle CQL operations. + +Currently, CQL operations are passed through the CQL Language Server(java) via the cqlLanguageClient. +Future plans intent to move the CQL operations to a JS based library(s) which will remove the need for a CQL Language Server. + +_Note: There should be no UI operations in these modules, those are 'upstream' functions. Limit code in these modules to dealing with +interacting with external services/libraries only._ + +_Note: It is acceptable to use the cqlLanguageClient sendRequest function to handle the REST operations needed to interact with an +external Language Server. The communication between the extension and the Language Server is an implementation detail that +only clutters the `business logic` of cql operations._ diff --git a/src/cql-service/cqlService.executeCql.ts b/src/cql-service/cqlService.executeCql.ts new file mode 100644 index 0000000..7174089 --- /dev/null +++ b/src/cql-service/cqlService.executeCql.ts @@ -0,0 +1,103 @@ +import * as fs from 'fs'; +import path from 'node:path'; +import { Uri } from 'vscode'; +import { Commands } from '../commands/commands'; +import { sendRequest } from '../cql-language-server/cqlLanguageClient'; + +export interface TestCase { + name?: string; + path?: Uri; +} + +export interface TestCaseExclusion { + library: string; + testCase: string; + reason: string; +} + +export interface TestConfig { + testCasesToExclude: TestCaseExclusion[]; +} + +export async function executeCql( + cqlFileUri: Uri, + testCases: Array, + terminologyUri: Uri, + fhirVersion: string, + optionsPath: Uri, + rootDir: Uri, + contextValue?: string, + measurementPeriod?: string, +): Promise { + let testCasesArgs: string[] = []; + for (let testCase of testCases) { + testCasesArgs.push( + ...getExecArgs( + cqlFileUri, + testCase.path, + terminologyUri, + contextValue ?? testCase.name, + measurementPeriod, + ), + ); + } + + let operationArgs = getCqlCommandArgs(fhirVersion, optionsPath, rootDir); + operationArgs.push(...testCasesArgs); + return await sendRequest(Commands.EXECUTE_CQL, operationArgs); +} + +function getCqlCommandArgs(fhirVersion: string, optionsPath: Uri, rootDir: Uri): string[] { + const args = ['cql']; + + args.push(`-fv=${fhirVersion}`); + + if (optionsPath && fs.existsSync(optionsPath.fsPath)) { + args.push(`-op=${optionsPath}`); + } + + if (rootDir) { + args.push(`-rd=${rootDir}`); + } + + return args; +} + +function getExecArgs( + cqlFileUri: Uri, + testCaseUri?: Uri, + terminologyUri?: Uri, + contextValue?: string, + measurementPeriod?: string, +): string[] { + // TODO: One day we might support other models and contexts + const modelType = 'FHIR'; + const contextType = 'Patient'; + + let args: string[] = []; + args.push( + `-ln=${path.basename(cqlFileUri.fsPath, '.cql')}`, + `-lu=${Uri.file(path.dirname(cqlFileUri.fsPath))}`, + ); + + if (testCaseUri) { + args.push(`-m=${modelType}`, `-mu=${testCaseUri}`); + } + + if (terminologyUri) { + args.push(`-t=${terminologyUri}`); + } + + if (contextValue) { + args.push(`-c=${contextType}`, `-cv=${contextValue}`); + } + + if (measurementPeriod && measurementPeriod !== '') { + args.push( + `-p=${path.basename(cqlFileUri.fsPath)}."Measurement Period"`, + `-pv=${measurementPeriod}`, + ); + } + + return args; +} diff --git a/src/cql-service/cqlService.getElm.ts b/src/cql-service/cqlService.getElm.ts new file mode 100644 index 0000000..f3449d7 --- /dev/null +++ b/src/cql-service/cqlService.getElm.ts @@ -0,0 +1,7 @@ +import { Uri } from 'vscode'; +import { Commands } from '../commands/commands'; +import { sendRequest } from '../cql-language-server/cqlLanguageClient'; + +export async function getElm(cqlFileUri: Uri, elmType: 'xml' | 'json'): Promise { + return await sendRequest(Commands.VIEW_ELM, [cqlFileUri.toString(), elmType]); +} diff --git a/src/cqlLanguageClient.ts b/src/cqlLanguageClient.ts deleted file mode 100644 index e6da2f4..0000000 --- a/src/cqlLanguageClient.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { commands, ExtensionContext, Uri, window, workspace } from "vscode"; -import { - ConfigurationParams, - ConfigurationRequest, - LanguageClientOptions, - MessageType, -} from "vscode-languageclient"; -import { LanguageClient } from "vscode-languageclient/node"; -import { Commands } from "./commands"; -import { executeCQLFile } from "./executeCql"; -import { ClientStatus } from "./extension.api"; -import { prepareExecutable } from "./languageServerStarter"; -import { logger } from "./log"; -import { - ActionableNotification, - ExecuteClientCommandRequest, - ProgressReportNotification, -} from "./protocol"; -import { RequirementsData } from "./requirements"; -import { statusBar } from "./statusBar"; - -const extensionName = "Language Support for CQL"; - -export class CqlLanguageClient { - private languageClient: LanguageClient | undefined; - private status: ClientStatus = ClientStatus.Uninitialized; - - public async initialize( - context: ExtensionContext, - requirements: RequirementsData, - clientOptions: LanguageClientOptions, - workspacePath: string, - ): Promise { - if (this.status !== ClientStatus.Uninitialized) { - return; - } - - const serverOptions = prepareExecutable( - requirements, - context, - workspacePath, - ); - // Create the language client and start the client. - this.languageClient = new LanguageClient( - "cql", - extensionName, - serverOptions, - clientOptions, - ); - - this.languageClient.onReady().then(() => { - this.status = ClientStatus.Started; - // this.languageClient.onNotification(StatusNotification.type, (report) => { - // switch (report.type) { - // case 'ServiceReady': - // break; - // case 'Started': - // this.status = ClientStatus.Started; - // statusBar.setReady(); - // break; - // case 'Error': - // this.status = ClientStatus.Error; - // statusBar.setError(); - // break; - // case 'Starting': - // case 'Message': - // // message goes to progress report instead - // break; - // } - // statusBar.updateTooltip(report.message); - // }); - - this.languageClient!.onNotification( - ProgressReportNotification.type, - (_progress) => { - // TODO: Support for long-running tasks - }, - ); - - this.languageClient!.onNotification( - ActionableNotification.type, - (notification) => { - const titles = notification.commands!.map((a) => a.title); - let show = null; - switch (notification.severity) { - case MessageType.Log: - logNotification(notification.message); - break; - case MessageType.Info: - show = window.showInformationMessage; - break; - case MessageType.Warning: - show = window.showWarningMessage; - break; - case MessageType.Error: - show = window.showErrorMessage; - break; - } - if (!show) { - return; - } - - show(notification.message, ...titles).then( - (selection: string | undefined) => { - for (const action of notification.commands!) { - if (action.title === selection) { - const args: any[] = action.arguments ? action.arguments : []; - commands.executeCommand(action.command, ...args); - break; - } - } - - return null; - }, - ); - }, - ); - - this.languageClient!.onRequest( - ExecuteClientCommandRequest.type, - (params) => { - return commands.executeCommand(params.command, ...params.arguments!); - }, - ); - - this.languageClient!.onRequest( - ConfigurationRequest.type, - (_params: ConfigurationParams) => { - // TODO: This is a request for workspace configuration. In the context of the IG - // this ought to be the cql-options file at least. - - return null; - }, - ); - - // TODO: Set this once we have the initialization signal from the LS. - statusBar.setReady(); - }); - - this.registerCommands(context); - this.status = ClientStatus.Initialized; - } - - private registerCommands(context: ExtensionContext): void { - context.subscriptions.push( - commands.registerCommand(Commands.OPEN_OUTPUT, () => - this.languageClient!.outputChannel.show(), - ), - ); - - context.subscriptions.push( - commands.registerCommand( - Commands.VIEW_ELM_COMMAND_XML, - async (uri: Uri) => { - const elmAsXml: string = await (( - commands.executeCommand( - Commands.EXECUTE_WORKSPACE_COMMAND, - Commands.VIEW_ELM, - uri.toString(), - "xml", - ) - )); - workspace - .openTextDocument({ language: "xml", content: elmAsXml }) - .then((t) => window.showTextDocument(t)); - }, - ), - commands.registerCommand( - Commands.VIEW_ELM_COMMAND_JSON, - async (uri: Uri) => { - const elmAsJson: string = await (( - commands.executeCommand( - Commands.EXECUTE_WORKSPACE_COMMAND, - Commands.VIEW_ELM, - uri.toString(), - "json", - ) - )); - workspace - .openTextDocument({ language: "json", content: elmAsJson }) - .then((t) => window.showTextDocument(t)); - }, - ), - ); - - context.subscriptions.push( - commands.registerCommand( - Commands.EXECUTE_CQL_COMMAND, - async (uri: Uri) => { - await executeCQLFile(uri); - }, - ), - ); - } - - public start(): void { - if (this.languageClient && this.status === ClientStatus.Initialized) { - this.languageClient.start(); - this.status = ClientStatus.Starting; - } - } - - public stop() { - if (this.languageClient) { - this.languageClient.stop(); - this.status = ClientStatus.Stopping; - } - } - - public getClient(): LanguageClient { - return this.languageClient!; - } - - public getClientStatus(): ClientStatus { - return this.status; - } -} - -function logNotification(message: string) { - return new Promise(() => { - logger.verbose(message); - }); -} diff --git a/src/executeCql.ts b/src/executeCql.ts deleted file mode 100644 index eaf30d6..0000000 --- a/src/executeCql.ts +++ /dev/null @@ -1,258 +0,0 @@ -import * as fs from 'fs'; -import * as fse from 'fs-extra'; -import { glob } from 'glob'; -import path from 'path'; -import { Position, TextEditor, Uri, commands, window, workspace } from 'vscode'; -import { Utils } from 'vscode-uri'; -import { Commands } from './commands'; - -interface TestCase { - name: string | null; - path: Uri | null; -} - -interface TestCaseExclusion { - library: string; - testCase: string; - reason: string; -} - -interface TestConfig { - testCasesToExclude: TestCaseExclusion[]; -} - -async function executeCQL(textEditor: TextEditor, operationArgs: string[]) { - const startExecution = Date.now(); - const result: string | undefined = await commands.executeCommand( - Commands.EXECUTE_WORKSPACE_COMMAND, - Commands.EXECUTE_CQL, - ...operationArgs, - ); - const endExecution = Date.now(); - - await insertLineAtEnd(textEditor, result!); - await insertLineAtEnd( - textEditor, - `elapsed: ${((endExecution - startExecution) / 1000).toString()} seconds`, - ); -} - -// NOTE: This is not the intended future state of executing CQL. -// There's a CQL debug server under development that will replace this. -export async function executeCQLFile(uri: Uri): Promise { - if (!fs.existsSync(uri.fsPath)) { - window.showInformationMessage('No library content found. Please save before executing.'); - return; - } - - const libraryDirectory = Utils.dirname(uri); - const libraryName = Utils.basename(uri).replace('.cql', '').split('-')[0]; - const projectPath = workspace.getWorkspaceFolder(uri)!.uri; - - // todo: make this a setting - let terminologyPath: Uri = Utils.resolvePath(projectPath, 'input', 'vocabulary', 'valueset'); - - let fhirVersion = getFhirVersion(); - if (!fhirVersion) { - fhirVersion = 'R4'; - window.showInformationMessage('Unable to determine version of FHIR used. Defaulting to R4.'); - } - - const rootDir = Utils.resolvePath(projectPath); - const optionsPath = Utils.resolvePath(libraryDirectory, 'cql-options.json'); - const testPath = Utils.resolvePath(projectPath, 'input', 'tests'); - const resultPath = Utils.resolvePath(testPath, 'results'); - - const outputPath = Utils.resolvePath(resultPath, `${libraryName}.txt`); - fse.ensureFileSync(outputPath.fsPath); - const textDocument = await workspace.openTextDocument(outputPath); - const textEditor = await window.showTextDocument(textDocument); - - const testConfigPath = Utils.resolvePath(testPath, 'config.json'); - const testConfig = loadTestConfig(testConfigPath); - const excludedTestCases = getExcludedTestCases(libraryName, testConfig.testCasesToExclude); - - let testCasesArgs: string[] = []; - let testPaths = getTestPaths(testPath, libraryName, Array.from(excludedTestCases.keys())); - - // We didn't find any test cases, so we'll just execute an empty one - if (testPaths.length === 0) { - testPaths.push({ name: null, path: null }); - } - - const measurementPeriod = ''; - for (let p of testPaths) { - testCasesArgs.push( - ...getExecArgs( - libraryDirectory, - libraryName, - p.path, - terminologyPath, - p.name, - measurementPeriod, - ), - ); - } - - const cqlMessage = `CQL: ${libraryDirectory.fsPath}`; - const terminologyMessage = fs.existsSync(terminologyPath.fsPath) - ? `Terminology: ${terminologyPath.fsPath}` - : `No terminology found at ${terminologyPath.fsPath}. Evaluation may fail if terminology is required.`; - - let testMessage = []; - if (testPaths.length == 1 && testPaths[0].name === null) { - testMessage.push( - `No data found at ${testPath.fsPath}. Evaluation may fail if data is required.`, - ); - } else { - testMessage.push(`Test cases:`); - for (let p of testPaths) { - testMessage.push(`${p.name} - ${p.path?.fsPath}`); - } - } - - if (excludedTestCases.size > 0) { - testMessage.push('\nExcluded test cases:'); - for (const [testCase, reason] of excludedTestCases.entries()) { - testMessage.push(`${testCase} - ${reason}`); - } - } - - await insertLineAtEnd(textEditor, `${cqlMessage}`); - await insertLineAtEnd(textEditor, `${terminologyMessage}`); - await insertLineAtEnd(textEditor, `${testMessage.join('\n')}\n`); - - let operationArgs = getCqlCommandArgs(fhirVersion, optionsPath, rootDir); - operationArgs.push(...testCasesArgs); - await executeCQL(textEditor, operationArgs); -} - -function getCqlCommandArgs(fhirVersion: string, optionsPath: Uri, rootDir: Uri): string[] { - const args = ['cql']; - - args.push(`-fv=${fhirVersion}`); - - if (optionsPath && fs.existsSync(optionsPath.fsPath)) { - args.push(`-op=${optionsPath}`); - } - - if (rootDir) { - args.push(`-rd=${rootDir}`); - } - - return args; -} - -function getExcludedTestCases( - libraryName: string, - testCasesToExclude: TestCaseExclusion[], -): Map { - let excludedTestCases = new Map(); - for (let excludedTestCase of testCasesToExclude) { - if (excludedTestCase.library == libraryName) { - excludedTestCases.set(excludedTestCase.testCase, excludedTestCase.reason); - } - } - return excludedTestCases; -} - -function getExecArgs( - libraryDirectory: Uri, - libraryName: string, - modelPath: Uri | null, - terminologyPath: Uri | null, - contextValue: string | null, - measurementPeriod: string, -): string[] { - // TODO: One day we might support other models and contexts - const modelType = 'FHIR'; - const contextType = 'Patient'; - - let args: string[] = []; - args.push(`-ln=${libraryName}`, `-lu=${libraryDirectory}`); - - if (modelPath) { - args.push(`-m=${modelType}`, `-mu=${modelPath}`); - } - - if (terminologyPath) { - args.push(`-t=${terminologyPath}`); - } - - if (contextValue) { - args.push(`-c=${contextType}`, `-cv=${contextValue}`); - } - - if (measurementPeriod && measurementPeriod !== '') { - args.push(`-p=${libraryName}."Measurement Period"`, `-pv=${measurementPeriod}`); - } - - return args; -} - -function getFhirVersion(): string | null { - const fhirVersionRegex = /using (FHIR|"FHIR") version '(\d(.|\d)*)'/; - const matches = window.activeTextEditor!.document.getText().match(fhirVersionRegex); - if (matches && matches.length > 2) { - const version = matches[2]; - if (version.startsWith('2')) { - return 'DSTU2'; - } else if (version.startsWith('3')) { - return 'DSTU3'; - } else if (version.startsWith('4')) { - return 'R4'; - } else if (version.startsWith('5')) { - return 'R5'; - } - } - - return null; -} - -/** - * Get the test cases to execute - * @param testPath the root path to look for test cases - * @returns a list of test cases to execute - */ -function getTestPaths( - testPath: Uri, - libraryName: string, - testCasesToExclude: string[], -): TestCase[] { - if (!fs.existsSync(testPath.fsPath)) { - return []; - } - - let testCases: TestCase[] = []; - let directories = glob - .sync(testPath.fsPath + `/**/${libraryName}`) - .filter(d => fs.statSync(d).isDirectory()); - for (let dir of directories) { - let cases = fs - .readdirSync(dir) - .filter(d => fs.statSync(path.join(dir, d)).isDirectory() && !testCasesToExclude.includes(d)); - for (let c of cases) { - testCases.push({ name: c, path: Uri.file(path.join(dir, c)) }); - } - } - - return testCases; -} - -async function insertLineAtEnd(textEditor: TextEditor, text: string) { - const document = textEditor.document; - await textEditor.edit(editBuilder => { - editBuilder.insert(new Position(document.lineCount, 0), text + '\n'); - }); -} - -function loadTestConfig(testConfigPath: Uri): TestConfig { - try { - const jsonString = fs.readFileSync(testConfigPath.fsPath, 'utf-8'); - // Cast the parsed object to the User interface - return JSON.parse(jsonString) as TestConfig; - } catch (error) { - console.error('Error reading or parsing JSON file:', error); - return { testCasesToExclude: [] }; - } -} diff --git a/src/extension.ts b/src/extension.ts index 09f8211..6754e64 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,29 +1,24 @@ -import * as fs from 'fs'; -import { glob } from 'glob'; -import * as os from 'os'; import * as path from 'path'; -import { ExtensionContext, OutputChannel, ViewColumn, commands, window, workspace } from 'vscode'; +import { commands, ExtensionContext, Uri, window } from 'vscode'; import { - CancellationToken, CloseAction, ErrorAction, ErrorHandler, - ExecuteCommandParams, - ExecuteCommandRequest, LanguageClientOptions, Message, RevealOutputChannelOn, } from 'vscode-languageclient'; -import { Commands } from './commands'; -import { CqlLanguageClient } from './cqlLanguageClient'; +import { Commands } from './commands/commands'; +import { register as registerExecuteCql } from './commands/execute-cql'; +import { register as registerLogCommands } from './commands/log-files'; +import { register as registerViewElmCommand } from './commands/view-elm'; +import { cqlLanguageClientInstance } from './cql-language-server/cqlLanguageClient'; import { ClientStatus } from './extension.api'; -import { initializeLogFile, logger } from './log'; -import * as requirements from './requirements'; +import * as requirements from './java-support/requirements'; +import * as log from './log-services/logger'; import { statusBar } from './statusBar'; -const cqlLanguageClient: CqlLanguageClient = new CqlLanguageClient(); -const extensionName = 'Language Support for CQL'; -let clientLogFile: string; +export const EXTENSION_NAME = 'Language Support for CQL'; export class ClientErrorHandler implements ErrorHandler { private restarts: number[]; @@ -34,30 +29,24 @@ export class ClientErrorHandler implements ErrorHandler { public error(_error: Error, _message: Message, count: number): ErrorAction { if (count && count <= 3) { - logger.error( - `${this.name} server encountered error: ${_message}, ${_error && _error.toString()}`, - ); + log.error(`${this.name} server encountered error: ${_message}`, _error); return ErrorAction.Continue; } - logger.error( - `${this.name} server encountered error and will shut down: ${_message}, ${ - _error && _error.toString() - }`, - ); + log.error(`${this.name} server encountered error and will shut down: ${_message}`, _error); return ErrorAction.Shutdown; } public closed(): CloseAction { this.restarts.push(Date.now()); if (this.restarts.length < 5) { - logger.error(`The ${this.name} server crashed and will restart.`); + log.error(`The ${this.name} server crashed and will restart.`); return CloseAction.Restart; } else { const diff = this.restarts[this.restarts.length - 1] - this.restarts[0]; if (diff <= 3 * 60 * 1000) { const message = `The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`; - logger.error(message); + log.error(message); const action = 'Show logs'; window.showErrorMessage(message, action).then(selection => { if (selection === action) { @@ -67,65 +56,32 @@ export class ClientErrorHandler implements ErrorHandler { return CloseAction.DoNotRestart; } - logger.error(`The ${this.name} server crashed and will restart.`); + log.error(`The ${this.name} server crashed and will restart.`); this.restarts.shift(); return CloseAction.Restart; } } } -export class OutputInfoCollector implements OutputChannel { - private channel: OutputChannel; - - constructor(public name: string) { - this.channel = window.createOutputChannel(this.name); - } - replace(value: string): void { - this.clear(); - this.append(value); - } - - append(value: string): void { - logger.info(value); - this.channel.append(value); - } - - appendLine(value: string): void { - logger.info(value); - this.channel.appendLine(value); - } - - clear(): void { - this.channel.clear(); - } - - show(preserveFocus?: boolean): void; - show(column?: ViewColumn, preserveFocus?: boolean): void; - show(_column?: any, preserveFocus?: any) { - this.channel.show(preserveFocus); - } - - hide(): void { - this.channel.hide(); - } - - dispose(): void { - this.channel.dispose(); +function getStorageUri(context: ExtensionContext): Uri { + const workspaceStorageUri = context.storageUri; + if (workspaceStorageUri) { + return workspaceStorageUri; + } else { + throw new Error( + 'No workspace storage URI available (e.g., when running an untitled workspace)', + ); } } export function activate(context: ExtensionContext): Promise { - let storagePath = context.storagePath; - if (!storagePath) { - storagePath = getTempWorkspace(); - } - clientLogFile = path.join(storagePath, 'client.log'); - initializeLogFile(clientLogFile); + const storageUri = getStorageUri(context); + const outputChannel = log.initialize(Uri.joinPath(storageUri, 'logs'), EXTENSION_NAME); return requirements .resolveRequirements(context) .catch(error => { - // show error + //log.error(error.message); window.showErrorMessage(error.message, error.label).then(selection => { if (error.label && error.label === selection && error.command) { commands.executeCommand(error.command, error.commandParam); @@ -135,69 +91,34 @@ export function activate(context: ExtensionContext): Promise { throw error; }) .then(async requirements => { - return new Promise(async resolve => { - const workspacePath = path.resolve(storagePath + '/cql_ls_ws'); - // Options to control the language client - const clientOptions: LanguageClientOptions = { - // Register the server for CQL - documentSelector: [ - { scheme: 'file', language: 'cql' }, - { scheme: 'untitled', language: 'cql' }, - ], - revealOutputChannelOn: RevealOutputChannelOn.Warn, // TODO: The Debug output should be handled a different way. - errorHandler: new ClientErrorHandler(extensionName), - initializationFailedHandler: error => { - logger.error( - `Failed to initialize ${extensionName} due to ${error && error.toString()}`, - ); - return true; - }, - outputChannel: new OutputInfoCollector(extensionName), - outputChannelName: extensionName, - }; - - context.subscriptions.push( - commands.registerCommand(Commands.EXECUTE_WORKSPACE_COMMAND, (command, ...rest) => { - let token: CancellationToken | undefined; - let commandArgs: any[] = rest; - if (rest && rest.length && CancellationToken.is(rest[rest.length - 1])) { - token = rest[rest.length - 1]; - commandArgs = rest.slice(0, rest.length - 1); - } - const params: ExecuteCommandParams = { - command, - arguments: commandArgs, - }; - if (token) { - return cqlLanguageClient - .getClient() - .sendRequest(ExecuteCommandRequest.type, params, token); - } else { - return cqlLanguageClient.getClient().sendRequest(ExecuteCommandRequest.type, params); - } - }), - ); - - // Register commands here to make it available even when the language client fails - context.subscriptions.push( - commands.registerCommand(Commands.OPEN_SERVER_LOG, (column: ViewColumn) => - openServerLogFile(workspacePath, column), - ), - ); - - context.subscriptions.push( - commands.registerCommand(Commands.OPEN_CLIENT_LOG, (column: ViewColumn) => - openClientLogFile(clientLogFile, column), - ), - ); - - context.subscriptions.push(commands.registerCommand(Commands.OPEN_LOGS, () => openLogs())); - - context.subscriptions.push(statusBar); - - await startServer(context, requirements, clientOptions, workspacePath); - resolve(); - }); + //log.info('extension activated'); + const workspacePath = path.resolve(storageUri.fsPath + '/cql_ls_ws'); + + // Options to control the language client + const clientOptions: LanguageClientOptions = { + // Register the server for CQL + documentSelector: [ + { scheme: 'file', language: 'cql' }, + { scheme: 'untitled', language: 'cql' }, + ], + revealOutputChannelOn: RevealOutputChannelOn.Warn, // TODO: The Debug output should be handled a different way. + errorHandler: new ClientErrorHandler(EXTENSION_NAME), + initializationFailedHandler: error => { + const message = `Failed to initialize ${EXTENSION_NAME} due to ${error && error.toString()}`; + //log.error(message); + window.showErrorMessage(message, error.label); + return true; + }, + outputChannel: outputChannel, + outputChannelName: EXTENSION_NAME, + }; + + registerExecuteCql(context); + registerLogCommands(context, storageUri); + registerViewElmCommand(context); + context.subscriptions.push(statusBar); + + await startServer(context, requirements, clientOptions, workspacePath); }); } @@ -206,114 +127,24 @@ async function startServer( requirements: requirements.RequirementsData, clientOptions: LanguageClientOptions, workspacePath: string, -) { - if (cqlLanguageClient.getClientStatus() !== ClientStatus.Uninitialized) { +): Promise { + if (cqlLanguageClientInstance.getClientStatus() !== ClientStatus.Uninitialized) { return; } - await cqlLanguageClient.initialize(context, requirements, clientOptions, workspacePath); - cqlLanguageClient.start(); - statusBar.showStatusBar(); -} - -export function deactivate(): void { - cqlLanguageClient.stop(); -} - -function openServerLogFile( - workspacePath: string, - column: ViewColumn = ViewColumn.Active, -): Thenable { - const serverLogFile = path.join(workspacePath, '.metadata', '.log'); - return openLogFile(serverLogFile, 'Could not open CQL Language Server log file', column); -} - -async function openClientLogFile( - logFile: string, - column: ViewColumn = ViewColumn.Active, -): Promise { - const filename = path.basename(logFile); - const dirname = path.dirname(logFile); - try { - const files = await glob(`${filename}.*`, { - cwd: dirname, - posix: true - }); - - if (files && files.length > 0) { - files.sort(); - const newestFile = files[files.length - 1]; - logFile = path.resolve(dirname, newestFile.toString()); - } - } catch (err) { - logger.error('Glob error while looking for client logs:', err); + await cqlLanguageClientInstance.initialize(context, requirements, clientOptions, workspacePath); + await cqlLanguageClientInstance.start(); + statusBar.showStatusBar(); + } catch (error) { + log.error(`Failed to start server: ${error}`); } - - return await openLogFile(logFile, 'Could not open CQL extension log file', column); -} - -async function openLogs() { - await commands.executeCommand(Commands.OPEN_CLIENT_LOG, ViewColumn.One); - await commands.executeCommand(Commands.OPEN_SERVER_LOG, ViewColumn.Two); -} - -function openLogFile( - logFile: string, - openingFailureWarning: string, - column: ViewColumn = ViewColumn.Active, -): Thenable { - if (!fs.existsSync(logFile)) { - return window.showWarningMessage('No log file available').then(() => false); - } - - return workspace - .openTextDocument(logFile) - .then( - doc => { - if (!doc) { - return false; - } - return window.showTextDocument(doc, column).then(editor => !!editor); - }, - () => false, - ) - .then(didOpen => { - if (!didOpen) { - window.showWarningMessage(openingFailureWarning); - } - return didOpen; - }); -} - -function getTempWorkspace() { - return path.resolve(os.tmpdir(), 'vscodesws_' + makeRandomHexString(5)); } -function makeRandomHexString(length: number) { - const chars = [ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '6', - '7', - '8', - '9', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - ]; - let result = ''; - for (let i = 0; i < length; i++) { - const idx = Math.floor(chars.length * Math.random()); - result += chars[idx]; +export async function deactivate(): Promise { + log.info('extension deactivated'); + if (!cqlLanguageClientInstance) { + return undefined; } - return result; + return cqlLanguageClientInstance.stop(); } diff --git a/src/findJavaRuntimes.ts b/src/java-support/findJavaRuntimes.ts similarity index 100% rename from src/findJavaRuntimes.ts rename to src/java-support/findJavaRuntimes.ts diff --git a/src/javaServiceInstaller.ts b/src/java-support/javaServiceInstaller.ts similarity index 96% rename from src/javaServiceInstaller.ts rename to src/java-support/javaServiceInstaller.ts index e9f9f33..ba435ac 100644 --- a/src/javaServiceInstaller.ts +++ b/src/java-support/javaServiceInstaller.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import fetch from 'node-fetch'; import * as path from 'path'; import { ExtensionContext, Progress, ProgressLocation, window } from 'vscode'; -import { ensureExists } from './helpers/file-helpers'; +import { ensureExists } from '../utils/file-utils'; interface MavenCoords { groupId: string; @@ -63,9 +63,7 @@ function getLocalName(coords: MavenCoords): string { function getSearchUrl(coords: MavenCoords): string { const groupIdAsDirectory = coords.groupId.replace(/\./gi, '/'); - return ( - `https://repo1.maven.org/maven2/${groupIdAsDirectory}/${coords.artifactId}/${coords.version}/${getLocalName(coords)}` - ); + return `https://repo1.maven.org/maven2/${groupIdAsDirectory}/${coords.artifactId}/${coords.version}/${getLocalName(coords)}`; } async function installServiceIfMissing(serviceName: string, coords: MavenCoords): Promise { diff --git a/src/requirements.ts b/src/java-support/requirements.ts similarity index 98% rename from src/requirements.ts rename to src/java-support/requirements.ts index d737331..8f9b137 100644 --- a/src/requirements.ts +++ b/src/java-support/requirements.ts @@ -2,7 +2,7 @@ import expandTilde from 'expand-tilde'; import * as fse from 'fs-extra'; import * as path from 'path'; import { ExtensionContext, Uri, env } from 'vscode'; -import { Commands } from './commands'; +import { Commands } from '../commands/commands'; import { JavaRuntime, findJavaHomes, getJavaVersion } from './findJavaRuntimes'; import { getServicePath, installJavaDependencies } from './javaServiceInstaller'; diff --git a/src/log-services/logger.ts b/src/log-services/logger.ts new file mode 100644 index 0000000..ce70cf7 --- /dev/null +++ b/src/log-services/logger.ts @@ -0,0 +1,48 @@ +import { LogOutputChannel, Uri } from 'vscode'; +import { MultiTransportLogger } from './multi-transport-logger'; + +let _logger: MultiTransportLogger; +let _logFilePath: Uri | undefined = undefined; + +/** + * Initializes Winston logger that integrates with VS Code's native logging. + * @param extensionPath The base path for log file storage. + * @param channelName The name visible in the VS Code Output dropdown. + */ +export function initialize(logFilePath: Uri, name: string): LogOutputChannel { + if (!_logger) { + _logFilePath = logFilePath; + _logger = new MultiTransportLogger(name, logFilePath); + } + return _logger; +} + +export function getLogFileDetails(): { directory: string; baseName: string } { + return _logger.getLogFileDetails(); +} + +export function debug(message: string, ...args: any[]): void { + _logger?.debug(message, args); +} + +export function error( + message: string, + error: Error | unknown | undefined = undefined, + ...args: any[] +) { + if (!error) { + _logger?.error(message, args); + } else if (error instanceof Error) { + _logger?.error(`${message} err: ${error.message}`, args); + } else { + _logger?.error(`${message} err: An unknown error occurred`, args); + } +} + +export function info(message: string, ...args: any[]): void { + _logger?.info(message, args); +} + +export function warn(message: string, ...args: any[]): void { + _logger?.warn(message, args); +} diff --git a/src/log-services/multi-transport-logger.ts b/src/log-services/multi-transport-logger.ts new file mode 100644 index 0000000..8f4e011 --- /dev/null +++ b/src/log-services/multi-transport-logger.ts @@ -0,0 +1,115 @@ +import { Event, LogLevel, LogOutputChannel, Uri, window } from 'vscode'; +import { createLogger, format, Logger as WinstonLogger } from 'winston'; +import DailyRotateFile from 'winston-daily-rotate-file'; +import { LogOutputChannelTransport } from 'winston-transport-vscode'; + +export class MultiTransportLogger implements LogOutputChannel { + private readonly _outputChannel: LogOutputChannel; + private readonly _dailyFileTransport: DailyRotateFile; + private readonly _logger: WinstonLogger; + private readonly _logFileBaseName: string; + private readonly _logFileStorageUri: Uri; + + readonly logLevel: LogLevel; + readonly onDidChangeLogLevel: Event; + readonly name: string; + + constructor(name: string, logFileStorageUri: Uri) { + this._outputChannel = window.createOutputChannel(name, { + log: true, + }); + this.logLevel = this._outputChannel.logLevel; + this.name = name.toLowerCase().replace(' ', '-'); + this.onDidChangeLogLevel = this._outputChannel.onDidChangeLogLevel; + + this._logFileStorageUri = logFileStorageUri; + this._logFileBaseName = this.name.toLowerCase().replace(/ /g, '-'); + + this._dailyFileTransport = new DailyRotateFile({ + filename: `${this._logFileBaseName}.log.%DATE%`, + datePattern: 'YYYY-MM-DD', + maxSize: '100k', // 100k max size per file + maxFiles: '7d', // retain logs of the last two days, + dirname: this._logFileStorageUri.fsPath, + extension: '.log', + }); + + this._logger = createLogger({ + level: 'debug', // Default level + format: format.combine( + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + format.errors({ stack: true }), + format.splat(), + format.json(), + ), + transports: [ + new LogOutputChannelTransport({ + outputChannel: this._outputChannel, + }), + this._dailyFileTransport, + ], + }); + } + + getOuptutChannelName(): string { + return this._outputChannel.name; + } + + getLogFileDetails(): { directory: string; baseName: string } { + return { directory: this._logFileStorageUri.fsPath, baseName: this._logFileBaseName }; + } + + trace(message: string, ...args: any[]): void { + this._logger.debug(message, args); + } + + debug(message: string, ...args: any[]): void { + this._logger.debug(message, args); + } + + info(message: string, ...args: any[]): void { + this._logger.info(message, args); + } + + warn(message: string, ...args: any[]): void { + this._logger.warn(message, args); + } + + error(error: string | Error, ...args: any[]): void { + this._logger.error(error); + } + + append(value: string): void { + this.appendLine(value); + } + + appendLine(value: string): void { + const lines = value.split('\n'); + + lines.forEach(line => { + if (line) this._logger.info(line); + }); + } + + replace(value: string): void { + this._outputChannel.replace(value); + } + + clear(): void { + this._outputChannel.clear(); + } + + show(preserveFocus?: unknown): void { + this._outputChannel.show(preserveFocus as boolean); + } + + hide(): void { + this._outputChannel.hide(); + } + + dispose(): void { + // a Winston Logger doesn't have a dispose function, this is needed for a plain outputchannel + // let the Winston Logger manage the outputchannel lifecycle + return; + } +} diff --git a/src/log.ts b/src/log.ts deleted file mode 100644 index c647996..0000000 --- a/src/log.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { createLogger, format } from 'winston'; -import DailyRotateFile from 'winston-daily-rotate-file'; - -export function initializeLogFile(filename: string) { - logger.add( - new DailyRotateFile({ - filename: filename, - datePattern: 'YYYY-MM-DD', - maxSize: '100k', // 100k max size per file - maxFiles: '2d', // retain logs of the last two days - }), - ); -} - -export const logger = createLogger({ - format: format.combine( - format.timestamp({ - format: 'YYYY-MM-DD HH:mm:ss.SSS', - }), - format.prettyPrint(), - ), - transports: [ - // See https://github.com/microsoft/vscode/issues/117327 - // Disable console.log for lsp trace because intense logging will freeze the code render process. - // new transports.Console() - ], -}); diff --git a/src/helpers/file-helpers.ts b/src/utils/file-utils.ts similarity index 100% rename from src/helpers/file-helpers.ts rename to src/utils/file-utils.ts From d778e983becb70523468c01e7d5638ce49a3a24a Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Fri, 20 Feb 2026 12:26:04 -0500 Subject: [PATCH 04/11] hides context-menu only cql options from command palette --- package.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/package.json b/package.json index 45be0b1..0066964 100644 --- a/package.json +++ b/package.json @@ -134,6 +134,24 @@ "when": "editorLangId == cql", "group": "1_cqlactions@2.elm@2" } + ], + "commandPalette": [ + { + "command": "cql.action.executeCql", + "when": "false" + }, + { + "command": "cql.action.executeCql.selectTestCases", + "when": "false" + }, + { + "command": "cql.action.viewElm.xml", + "when": "false" + }, + { + "command": "cql.action.viewElm.json", + "when": "false" + } ] } }, From 26a6c345539e7141330b59d61cacb7f6768bc25f Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Sun, 22 Feb 2026 11:21:01 -0500 Subject: [PATCH 05/11] refactors test cases, adds detail to quickpick select test cases --- package-lock.json | 207 ++++++++++++++++++ package.json | 4 +- .../1111/MeasureReport-9876.json | 45 ++++ src/commands/execute-cql.ts | 93 ++------ src/cql-service/cqlService.executeCql.ts | 16 +- src/model/testCase.ts | 76 +++++++ 6 files changed, 352 insertions(+), 89 deletions(-) create mode 100644 src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/MeasureReport-9876.json create mode 100644 src/model/testCase.ts diff --git a/package-lock.json b/package-lock.json index af860dc..69630e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,9 @@ "find-java-home": "1.2.2", "fs-extra": "^8.1.0", "glob": "^10.5.0", + "jsonpath": "^1.2.1", "lodash": "^4.17.23", + "markdown-to-text": "^0.1.1", "node-fetch": "2.6.7", "pino": "^10.3.1", "tslib": "^2.4.0", @@ -979,6 +981,70 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -1589,6 +1655,17 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonpath": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz", + "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==", + "license": "MIT", + "dependencies": { + "esprima": "1.2.5", + "static-eval": "2.1.1", + "underscore": "1.13.6" + } + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -1708,6 +1785,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-to-text": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/markdown-to-text/-/markdown-to-text-0.1.1.tgz", + "integrity": "sha512-co/J5l8mJ2RK9wD/nQRGwO7JxoeyfvVNtOZll016EdAX2qYkwCWMdtYvJO42b41Ho7GFEJMuly9llf0Nj+ReQw==", + "license": "MIT", + "dependencies": { + "@types/chai": "^4.2.14", + "@types/mocha": "^8.2.0" + } + }, + "node_modules/markdown-to-text/node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "license": "MIT" + }, + "node_modules/markdown-to-text/node_modules/@types/mocha": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==", + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2316,6 +2415,16 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -2333,6 +2442,15 @@ "node": "*" } }, + "node_modules/static-eval": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", + "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", + "license": "MIT", + "dependencies": { + "escodegen": "^2.1.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2551,6 +2669,12 @@ "node": ">=14.17" } }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "license": "MIT" + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -3549,6 +3673,39 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } + }, + "esprima": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==" + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -3972,6 +4129,16 @@ "graceful-fs": "^4.1.6" } }, + "jsonpath": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz", + "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==", + "requires": { + "esprima": "1.2.5", + "static-eval": "2.1.1", + "underscore": "1.13.6" + } + }, "jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -4061,6 +4228,27 @@ "semver": "^7.5.3" } }, + "markdown-to-text": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/markdown-to-text/-/markdown-to-text-0.1.1.tgz", + "integrity": "sha512-co/J5l8mJ2RK9wD/nQRGwO7JxoeyfvVNtOZll016EdAX2qYkwCWMdtYvJO42b41Ho7GFEJMuly9llf0Nj+ReQw==", + "requires": { + "@types/chai": "^4.2.14", + "@types/mocha": "^8.2.0" + }, + "dependencies": { + "@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==" + }, + "@types/mocha": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz", + "integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==" + } + } + }, "math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4468,6 +4656,12 @@ "atomic-sleep": "^1.0.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, "split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -4478,6 +4672,14 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" }, + "static-eval": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", + "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", + "requires": { + "escodegen": "^2.1.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -4627,6 +4829,11 @@ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index 0066964..a1aed54 100644 --- a/package.json +++ b/package.json @@ -199,7 +199,9 @@ "find-java-home": "1.2.2", "fs-extra": "^8.1.0", "glob": "^10.5.0", + "jsonpath": "^1.2.1", "lodash": "^4.17.23", + "markdown-to-text": "^0.1.1", "node-fetch": "2.6.7", "pino": "^10.3.1", "tslib": "^2.4.0", @@ -216,4 +218,4 @@ "tabWidth": 2, "arrowParens": "avoid" } -} \ No newline at end of file +} diff --git a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/MeasureReport-9876.json b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/MeasureReport-9876.json new file mode 100644 index 0000000..354be15 --- /dev/null +++ b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/1111/MeasureReport-9876.json @@ -0,0 +1,45 @@ +{ + "resourceType": "MeasureReport", + "id": "9876", + "meta": { + "profile": [ + "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/test-case-cqfm" + ] + }, + "contained": [ + { + "resourceType": "Parameters", + "id": "6b356ec3-e349-4b6d-8281-10186194ec3c-parameters", + "parameter": [ + { + "name": "subject", + "valueString": "0c76341a-34f1-4d1b-9bbe-5915e00a0818" + } + ] + } + ], + "extension": [ + { + "url": "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-testCaseDescription", + "valueMarkdown": "SimpleMeasure" + } + ], + "modifierExtension": [ + { + "url": "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-isTestCase", + "valueBoolean": true + } + ], + "status": "complete", + "type": "individual", + "measure": "https://vscode-cql/tests/measure/SimpleMeasure", + "period": { + "start": "2026-01-01", + "end": "2026-12-31" + }, + "evaluatedResource": [ + { + "reference": "Patient/1111" + } + ] +} \ No newline at end of file diff --git a/src/commands/execute-cql.ts b/src/commands/execute-cql.ts index 0377fb4..fefd2fb 100644 --- a/src/commands/execute-cql.ts +++ b/src/commands/execute-cql.ts @@ -1,17 +1,21 @@ import * as fse from 'fs-extra'; import { glob } from 'glob'; import * as fs from 'node:fs'; -import * as path from 'node:path'; -import { commands, ExtensionContext, Position, ProgressLocation, TextEditor, Uri, window, workspace } from 'vscode'; +import { + commands, + ExtensionContext, + Position, + ProgressLocation, + TextEditor, + Uri, + window, + workspace, +} from 'vscode'; import { Utils } from 'vscode-uri'; import { Commands } from '../commands/commands'; -import { - executeCql, - TestCase, - TestCaseExclusion, - TestConfig, -} from '../cql-service/cqlService.executeCql'; +import { executeCql } from '../cql-service/cqlService.executeCql'; import * as log from '../log-services/logger'; +import { getTestCases, TestCase, TestCaseExclusion } from '../model/testCase'; interface CqlPaths { libraryDirectoryPath: Uri; @@ -23,6 +27,10 @@ interface CqlPaths { testDirectoryPath: Uri; } +interface TestConfig { + testCasesToExclude: TestCaseExclusion[]; +} + export function register(context: ExtensionContext): void { context.subscriptions.push( commands.registerCommand(Commands.EXECUTE_CQL_COMMAND, async (uri: Uri) => { @@ -107,7 +115,10 @@ export async function selectTestCases(cqlFileUri: Uri): Promise { const namedTestCases = testCases.filter( (testCase): testCase is Required => testCase.name !== undefined, ); - const quickPickItems = namedTestCases.map(testCase => ({ label: testCase.name })); + const quickPickItems = namedTestCases.map(testCase => ({ + label: testCase.name, + detail: testCase.description, // use quickpick detail to get description on 2nd line of quickpick + })); if (quickPickItems.length > 0) { quickPick.items = quickPickItems; @@ -252,40 +263,6 @@ function getExcludedTestCases( return excludedTestCases; } -function getExecArgs( - libraryDirectory: Uri, - libraryName: string, - modelPath: Uri | null, - terminologyPath: Uri | null, - contextValue: string | null, - measurementPeriod: string, -): string[] { - // TODO: One day we might support other models and contexts - const modelType = 'FHIR'; - const contextType = 'Patient'; - - let args: string[] = []; - args.push(`-ln=${libraryName}`, `-lu=${libraryDirectory}`); - - if (modelPath) { - args.push(`-m=${modelType}`, `-mu=${modelPath}`); - } - - if (terminologyPath) { - args.push(`-t=${terminologyPath}`); - } - - if (contextValue) { - args.push(`-c=${contextType}`, `-cv=${contextValue}`); - } - - if (measurementPeriod && measurementPeriod !== '') { - args.push(`-p=${libraryName}."Measurement Period"`, `-pv=${measurementPeriod}`); - } - - return args; -} - function getFhirVersion(): string | null { const fhirVersionRegex = /using (FHIR|"FHIR") version '(\d(.|\d)*)'/; const matches = window.activeTextEditor!.document.getText().match(fhirVersionRegex); @@ -316,36 +293,6 @@ function getLibraries(libraryPath: Uri): Array { .map(f => Uri.file(f)); } -/** - * Get the test cases to execute - * @param testPath the root path to look for test cases - * @returns a list of test cases to execute - */ -function getTestCases( - testPath: Uri, - libraryName: string, - testCasesToExclude: string[], -): Array { - if (!fs.existsSync(testPath.fsPath)) { - return []; - } - - let testCases: TestCase[] = []; - let directories = glob - .sync(testPath.fsPath + `/**/${libraryName}`) - .filter(d => fs.statSync(d).isDirectory()); - for (let dir of directories) { - let cases = fs - .readdirSync(dir) - .filter(d => fs.statSync(path.join(dir, d)).isDirectory() && !testCasesToExclude.includes(d)); - for (let c of cases) { - testCases.push({ name: c, path: Uri.file(path.join(dir, c)) }); - } - } - - return testCases; -} - function getWorkspacePath(): Uri | undefined { if (workspace.workspaceFolders && workspace.workspaceFolders.length > 0) { return workspace.workspaceFolders[0].uri; diff --git a/src/cql-service/cqlService.executeCql.ts b/src/cql-service/cqlService.executeCql.ts index 7174089..feef416 100644 --- a/src/cql-service/cqlService.executeCql.ts +++ b/src/cql-service/cqlService.executeCql.ts @@ -3,21 +3,7 @@ import path from 'node:path'; import { Uri } from 'vscode'; import { Commands } from '../commands/commands'; import { sendRequest } from '../cql-language-server/cqlLanguageClient'; - -export interface TestCase { - name?: string; - path?: Uri; -} - -export interface TestCaseExclusion { - library: string; - testCase: string; - reason: string; -} - -export interface TestConfig { - testCasesToExclude: TestCaseExclusion[]; -} +import { TestCase } from '../model/testCase'; export async function executeCql( cqlFileUri: Uri, diff --git a/src/model/testCase.ts b/src/model/testCase.ts new file mode 100644 index 0000000..8dd5cbb --- /dev/null +++ b/src/model/testCase.ts @@ -0,0 +1,76 @@ +import { glob } from 'glob'; +import * as fs from 'node:fs'; +import path from 'node:path'; +import { Uri } from 'vscode'; + +export interface TestCase { + name?: string; + path?: Uri; + description?: string; +} + +export interface TestCaseExclusion { + library: string; + testCase: string; + reason: string; +} + +/** + * Get the test cases to execute + * @param testPath the root path to look for test cases + * @returns a list of test cases to execute + */ +export function getTestCases( + testPath: Uri, + libraryName: string, + testCasesToExclude: string[], +): Array { + if (!fs.existsSync(testPath.fsPath)) { + return []; + } + + let testCases: TestCase[] = []; + let directories = glob + .sync(testPath.fsPath + `/**/${libraryName}`) + .filter(d => fs.statSync(d).isDirectory()); + for (let dir of directories) { + let cases = fs + .readdirSync(dir) + .filter(d => fs.statSync(path.join(dir, d)).isDirectory() && !testCasesToExclude.includes(d)); + for (let c of cases) { + testCases.push({ + name: c, + path: Uri.file(path.join(dir, c)), + description: getMeasureReportDescription(Uri.file(path.join(dir, c))), + }); + } + } + + return testCases; +} + +const TEST_CASE_DESCRIPTION_URL = + 'http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-testCaseDescription'; + +export function getMeasureReportDescription(testCaseFolderPath: Uri): string | undefined { + if (!fs.existsSync(testCaseFolderPath.fsPath)) { + return undefined; + } + + const measureReportFile = fs + .readdirSync(testCaseFolderPath.fsPath) + .find(f => f.startsWith('MeasureReport')); + + if (!measureReportFile) { + return undefined; + } + + const content = fs.readFileSync(path.join(testCaseFolderPath.fsPath, measureReportFile), 'utf-8'); + const report = JSON.parse(content); + + const extension = ( + report.extension as { url: string; valueMarkdown?: string }[] | undefined + )?.find(e => e.url === TEST_CASE_DESCRIPTION_URL); + + return extension?.valueMarkdown; +} From 747e02b7519c27711136fb669954836c3d79b727 Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Sun, 22 Feb 2026 21:39:47 -0500 Subject: [PATCH 06/11] package clean up. adds markdown-to-text to test case quick-pick --- package-lock.json | 424 ------------------------------------ package.json | 4 - src/commands/execute-cql.ts | 3 +- 3 files changed, 2 insertions(+), 429 deletions(-) diff --git a/package-lock.json b/package-lock.json index 69630e7..0aac02b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,11 @@ "license": "Apache-2.0", "dependencies": { "expand-tilde": "^2.0.2", - "find-java-home": "1.2.2", "fs-extra": "^8.1.0", "glob": "^10.5.0", - "jsonpath": "^1.2.1", "lodash": "^4.17.23", "markdown-to-text": "^0.1.1", "node-fetch": "2.6.7", - "pino": "^10.3.1", "tslib": "^2.4.0", "vscode-languageclient": "^7.0.0", "vscode-uri": "^3.0.8", @@ -42,7 +39,6 @@ "chai": "4.5", "mocha": "^11.7.5", "mock-fs": "^5.5.0", - "prettier": "^3.3.3", "typescript": "^5.3.2" }, "engines": { @@ -212,12 +208,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", - "license": "MIT" - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -483,15 +473,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -981,70 +962,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -1082,23 +999,6 @@ "node": ">=8" } }, - "node_modules/find-java-home": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/find-java-home/-/find-java-home-1.2.2.tgz", - "integrity": "sha512-rN2LcQa+YDwfnPT0TQgn015eYqJkn3h3G/uVX5oOD2Ge7gKOuoJrntAJO4BiGb+K6lo6Mb+xJdoqbfzqaC75gw==", - "dependencies": { - "which": "~1.0.5", - "winreg": "~1.2.2" - } - }, - "node_modules/find-java-home/node_modules/which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", - "bin": { - "which": "bin/which" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1655,17 +1555,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/jsonpath": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz", - "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==", - "license": "MIT", - "dependencies": { - "esprima": "1.2.5", - "static-eval": "2.1.1", - "underscore": "1.13.6" - } - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -2028,15 +1917,6 @@ "node": ">= 6" } }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/one-time": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", @@ -2167,86 +2047,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pino": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", - "license": "MIT" - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "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 }, - "node_modules/process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "license": "MIT" - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -2291,15 +2097,6 @@ "node": ">=8.10.0" } }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2406,34 +2203,6 @@ "is-arrayish": "^0.3.1" } }, - "node_modules/sonic-boom": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -2442,15 +2211,6 @@ "node": "*" } }, - "node_modules/static-eval": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", - "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", - "license": "MIT", - "dependencies": { - "escodegen": "^2.1.0" - } - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2602,18 +2362,6 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, - "node_modules/thread-stream": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2669,12 +2417,6 @@ "node": ">=14.17" } }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "license": "MIT" - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -3096,11 +2838,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" - }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -3316,11 +3053,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3673,39 +3405,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - } - } - }, - "esprima": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==" - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, "expand-tilde": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", @@ -3736,22 +3435,6 @@ "to-regex-range": "^5.0.1" } }, - "find-java-home": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/find-java-home/-/find-java-home-1.2.2.tgz", - "integrity": "sha512-rN2LcQa+YDwfnPT0TQgn015eYqJkn3h3G/uVX5oOD2Ge7gKOuoJrntAJO4BiGb+K6lo6Mb+xJdoqbfzqaC75gw==", - "requires": { - "which": "~1.0.5", - "winreg": "~1.2.2" - }, - "dependencies": { - "which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==" - } - } - }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -4129,16 +3812,6 @@ "graceful-fs": "^4.1.6" } }, - "jsonpath": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz", - "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==", - "requires": { - "esprima": "1.2.5", - "static-eval": "2.1.1", - "underscore": "1.13.6" - } - }, "jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -4391,11 +4064,6 @@ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" }, - "on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" - }, "one-time": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", @@ -4483,59 +4151,12 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "pino": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", - "requires": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - } - }, - "pino-abstract-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", - "requires": { - "split2": "^4.0.0" - } - }, - "pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" - }, - "prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true - }, "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 }, - "process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==" - }, - "quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" - }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -4577,11 +4198,6 @@ "picomatch": "^2.2.1" } }, - "real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4648,38 +4264,11 @@ "is-arrayish": "^0.3.1" } }, - "sonic-boom": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "requires": { - "atomic-sleep": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, - "split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" - }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" }, - "static-eval": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", - "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", - "requires": { - "escodegen": "^2.1.0" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -4785,14 +4374,6 @@ "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, - "thread-stream": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", - "requires": { - "real-require": "^0.2.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4829,11 +4410,6 @@ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index a1aed54..7ef6219 100644 --- a/package.json +++ b/package.json @@ -191,19 +191,15 @@ "chai": "4.5", "mocha": "^11.7.5", "mock-fs": "^5.5.0", - "prettier": "^3.3.3", "typescript": "^5.3.2" }, "dependencies": { "expand-tilde": "^2.0.2", - "find-java-home": "1.2.2", "fs-extra": "^8.1.0", "glob": "^10.5.0", - "jsonpath": "^1.2.1", "lodash": "^4.17.23", "markdown-to-text": "^0.1.1", "node-fetch": "2.6.7", - "pino": "^10.3.1", "tslib": "^2.4.0", "vscode-languageclient": "^7.0.0", "vscode-uri": "^3.0.8", diff --git a/src/commands/execute-cql.ts b/src/commands/execute-cql.ts index fefd2fb..d67267f 100644 --- a/src/commands/execute-cql.ts +++ b/src/commands/execute-cql.ts @@ -1,5 +1,6 @@ import * as fse from 'fs-extra'; import { glob } from 'glob'; +import markdownToText from 'markdown-to-text'; import * as fs from 'node:fs'; import { commands, @@ -117,7 +118,7 @@ export async function selectTestCases(cqlFileUri: Uri): Promise { ); const quickPickItems = namedTestCases.map(testCase => ({ label: testCase.name, - detail: testCase.description, // use quickpick detail to get description on 2nd line of quickpick + detail: markdownToText(testCase.description), // use quickpick detail to get description on 2nd line of quickpick })); if (quickPickItems.length > 0) { From 30b7be1109dbc6815e6ba63398164c5d3a6b9893 Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Mon, 23 Feb 2026 10:33:39 -0500 Subject: [PATCH 07/11] saves/restores quick-pick selections --- src/commands/execute-cql.ts | 59 ++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/commands/execute-cql.ts b/src/commands/execute-cql.ts index d67267f..f7d2b9d 100644 --- a/src/commands/execute-cql.ts +++ b/src/commands/execute-cql.ts @@ -18,6 +18,8 @@ import { executeCql } from '../cql-service/cqlService.executeCql'; import * as log from '../log-services/logger'; import { getTestCases, TestCase, TestCaseExclusion } from '../model/testCase'; +let _context: ExtensionContext | undefined; + interface CqlPaths { libraryDirectoryPath: Uri; projectDirectoryPath: Uri; @@ -33,6 +35,7 @@ interface TestConfig { } export function register(context: ExtensionContext): void { + _context = context; context.subscriptions.push( commands.registerCommand(Commands.EXECUTE_CQL_COMMAND, async (uri: Uri) => { executeCQLFile(uri); @@ -62,10 +65,20 @@ export async function selectLibraries(): Promise { if (quickPickItems.length > 0) { quickPick.items = quickPickItems; quickPick.canSelectMany = true; + + const stateKey = 'selectLibraries.selections'; + const savedSelections = _context?.workspaceState.get(stateKey) ?? []; + if (savedSelections.length > 0) { + quickPick.selectedItems = quickPick.items.filter(item => + savedSelections.includes(item.label), + ); + } + quickPick.show(); quickPick.onDidAccept(async () => { const selected = [...quickPick.selectedItems]; + _context?.workspaceState.update(stateKey, selected.map(item => item.label)); quickPick.hide(); await window.withProgress( @@ -92,27 +105,27 @@ export async function selectLibraries(): Promise { } export async function selectTestCases(cqlFileUri: Uri): Promise { - const quickPick = window.createQuickPick(); + const cqlPaths = getCqlPaths(); + if (!cqlPaths) { + const msg = 'Unable to resolve needed CQL project paths.'; + log.error(msg); + window.showErrorMessage(msg); + return; + } - const libraryDirectory = Utils.dirname(cqlFileUri); + const quickPick = window.createQuickPick(); const libraryName = Utils.basename(cqlFileUri).replace('.cql', '').split('-')[0]; - const projectPath = workspace.getWorkspaceFolder(cqlFileUri)!.uri; - - const rootDir = Utils.resolvePath(projectPath); - const optionsPath = Utils.resolvePath(libraryDirectory, 'cql-options.json'); - const testPath = Utils.resolvePath(projectPath, 'input', 'tests'); - const resultPath = Utils.resolvePath(testPath, 'results'); - - const outputPath = Utils.resolvePath(resultPath, `${libraryName}.txt`); + const outputPath = Utils.resolvePath(cqlPaths.resultDirectoryPath, `${libraryName}.txt`); fse.ensureFileSync(outputPath.fsPath); const textDocument = await workspace.openTextDocument(outputPath); - const textEditor = await window.showTextDocument(textDocument); - - const testConfigPath = Utils.resolvePath(testPath, 'config.json'); - const testConfig = loadTestConfig(testConfigPath); + await window.showTextDocument(textDocument); + const testConfig = loadTestConfig(cqlPaths.testConfigPath); const excludedTestCases = getExcludedTestCases(libraryName, testConfig.testCasesToExclude); - - const testCases = getTestCases(testPath, libraryName, Array.from(excludedTestCases.keys())); + const testCases = getTestCases( + cqlPaths.testDirectoryPath, + libraryName, + Array.from(excludedTestCases.keys()), + ); const namedTestCases = testCases.filter( (testCase): testCase is Required => testCase.name !== undefined, ); @@ -124,11 +137,23 @@ export async function selectTestCases(cqlFileUri: Uri): Promise { if (quickPickItems.length > 0) { quickPick.items = quickPickItems; quickPick.canSelectMany = true; + + const stateKey = `selectTestCases.selections.${libraryName}`; + const savedSelections = _context?.workspaceState.get(stateKey) ?? []; + if (savedSelections.length > 0) { + quickPick.selectedItems = quickPick.items.filter(item => + savedSelections.includes(item.label), + ); + } + quickPick.show(); quickPick.onDidAccept(() => { + const selectedLabels = quickPick.selectedItems.map(item => item.label); + _context?.workspaceState.update(stateKey, selectedLabels); + const selected = namedTestCases.filter(testCase => - quickPick.selectedItems.some(item => item.label === testCase.name), + selectedLabels.some(label => label === testCase.name), ); quickPick.hide(); executeCQLFile(cqlFileUri, selected); From ec0396ebe8a2659acf45f86f2a44e4ae29dc01b3 Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Mon, 23 Feb 2026 12:28:27 -0500 Subject: [PATCH 08/11] adds testModel unit tests --- .vscode/extensions.json | 1 + .vscode/launch.json | 7 + .../SimpleMeasure/2222/Patient-2222.json | 168 ++++++++++++++++++ ...stCase.getMeasureReportDescription.test.ts | 26 +++ src/model/testCase.ts | 39 ++-- 5 files changed, 226 insertions(+), 15 deletions(-) create mode 100644 src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json create mode 100644 src/__test__/suite/model/testCase.getMeasureReportDescription.test.ts diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0801f30..ad19ce7 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,7 @@ // See https://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ + "ms-vscode.extension-test-runner", "dbaeumer.vscode-eslint", "streetsidesoftware.code-spell-checker", "streetsidesoftware.code-spell-checker-medical-terms", diff --git a/.vscode/launch.json b/.vscode/launch.json index c6b355c..16bc7ad 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,13 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "testConfiguration": "${workspaceFolder}/.vscode-test.js", + "preLaunchTask": "npm: compile" + }, { "name": "Run Extension", "type": "extensionHost", diff --git a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json new file mode 100644 index 0000000..d974442 --- /dev/null +++ b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json @@ -0,0 +1,168 @@ +{ + "resourceType": "Patient", + "id": "1111", + "meta": { + "profile": [ + "http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-patient" + ] + }, + "text": { + "status": "generated", + "div": "

Jim Chalmers male, DoB: 1974-12-25 ( Medical record number/12345\u00a0(use:\u00a0USUAL,\u00a0period:\u00a02001-05-06 --> (ongoing)))


Active:trueDeceased:false
Alt Names:
  • Peter James Chalmers (OFFICIAL)
  • Peter James Windsor (MAIDEN)
Contact Details:
  • ph: (03) 5555 6473(WORK)
  • ph: (03) 3410 5613(MOBILE)
  • ph: (03) 5555 8834(OLD)
  • 534 Erewhon St PeasantVille, Utah 84414(HOME)
Next-of-Kin:
  • Bénédicte du Marché (female)
  • 534 Erewhon St PleasantVille VT 3999 (HOME)
  • +33 (237) 998327
  • Valid Period: 2012 --> (ongoing)
Links:
" + }, + "identifier": [ + { + "use": "usual", + "type": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "code": "MR" + } + ] + }, + "system": "urn:oid:1.2.36.146.595.217.0.1", + "value": "12345", + "period": { + "start": "2001-05-06" + }, + "assigner": { + "display": "Acme Healthcare" + } + } + ], + "active": true, + "name": [ + { + "use": "official", + "family": "Chalmers", + "given": [ + "Peter", + "James" + ] + }, + { + "use": "usual", + "family": "Chalmers", + "given": [ + "Jim" + ] + }, + { + "use": "maiden", + "family": "Windsor", + "given": [ + "Peter", + "James" + ], + "period": { + "end": "2002" + } + } + ], + "telecom": [ + { + "system": "phone", + "value": "(03) 5555 6473", + "use": "work", + "rank": 1 + }, + { + "system": "phone", + "value": "(03) 3410 5613", + "use": "mobile", + "rank": 2 + }, + { + "system": "phone", + "value": "(03) 5555 8834", + "use": "old", + "period": { + "end": "2014" + } + } + ], + "gender": "male", + "birthDate": "1974-12-25", + "_birthDate": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime", + "valueDateTime": "1974-12-25T14:35:45-05:00" + } + ] + }, + "deceasedBoolean": false, + "address": [ + { + "use": "home", + "type": "both", + "text": "534 Erewhon St PeasantVille, Utah 84414", + "line": [ + "534 Erewhon St" + ], + "city": "PleasantVille", + "district": "Rainbow", + "state": "UT", + "postalCode": "84414", + "period": { + "start": "1974-12-25" + } + } + ], + "contact": [ + { + "relationship": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0131", + "code": "N" + } + ] + } + ], + "name": { + "family": "du Marché", + "_family": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix", + "valueString": "VV" + } + ] + }, + "given": [ + "Bénédicte" + ] + }, + "telecom": [ + { + "system": "phone", + "value": "+33 (237) 998327" + } + ], + "address": { + "use": "home", + "type": "both", + "line": [ + "534 Erewhon St" + ], + "city": "PleasantVille", + "district": "Rainbow", + "state": "VT", + "postalCode": "3999", + "period": { + "start": "1974-12-25" + } + }, + "gender": "female", + "period": { + "start": "2012" + } + } + ], + "managingOrganization": { + "reference": "Organization/example" + } +} \ No newline at end of file diff --git a/src/__test__/suite/model/testCase.getMeasureReportDescription.test.ts b/src/__test__/suite/model/testCase.getMeasureReportDescription.test.ts new file mode 100644 index 0000000..df3e180 --- /dev/null +++ b/src/__test__/suite/model/testCase.getMeasureReportDescription.test.ts @@ -0,0 +1,26 @@ +import { expect } from 'chai'; +import { Uri, workspace } from 'vscode'; +import { getMeasureReportDescription } from '../../../model/testCase'; + +suite('testCase.getMeasureReportDescription tests', () => { + test('should return undefined when directory does not exist', () => { + const folder = '/tests/measure/library-example/1234'; + expect(getMeasureReportDescription(Uri.file(folder))).to.equal(undefined); + }); + + test('should return undefined when directory exist but there is no measure report', () => { + const testCaseFolder = Uri.joinPath( + workspace.workspaceFolders![0].uri, + 'input/tests/measure/SimpleMeasure/2222', + ); + expect(getMeasureReportDescription(testCaseFolder)).to.equal(undefined); + }); + + test('should return description', () => { + const testCaseFolder = Uri.joinPath( + workspace.workspaceFolders![0].uri, + 'input/tests/measure/SimpleMeasure/1111', + ); + expect(getMeasureReportDescription(testCaseFolder)).to.equal('SimpleMeasure'); + }); +}); diff --git a/src/model/testCase.ts b/src/model/testCase.ts index 8dd5cbb..f2684fb 100644 --- a/src/model/testCase.ts +++ b/src/model/testCase.ts @@ -2,6 +2,7 @@ import { glob } from 'glob'; import * as fs from 'node:fs'; import path from 'node:path'; import { Uri } from 'vscode'; +import * as log from '../log-services/logger'; export interface TestCase { name?: string; @@ -53,24 +54,32 @@ const TEST_CASE_DESCRIPTION_URL = 'http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-testCaseDescription'; export function getMeasureReportDescription(testCaseFolderPath: Uri): string | undefined { - if (!fs.existsSync(testCaseFolderPath.fsPath)) { - return undefined; - } + try { + if (!fs.existsSync(testCaseFolderPath.fsPath)) { + return undefined; + } - const measureReportFile = fs - .readdirSync(testCaseFolderPath.fsPath) - .find(f => f.startsWith('MeasureReport')); + const measureReportFile = fs + .readdirSync(testCaseFolderPath.fsPath) + .find(f => f.startsWith('MeasureReport')); - if (!measureReportFile) { - return undefined; - } + if (!measureReportFile) { + return undefined; + } - const content = fs.readFileSync(path.join(testCaseFolderPath.fsPath, measureReportFile), 'utf-8'); - const report = JSON.parse(content); + const content = fs.readFileSync( + path.join(testCaseFolderPath.fsPath, measureReportFile), + 'utf-8', + ); + const report = JSON.parse(content); - const extension = ( - report.extension as { url: string; valueMarkdown?: string }[] | undefined - )?.find(e => e.url === TEST_CASE_DESCRIPTION_URL); + const extension = ( + report.extension as { url: string; valueMarkdown?: string }[] | undefined + )?.find(e => e.url === TEST_CASE_DESCRIPTION_URL); - return extension?.valueMarkdown; + return extension?.valueMarkdown; + } catch (error) { + log.error('Error while attempting to getMeasureReport Description', error); + } + return undefined; } From b129dabdac2e925a34ada879c7e0d6bedd60537e Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Mon, 23 Feb 2026 12:37:46 -0500 Subject: [PATCH 09/11] fixes issue with patient 222 id --- .../input/tests/measure/SimpleMeasure/2222/Patient-2222.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json index d974442..a18dc7e 100644 --- a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json +++ b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json @@ -1,6 +1,6 @@ { "resourceType": "Patient", - "id": "1111", + "id": "2222", "meta": { "profile": [ "http://hl7.org/fhir/us/qicore/StructureDefinition/qicore-patient" From 4b6c3744f8d9a124e3d25c6681946fc76b7b68ff Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Tue, 24 Feb 2026 11:22:34 -0500 Subject: [PATCH 10/11] fixes issue with ensureExists tests --- .../suite/helpers/file-helpers.test.ts | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/__test__/suite/helpers/file-helpers.test.ts b/src/__test__/suite/helpers/file-helpers.test.ts index 2a4ca68..ccfa725 100644 --- a/src/__test__/suite/helpers/file-helpers.test.ts +++ b/src/__test__/suite/helpers/file-helpers.test.ts @@ -1,36 +1,32 @@ import { expect } from 'chai'; import * as fs from 'fs'; -import mock from 'mock-fs'; +import * as os from 'os'; +import * as path from 'path'; import { ensureExists } from '../../../utils/file-utils'; -suite('ensureExists() with mock-fs', () => { +suite('ensureExists()', () => { + let testDir: string; + + setup(() => { + testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vscode-cql-test-')); + }); + teardown(() => { - // Crucial: Restore the real file system after every test - mock.restore(); + fs.rmSync(testDir, { recursive: true, force: true }); }); test('should create the directory if it does not exist', () => { - // Setup an empty virtual file system - mock({}); - - const testPath = './new-folder'; + const testPath = path.join(testDir, 'new-folder'); ensureExists(testPath); - // Verify the folder now exists in the virtual FS - const exists = fs.existsSync(testPath); - expect(exists).to.be.true; + expect(fs.existsSync(testPath)).to.be.true; }); test('should not throw an error if the directory already exists', () => { - // Setup virtual FS with an existing directory - mock({ - './existing-folder': {}, - }); - - const testPath = './existing-folder'; + const testPath = path.join(testDir, 'existing-folder'); + fs.mkdirSync(testPath); - // This should run without calling mkdirSync again/throwing error expect(() => ensureExists(testPath)).to.not.throw(); expect(fs.existsSync(testPath)).to.be.true; }); From b8083bf3a6d17a8fab1d4dbf3ccffe0713e965d8 Mon Sep 17 00:00:00 2001 From: raleigh-g-thompson Date: Mon, 2 Mar 2026 13:29:35 -0500 Subject: [PATCH 11/11] adds cql command interlock with CQL LS ready --- package.json | 12 ++++++--- .../input/cql/SimpleMeasure.cql | 26 ++++++++++++++----- .../SimpleMeasure/2222/Patient-2222.json | 8 ------ src/cql-language-server/cqlLanguageClient.ts | 4 ++- src/statusBar.ts | 19 +++++++++++--- 5 files changed, 47 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 7ef6219..b17524c 100644 --- a/package.json +++ b/package.json @@ -116,22 +116,22 @@ "editor/context": [ { "command": "cql.action.executeCql", - "when": "editorLangId == cql", + "when": "editorLangId == cql && cql.languageServerReady", "group": "1_cqlactions@1.execute@1" }, { "command": "cql.action.executeCql.selectTestCases", - "when": "editorLangId == cql", + "when": "editorLangId == cql && cql.languageServerReady", "group": "1_cqlactions@1.execute@3" }, { "command": "cql.action.viewElm.xml", - "when": "editorLangId == cql", + "when": "editorLangId == cql && cql.languageServerReady", "group": "1_cqlactions@2.elm@1" }, { "command": "cql.action.viewElm.json", - "when": "editorLangId == cql", + "when": "editorLangId == cql && cql.languageServerReady", "group": "1_cqlactions@2.elm@2" } ], @@ -151,6 +151,10 @@ { "command": "cql.action.viewElm.json", "when": "false" + }, + { + "command": "cql.action.executeCql.selectLibraries", + "when": "cql.languageServerReady" } ] } diff --git a/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql b/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql index 3499e75..be23e52 100644 --- a/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql +++ b/src/__test__/resources/test-workspace/input/cql/SimpleMeasure.cql @@ -1,11 +1,25 @@ -library SimpleMeasure version '1.0.000' +library SimpleMeasure version '1.0.0' -using QICore version '6.0.0' - -parameter "Measurement Period" Interval - default Interval[@2026-01-01T00:00:00.000Z, @2027-01-01T00:00:00.000Z) +using FHIR version '4.0.1' +include FHIRHelpers version '4.0.1' called FHIRHelpers context Patient +define "isOfficial": + exists (Patient.name Name where Name.use.value = 'official') + define "Patient Name": - Patient.name + Coalesce( + "Get Name String"(First(Patient.name Name where Name.use.value = 'official')), + "Get Name String"(First(Patient.name Name where Name.use.value = 'usual')), + "Get Name String"(First(Patient.name)), + 'Unknown' + ) + +define function "Get Name String"(name FHIR.HumanName): + if name is null then null + else + Coalesce( + name.text.value, + Combine(name.given.value, ' ') + ' ' + Coalesce(name.family.value, '') + ) \ No newline at end of file diff --git a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json index a18dc7e..7ccb161 100644 --- a/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json +++ b/src/__test__/resources/test-workspace/input/tests/measure/SimpleMeasure/2222/Patient-2222.json @@ -33,14 +33,6 @@ ], "active": true, "name": [ - { - "use": "official", - "family": "Chalmers", - "given": [ - "Peter", - "James" - ] - }, { "use": "usual", "family": "Chalmers", diff --git a/src/cql-language-server/cqlLanguageClient.ts b/src/cql-language-server/cqlLanguageClient.ts index 3938f00..8ba0eaa 100644 --- a/src/cql-language-server/cqlLanguageClient.ts +++ b/src/cql-language-server/cqlLanguageClient.ts @@ -58,6 +58,8 @@ export class CqlLanguageClient { this.languageClient.onReady().then(() => { //log.info('language client is ready'); this.status = ClientStatus.Started; + commands.executeCommand('setContext', 'cql.languageServerReady', true); + const version = requirements.cql_ls_info.cql_ls_jar.match(/(\d+\.\d+\.\d+)/)?.[1]; // this.languageClient.onNotification(StatusNotification.type, (report) => { // switch (report.type) { // case 'ServiceReady': @@ -128,7 +130,7 @@ export class CqlLanguageClient { }); // TODO: Set this once we have the initialization signal from the LS. - statusBar.setReady(); + statusBar.setReady(version); }); //this.registerCommands(context); diff --git a/src/statusBar.ts b/src/statusBar.ts index 200363c..b3aeefb 100644 --- a/src/statusBar.ts +++ b/src/statusBar.ts @@ -1,4 +1,4 @@ -import { StatusBarItem, window, StatusBarAlignment } from 'vscode'; +import { MarkdownString, StatusBarAlignment, StatusBarItem, window } from 'vscode'; import { Disposable } from 'vscode-languageclient'; class StatusBar implements Disposable { @@ -10,7 +10,7 @@ class StatusBar implements Disposable { public showStatusBar(): void { this.statusBarItem.text = StatusIcon.Busy; - this.statusBarItem.tooltip = ''; + this.statusBarItem.tooltip = StatusTooltip.Busy; this.statusBarItem.show(); } @@ -20,14 +20,21 @@ class StatusBar implements Disposable { public setBusy(): void { this.statusBarItem.text = StatusIcon.Busy; + this.statusBarItem.tooltip = StatusTooltip.Busy; } public setError(): void { this.statusBarItem.text = StatusIcon.Error; + this.statusBarItem.tooltip = StatusTooltip.Error; } - public setReady(): void { + public setReady(version?: string): void { this.statusBarItem.text = StatusIcon.Ready; + const tooltip = new MarkdownString(StatusTooltip.Ready); + if (version) { + tooltip.appendMarkdown(`\n\nVersion: ${version}`); + } + this.statusBarItem.tooltip = tooltip; } public updateTooltip(tooltip: string): void { @@ -45,4 +52,10 @@ enum StatusIcon { Error = '$(error) CQL', } +enum StatusTooltip { + Busy = 'Server Busy', + Ready = 'Server Ready', + Error = 'Server Error', +} + export const statusBar: StatusBar = new StatusBar();