diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json index cb456b097..a19bb0e7a 100644 --- a/extensions/ql-vscode/package-lock.json +++ b/extensions/ql-vscode/package-lock.json @@ -23,6 +23,7 @@ "fs-extra": "^11.1.1", "immutable": "^4.0.0", "js-yaml": "^4.1.0", + "minimatch": "^9.0.0", "minimist": "~1.2.6", "msw": "^1.2.0", "nanoid": "^3.2.0", @@ -93,7 +94,7 @@ "@types/through2": "^2.0.36", "@types/tmp": "^0.1.0", "@types/unzipper": "~0.10.1", - "@types/vscode": "^1.59.0", + "@types/vscode": "^1.67.0", "@types/webpack": "^5.28.0", "@types/webpack-env": "^1.18.0", "@types/xml2js": "~0.4.4", @@ -117,7 +118,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-storybook": "^0.6.4", "file-loader": "^6.2.0", - "glob": "^9.3.2", + "glob": "^10.0.0", "gulp": "^4.0.2", "gulp-esbuild": "^0.10.5", "gulp-replace": "^1.1.3", @@ -2584,9 +2585,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.15.tgz", - "integrity": "sha512-JJjZjJi2eBL01QJuWjfCdZxcIgot+VoK6Fq7eKF9w4YHm9hwl7nhBR1o2Wnt/WcANk5l9SkpvrldW1PLuXxcbw==", + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", + "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", "cpu": [ "arm" ], @@ -2744,9 +2745,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.15.tgz", - "integrity": "sha512-lhz6UNPMDXUhtXSulw8XlFAtSYO26WmHQnCi2Lg2p+/TMiJKNLtZCYUxV4wG6rZMzXmr8InGpNwk+DLT2Hm0PA==", + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", + "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", "cpu": [ "loong64" ], @@ -2974,6 +2975,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@eslint/eslintrc/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3006,6 +3017,18 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3242,6 +3265,16 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@humanwhocodes/config-array/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3259,6 +3292,18 @@ } } }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/config-array/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4485,6 +4530,16 @@ "node": ">= 8" } }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@jest/reporters/node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -4690,6 +4745,18 @@ "node": ">=8.6" } }, + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@jest/reporters/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5765,6 +5832,16 @@ "node": ">=10" } }, + "node_modules/@npmcli/move-file/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@npmcli/move-file/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5785,6 +5862,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@npmcli/move-file/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@npmcli/move-file/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -8942,6 +9031,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/@storybook/builder-webpack4/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@storybook/builder-webpack4/node_modules/clean-css": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", @@ -9274,6 +9373,18 @@ "node": ">=4.0.0" } }, + "node_modules/@storybook/builder-webpack4/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@storybook/builder-webpack4/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9868,38 +9979,6 @@ } } }, - "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/android-arm": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", - "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@storybook/builder-webpack5/node_modules/@esbuild/linux-loong64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", - "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@storybook/builder-webpack5/node_modules/@storybook/addons": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-7.0.4.tgz", @@ -10220,15 +10299,6 @@ "webpack": ">=5" } }, - "node_modules/@storybook/builder-webpack5/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==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@storybook/builder-webpack5/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -10717,6 +10787,28 @@ "semver": "bin/semver.js" } }, + "node_modules/@storybook/builder-webpack5/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@storybook/builder-webpack5/node_modules/minimatch/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@storybook/builder-webpack5/node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -11936,6 +12028,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/@storybook/core-common/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@storybook/core-common/node_modules/cacache": { "version": "12.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", @@ -12158,6 +12260,18 @@ "yallist": "^3.0.2" } }, + "node_modules/@storybook/core-common/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@storybook/core-common/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -12716,6 +12830,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/@storybook/core-server/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@storybook/core-server/node_modules/cacache": { "version": "12.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", @@ -12872,6 +12996,18 @@ "yallist": "^3.0.2" } }, + "node_modules/@storybook/core-server/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@storybook/core-server/node_modules/schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -13073,38 +13209,6 @@ "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/core-webpack/node_modules/@esbuild/android-arm": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", - "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@storybook/core-webpack/node_modules/@esbuild/linux-loong64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", - "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@storybook/core-webpack/node_modules/@storybook/core-common": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.0.4.tgz", @@ -13190,15 +13294,6 @@ "node": ">=10" } }, - "node_modules/@storybook/core-webpack/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==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@storybook/core-webpack/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -14174,6 +14269,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "node_modules/@storybook/manager-webpack4/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@storybook/manager-webpack4/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -14527,6 +14632,18 @@ "node": ">=4.0.0" } }, + "node_modules/@storybook/manager-webpack4/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@storybook/manager-webpack4/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -19170,9 +19287,9 @@ } }, "node_modules/@types/vscode": { - "version": "1.63.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.63.1.tgz", - "integrity": "sha512-Z+ZqjRcnGfHP86dvx/BtSwWyZPKQ/LBdmAVImY82TphyjOw2KgTKcp7Nx92oNwCTsHzlshwexAG/WiY2JuUm3g==", + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.77.0.tgz", + "integrity": "sha512-MWFN5R7a33n8eJZJmdVlifjig3LWUNRrPeO1xemIcZ0ae0TEQuRc7G2xV0LUX78RZFECY1plYBn+dP/Acc3L0Q==", "dev": true }, "node_modules/@types/webpack": { @@ -19729,6 +19846,16 @@ "node": ">=8.9.3" } }, + "node_modules/@vscode/test-electron/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@vscode/test-electron/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -19749,6 +19876,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@vscode/test-electron/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@vscode/test-electron/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -19798,6 +19937,16 @@ "node": ">= 14" } }, + "node_modules/@vscode/vsce/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@vscode/vsce/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -19851,6 +20000,18 @@ "node": ">=10" } }, + "node_modules/@vscode/vsce/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@vscode/vsce/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -20680,6 +20841,15 @@ "node": ">= 6" } }, + "node_modules/archiver-utils/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/archiver-utils/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -20699,6 +20869,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/archiver-utils/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/archiver/node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -22389,12 +22570,11 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -22713,6 +22893,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/c8/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/c8/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -22802,6 +22992,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/c8/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/c8/node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -22938,6 +23140,16 @@ "node": ">= 10" } }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/cacache/node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -22979,6 +23191,18 @@ "node": ">=10" } }, + "node_modules/cacache/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/cacache/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -23942,7 +24166,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concat-stream": { "version": "1.6.2", @@ -24256,6 +24480,16 @@ "node": ">=0.10.0" } }, + "node_modules/cpy/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/cpy/node_modules/dir-glob": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", @@ -24346,6 +24580,18 @@ "node": ">=6" } }, + "node_modules/cpy/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/cpy/node_modules/p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", @@ -25500,6 +25746,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/del/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/del/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -25520,6 +25776,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/del/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/del/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -26811,6 +27079,38 @@ "node": ">=12" } }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.15.tgz", + "integrity": "sha512-JJjZjJi2eBL01QJuWjfCdZxcIgot+VoK6Fq7eKF9w4YHm9hwl7nhBR1o2Wnt/WcANk5l9SkpvrldW1PLuXxcbw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/@esbuild/linux-loong64": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.15.tgz", + "integrity": "sha512-lhz6UNPMDXUhtXSulw8XlFAtSYO26WmHQnCi2Lg2p+/TMiJKNLtZCYUxV4wG6rZMzXmr8InGpNwk+DLT2Hm0PA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -27159,6 +27459,16 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -27171,6 +27481,18 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-jest-dom": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-4.0.2.tgz", @@ -27230,12 +27552,34 @@ "node": ">=6.0" } }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -27315,6 +27659,16 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-react/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -27336,6 +27690,18 @@ "node": ">=4.0" } }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", @@ -27478,6 +27844,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -27657,6 +28033,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -29132,6 +29520,16 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/flat-cache/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -29152,6 +29550,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/flat-cache/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/flat-cache/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -29350,6 +29760,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -29428,6 +29848,18 @@ "node": ">=8" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -29789,15 +30221,15 @@ "dev": true }, "node_modules/glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.0.0.tgz", + "integrity": "sha512-zmp9ZDC6NpDNLujV2W2n+3lH+BafIVZ4/ct+Yj3BMZTH/+bgm/eVjHzeFLwxJrrIGgjjS2eiQLlpurHsNlEAtQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" + "minimatch": "^9.0.0", + "minipass": "^5.0.0", + "path-scurry": "^1.6.4" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -29853,6 +30285,16 @@ "node": ">= 0.10" } }, + "node_modules/glob-stream/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/glob-stream/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -29895,6 +30337,18 @@ "node": ">=0.10.0" } }, + "node_modules/glob-stream/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -30018,34 +30472,25 @@ "node": ">=0.10" } }, - "node_modules/glob/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==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/glob/node_modules/minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" @@ -32860,6 +33305,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/jest-config/node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -33004,6 +33459,18 @@ "node": ">=8.6" } }, + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/jest-config/node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -35279,6 +35746,16 @@ "node": ">= 8" } }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/jest-runtime/node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -35498,6 +35975,18 @@ "node": ">=8.6" } }, + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/jest-runtime/node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -38426,14 +38915,17 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -38999,6 +39491,28 @@ "node": ">= 0.10.5" } }, + "node_modules/node-dir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-dir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -39167,6 +39681,16 @@ "node": ">= 4" } }, + "node_modules/npm-run-all/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/npm-run-all/node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -39198,6 +39722,18 @@ "node": ">=4" } }, + "node_modules/npm-run-all/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/npm-run-all/node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -40369,13 +40905,13 @@ } }, "node_modules/path-scurry": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.3.tgz", - "integrity": "sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.4.tgz", + "integrity": "sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==", "dev": true, "dependencies": { - "lru-cache": "^7.14.1", - "minipass": "^4.0.2" + "lru-cache": "^9.0.0", + "minipass": "^5.0.0" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -40385,18 +40921,18 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.0.1.tgz", + "integrity": "sha512-C8QsKIN1UIXeOs3iWmiZ1lQY+EnKDojWd37fXy1aSbJvH4iSma1uy2OWuoB3m4SYRli5+CUjDv3Dij5DVoetmg==", "dev": true, "engines": { - "node": ">=12" + "node": "14 || >=16.14" } }, "node_modules/path-scurry/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" @@ -41568,6 +42104,26 @@ "minimatch": "^3.0.4" } }, + "node_modules/readdir-glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -42268,6 +42824,15 @@ "rimraf": "bin.js" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -42287,6 +42852,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -44243,6 +44819,16 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/test-exclude/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -44263,6 +44849,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -44379,6 +44977,15 @@ "tmp": "^0.2.0" } }, + "node_modules/tmp-promise/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/tmp-promise/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -44398,6 +45005,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/tmp-promise/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/tmp-promise/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -44819,15 +45437,6 @@ "node": ">=10.0.0" } }, - "node_modules/ts-json-schema-generator/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==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/ts-json-schema-generator/node_modules/commander": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", @@ -46416,6 +47025,26 @@ "vscode": "^1.67.0" } }, + "node_modules/vscode-languageclient/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/vscode-languageclient/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/vscode-languageserver-protocol": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2.tgz", @@ -49333,9 +49962,9 @@ "dev": true }, "@esbuild/android-arm": { - "version": "0.15.15", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.15.tgz", - "integrity": "sha512-JJjZjJi2eBL01QJuWjfCdZxcIgot+VoK6Fq7eKF9w4YHm9hwl7nhBR1o2Wnt/WcANk5l9SkpvrldW1PLuXxcbw==", + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", + "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", "dev": true, "optional": true }, @@ -49403,9 +50032,9 @@ "optional": true }, "@esbuild/linux-loong64": { - "version": "0.15.15", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.15.tgz", - "integrity": "sha512-lhz6UNPMDXUhtXSulw8XlFAtSYO26WmHQnCi2Lg2p+/TMiJKNLtZCYUxV4wG6rZMzXmr8InGpNwk+DLT2Hm0PA==", + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", + "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", "dev": true, "optional": true }, @@ -49515,6 +50144,16 @@ "uri-js": "^4.2.2" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -49536,6 +50175,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -49725,6 +50373,16 @@ "minimatch": "^3.0.4" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -49734,6 +50392,15 @@ "ms": "2.1.2" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -50689,6 +51356,16 @@ "picomatch": "^2.0.4" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -50843,6 +51520,15 @@ "picomatch": "^2.3.1" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -51673,6 +52359,16 @@ "rimraf": "^3.0.2" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -51687,6 +52383,15 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -53920,6 +54625,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "clean-css": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", @@ -54160,6 +54875,15 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -54618,20 +55342,6 @@ "webpack-virtual-modules": "^0.4.3" }, "dependencies": { - "@esbuild/android-arm": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", - "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", - "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", - "dev": true, - "optional": true - }, "@storybook/addons": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-7.0.4.tgz", @@ -54852,15 +55562,6 @@ "schema-utils": "^4.0.0" } }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -55212,6 +55913,27 @@ } } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + } + } + }, "npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -56106,6 +56828,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "cacache": { "version": "12.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", @@ -56269,6 +57001,15 @@ "yallist": "^3.0.2" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -56718,6 +57459,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "cacache": { "version": "12.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", @@ -56841,6 +57592,15 @@ "yallist": "^3.0.2" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -57003,20 +57763,6 @@ "ts-dedent": "^2.0.0" }, "dependencies": { - "@esbuild/android-arm": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", - "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", - "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", - "dev": true, - "optional": true - }, "@storybook/core-common": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.0.4.tgz", @@ -57085,15 +57831,6 @@ "readable-stream": "^3.6.0" } }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -57842,6 +58579,16 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -58096,6 +58843,15 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -61731,9 +62487,9 @@ } }, "@types/vscode": { - "version": "1.63.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.63.1.tgz", - "integrity": "sha512-Z+ZqjRcnGfHP86dvx/BtSwWyZPKQ/LBdmAVImY82TphyjOw2KgTKcp7Nx92oNwCTsHzlshwexAG/WiY2JuUm3g==", + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.77.0.tgz", + "integrity": "sha512-MWFN5R7a33n8eJZJmdVlifjig3LWUNRrPeO1xemIcZ0ae0TEQuRc7G2xV0LUX78RZFECY1plYBn+dP/Acc3L0Q==", "dev": true }, "@types/webpack": { @@ -62101,6 +62857,16 @@ "unzipper": "^0.10.11" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -62115,6 +62881,15 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -62154,6 +62929,16 @@ "yazl": "^2.2.2" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -62192,6 +62977,15 @@ "yallist": "^4.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -62904,6 +63698,15 @@ "readable-stream": "^2.0.0" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -62916,6 +63719,14 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -64214,12 +65025,11 @@ } }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "braces": { @@ -64473,6 +65283,16 @@ "color-convert": "^2.0.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -64538,6 +65358,15 @@ "p-locate": "^5.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -64637,6 +65466,16 @@ "unique-filename": "^1.1.1" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -64666,6 +65505,15 @@ "yallist": "^4.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -65403,7 +66251,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -65646,6 +66494,16 @@ "array-uniq": "^1.0.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "dir-glob": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", @@ -65720,6 +66578,15 @@ "slash": "^2.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", @@ -66615,6 +67482,16 @@ "slash": "^3.0.0" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -66629,6 +67506,15 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -67401,6 +68287,22 @@ "esbuild-windows-32": "0.15.15", "esbuild-windows-64": "0.15.15", "esbuild-windows-arm64": "0.15.15" + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.15.tgz", + "integrity": "sha512-JJjZjJi2eBL01QJuWjfCdZxcIgot+VoK6Fq7eKF9w4YHm9hwl7nhBR1o2Wnt/WcANk5l9SkpvrldW1PLuXxcbw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.15.tgz", + "integrity": "sha512-lhz6UNPMDXUhtXSulw8XlFAtSYO26WmHQnCi2Lg2p+/TMiJKNLtZCYUxV4wG6rZMzXmr8InGpNwk+DLT2Hm0PA==", + "dev": true, + "optional": true + } } }, "esbuild-android-64": { @@ -67681,6 +68583,16 @@ "color-convert": "^2.0.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -67804,6 +68716,15 @@ "p-locate": "^5.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -68086,6 +69007,16 @@ "tsconfig-paths": "^3.14.1" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -68094,6 +69025,15 @@ "requires": { "esutils": "^2.0.2" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -68139,12 +69079,31 @@ "@babel/runtime-corejs3": "^7.10.2" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -68190,6 +69149,16 @@ "string.prototype.matchall": "^4.0.7" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -68205,6 +69174,15 @@ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "resolve": { "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", @@ -69336,6 +70314,16 @@ "rimraf": "^3.0.2" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -69350,6 +70338,15 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -69492,6 +70489,16 @@ "color-convert": "^2.0.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -69549,6 +70556,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -69834,39 +70850,30 @@ "dev": true }, "glob": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.2.tgz", - "integrity": "sha512-BTv/JhKXFEHsErMte/AnfiSv8yYOLLiyH2lTg8vn02O21zWFgHPTfxtgn1QRe7NRgggUhC8hacR2Re94svHqeA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.0.0.tgz", + "integrity": "sha512-zmp9ZDC6NpDNLujV2W2n+3lH+BafIVZ4/ct+Yj3BMZTH/+bgm/eVjHzeFLwxJrrIGgjjS2eiQLlpurHsNlEAtQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", - "minimatch": "^7.4.1", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" + "minimatch": "^9.0.0", + "minipass": "^5.0.0", + "path-scurry": "^1.6.4" }, "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==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "minimatch": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.3.tgz", - "integrity": "sha512-5UB4yYusDtkRPbRiy1cqZ1IpGNcJCGlEMG17RKzPddpyiPKoCdwohbED8g4QXT0ewCt8LTkQXuljsUfQ3FKM4A==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } }, "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true } } @@ -69906,6 +70913,16 @@ "unique-stream": "^2.0.2" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -69938,6 +70955,15 @@ "requires": { "is-extglob": "^2.1.0" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -72190,6 +73216,16 @@ "color-convert": "^2.0.1" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -72295,6 +73331,15 @@ "picomatch": "^2.3.1" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -74053,6 +75098,16 @@ "picomatch": "^2.0.4" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -74218,6 +75273,15 @@ "picomatch": "^2.3.1" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -76398,11 +77462,11 @@ "dev": true }, "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" } }, "minimist": { @@ -76854,6 +77918,27 @@ "dev": true, "requires": { "minimatch": "^3.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "node-fetch": { @@ -76994,6 +78079,16 @@ "string.prototype.padend": "^3.0.0" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -77019,6 +78114,15 @@ "strip-bom": "^3.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -77920,25 +79024,25 @@ "dev": true }, "path-scurry": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.3.tgz", - "integrity": "sha512-RAmB+n30SlN+HnNx6EbcpoDy9nwdpcGPnEKrJnu6GZoDWBdIjo1UQMVtW2ybtC7LC2oKLcMq8y5g8WnKLiod9g==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.4.tgz", + "integrity": "sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==", "dev": true, "requires": { - "lru-cache": "^7.14.1", - "minipass": "^4.0.2" + "lru-cache": "^9.0.0", + "minipass": "^5.0.0" }, "dependencies": { "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.0.1.tgz", + "integrity": "sha512-C8QsKIN1UIXeOs3iWmiZ1lQY+EnKDojWd37fXy1aSbJvH4iSma1uy2OWuoB3m4SYRli5+CUjDv3Dij5DVoetmg==", "dev": true }, "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true } } @@ -78834,6 +79938,25 @@ "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==", "requires": { "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "readdirp": { @@ -79374,6 +80497,15 @@ "glob": "^7.1.3" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -79386,6 +80518,14 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -80924,6 +82064,16 @@ "minimatch": "^3.0.4" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -80937,6 +82087,15 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -81042,6 +82201,15 @@ "tmp": "^0.2.0" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -81055,6 +82223,14 @@ "path-is-absolute": "^1.0.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -81366,15 +82542,6 @@ "typescript": "~4.8.3" }, "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==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "commander": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", @@ -82560,6 +83727,25 @@ "minimatch": "^3.0.4", "semver": "^7.3.5", "vscode-languageserver-protocol": "3.17.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "vscode-languageserver-protocol": { diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index d4c208b8b..875f01bd2 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -1461,6 +1461,7 @@ "fs-extra": "^11.1.1", "immutable": "^4.0.0", "js-yaml": "^4.1.0", + "minimatch": "^9.0.0", "minimist": "~1.2.6", "msw": "^1.2.0", "nanoid": "^3.2.0", @@ -1531,7 +1532,7 @@ "@types/through2": "^2.0.36", "@types/tmp": "^0.1.0", "@types/unzipper": "~0.10.1", - "@types/vscode": "^1.59.0", + "@types/vscode": "^1.67.0", "@types/webpack": "^5.28.0", "@types/webpack-env": "^1.18.0", "@types/xml2js": "~0.4.4", @@ -1555,7 +1556,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-storybook": "^0.6.4", "file-loader": "^6.2.0", - "glob": "^9.3.2", + "glob": "^10.0.0", "gulp": "^4.0.2", "gulp-esbuild": "^0.10.5", "gulp-replace": "^1.1.3", diff --git a/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-module.ts b/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-module.ts index 6354f56bb..e330db0b1 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-module.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-module.ts @@ -11,6 +11,8 @@ import { showAndLogErrorMessage } from "../helpers"; import { withProgress } from "../progress"; import { pickExtensionPackModelFile } from "./extension-pack-picker"; +const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"]; + export class DataExtensionsEditorModule { private readonly queryStorageDir: string; @@ -51,15 +53,22 @@ export class DataExtensionsEditorModule { public getCommands(): DataExtensionsEditorCommands { return { - "codeQL.openDataExtensionsEditor": async () => - withProgress( - async (progress) => { - const db = this.databaseManager.currentDatabaseItem; - if (!db) { - void showAndLogErrorMessage("No database selected"); - return; - } + "codeQL.openDataExtensionsEditor": async () => { + const db = this.databaseManager.currentDatabaseItem; + if (!db) { + void showAndLogErrorMessage("No database selected"); + return; + } + if (!SUPPORTED_LANGUAGES.includes(db.language)) { + void showAndLogErrorMessage( + `The data extensions editor is not supported for ${db.language} databases.`, + ); + return; + } + + return withProgress( + async (progress, token) => { if (!(await this.cliServer.cliConstraints.supportsQlpacksKind())) { void showAndLogErrorMessage( `This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND.format()} or later.`, @@ -69,7 +78,9 @@ export class DataExtensionsEditorModule { const modelFile = await pickExtensionPackModelFile( this.cliServer, + db, progress, + token, ); if (!modelFile) { return; @@ -90,7 +101,8 @@ export class DataExtensionsEditorModule { { title: "Opening Data Extensions Editor", }, - ), + ); + }, }; } diff --git a/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts b/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts index 0afe1f81f..24d08e769 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts @@ -18,7 +18,7 @@ import { showAndLogExceptionWithTelemetry, } from "../helpers"; import { extLogger } from "../common"; -import { readFile, writeFile } from "fs-extra"; +import { outputFile, readFile } from "fs-extra"; import { load as loadYaml } from "js-yaml"; import { DatabaseItem, DatabaseManager } from "../local-databases"; import { CodeQLCliServer } from "../cli"; @@ -148,9 +148,13 @@ export class DataExtensionsEditorView extends AbstractWebview< externalApiUsages: ExternalApiUsage[], modeledMethods: Record, ): Promise { - const yaml = createDataExtensionYaml(externalApiUsages, modeledMethods); + const yaml = createDataExtensionYaml( + this.databaseItem.language, + externalApiUsages, + modeledMethods, + ); - await writeFile(this.modelFilename, yaml); + await outputFile(this.modelFilename, yaml); void extLogger.log(`Saved data extension YAML to ${this.modelFilename}`); } @@ -194,7 +198,6 @@ export class DataExtensionsEditorView extends AbstractWebview< queryRunner: this.queryRunner, databaseItem: this.databaseItem, queryStorageDir: this.queryStorageDir, - logger: extLogger, progress: (progressUpdate: ProgressUpdate) => { void this.showProgress(progressUpdate, 1500); }, diff --git a/extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts b/extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts index 4f5c10800..87f2d7220 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/extension-pack-picker.ts @@ -1,21 +1,49 @@ -import { relative, sep } from "path"; -import { window } from "vscode"; +import { join, relative, resolve, sep } from "path"; +import { outputFile, pathExists, readFile } from "fs-extra"; +import { dump as dumpYaml, load as loadYaml } from "js-yaml"; +import { minimatch } from "minimatch"; +import { CancellationToken, window } from "vscode"; import { CodeQLCliServer } from "../cli"; -import { getOnDiskWorkspaceFolders, showAndLogErrorMessage } from "../helpers"; +import { + getOnDiskWorkspaceFolders, + getOnDiskWorkspaceFoldersObjects, + showAndLogErrorMessage, +} from "../helpers"; import { ProgressCallback } from "../progress"; +import { DatabaseItem } from "../local-databases"; +import { getQlPackPath, QLPACK_FILENAMES } from "../pure/ql"; const maxStep = 3; +const packNamePartRegex = /[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/; +const packNameRegex = new RegExp( + `^(?:(?${packNamePartRegex.source})/)?(?${packNamePartRegex.source})$`, +); +const packNameLength = 128; + export async function pickExtensionPackModelFile( cliServer: Pick, + databaseItem: Pick, progress: ProgressCallback, + token: CancellationToken, ): Promise { - const extensionPackPath = await pickExtensionPack(cliServer, progress); + const extensionPackPath = await pickExtensionPack( + cliServer, + databaseItem, + progress, + token, + ); if (!extensionPackPath) { return; } - const modelFile = await pickModelFile(cliServer, progress, extensionPackPath); + const modelFile = await pickModelFile( + cliServer, + databaseItem, + extensionPackPath, + progress, + token, + ); if (!modelFile) { return; } @@ -25,7 +53,9 @@ export async function pickExtensionPackModelFile( async function pickExtensionPack( cliServer: Pick, + databaseItem: Pick, progress: ProgressCallback, + token: CancellationToken, ): Promise { progress({ message: "Resolving extension packs...", @@ -36,10 +66,20 @@ async function pickExtensionPack( // Get all existing extension packs in the workspace const additionalPacks = getOnDiskWorkspaceFolders(); const extensionPacks = await cliServer.resolveQlpacks(additionalPacks, true); - const options = Object.keys(extensionPacks).map((pack) => ({ - label: pack, - extensionPack: pack, - })); + + if (Object.keys(extensionPacks).length === 0) { + return pickNewExtensionPack(databaseItem, token); + } + + const options: Array<{ label: string; extensionPack: string | null }> = + Object.keys(extensionPacks).map((pack) => ({ + label: pack, + extensionPack: pack, + })); + options.push({ + label: "Create new extension pack", + extensionPack: null, + }); progress({ message: "Choosing extension pack...", @@ -47,13 +87,21 @@ async function pickExtensionPack( maxStep, }); - const extensionPackOption = await window.showQuickPick(options, { - title: "Select extension pack to use", - }); + const extensionPackOption = await window.showQuickPick( + options, + { + title: "Select extension pack to use", + }, + token, + ); if (!extensionPackOption) { return undefined; } + if (!extensionPackOption.extensionPack) { + return pickNewExtensionPack(databaseItem, token); + } + const extensionPackPaths = extensionPacks[extensionPackOption.extensionPack]; if (extensionPackPaths.length !== 1) { void showAndLogErrorMessage( @@ -74,8 +122,10 @@ async function pickExtensionPack( async function pickModelFile( cliServer: Pick, - progress: ProgressCallback, + databaseItem: Pick, extensionPackPath: string, + progress: ProgressCallback, + token: CancellationToken, ): Promise { // Find the existing model files in the extension pack const additionalPacks = getOnDiskWorkspaceFolders(); @@ -92,13 +142,21 @@ async function pickModelFile( } } - const fileOptions: Array<{ label: string; file: string }> = []; + if (modelFiles.size === 0) { + return pickNewModelFile(databaseItem, extensionPackPath, token); + } + + const fileOptions: Array<{ label: string; file: string | null }> = []; for (const file of modelFiles) { fileOptions.push({ label: relative(extensionPackPath, file).replaceAll(sep, "/"), file, }); } + fileOptions.push({ + label: "Create new model file", + file: null, + }); progress({ message: "Choosing model file...", @@ -106,13 +164,186 @@ async function pickModelFile( maxStep, }); - const fileOption = await window.showQuickPick(fileOptions, { - title: "Select model file to use", - }); + const fileOption = await window.showQuickPick( + fileOptions, + { + title: "Select model file to use", + }, + token, + ); if (!fileOption) { + return undefined; + } + + if (fileOption.file) { + return fileOption.file; + } + + return pickNewModelFile(databaseItem, extensionPackPath, token); +} + +async function pickNewExtensionPack( + databaseItem: Pick, + token: CancellationToken, +): Promise { + const workspaceFolders = getOnDiskWorkspaceFoldersObjects(); + const workspaceFolderOptions = workspaceFolders.map((folder) => ({ + label: folder.name, + detail: folder.uri.fsPath, + path: folder.uri.fsPath, + })); + + // We're not using window.showWorkspaceFolderPick because that also includes the database source folders while + // we only want to include on-disk workspace folders. + const workspaceFolder = await window.showQuickPick(workspaceFolderOptions, { + title: "Select workspace folder to create extension pack in", + }); + if (!workspaceFolder) { + return undefined; + } + + const packName = await window.showInputBox( + { + title: "Create new extension pack", + prompt: "Enter name of extension pack", + placeHolder: `e.g. ${databaseItem.name}-extensions`, + validateInput: async (value: string): Promise => { + if (!value) { + return "Pack name must not be empty"; + } + + if (value.length > packNameLength) { + return `Pack name must be no longer than ${packNameLength} characters`; + } + + const matches = packNameRegex.exec(value); + if (!matches?.groups) { + return "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens"; + } + + const packPath = join(workspaceFolder.path, matches.groups.name); + if (await pathExists(packPath)) { + return `A pack already exists at ${packPath}`; + } + + return undefined; + }, + }, + token, + ); + if (!packName) { + return undefined; + } + + const matches = packNameRegex.exec(packName); + if (!matches?.groups) { return; } - return fileOption.file; + const name = matches.groups.name; + const packPath = join(workspaceFolder.path, name); + + if (await pathExists(packPath)) { + return undefined; + } + + const packYamlPath = join(packPath, "codeql-pack.yml"); + + await outputFile( + packYamlPath, + dumpYaml({ + name, + version: "0.0.0", + library: true, + extensionTargets: { + [`codeql/${databaseItem.language}-all`]: "*", + }, + dataExtensions: ["models/**/*.yml"], + }), + ); + + return packPath; +} + +async function pickNewModelFile( + databaseItem: Pick, + extensionPackPath: string, + token: CancellationToken, +) { + const qlpackPath = await getQlPackPath(extensionPackPath); + if (!qlpackPath) { + void showAndLogErrorMessage( + `Could not find any of ${QLPACK_FILENAMES.join( + ", ", + )} in ${extensionPackPath}`, + ); + return undefined; + } + + const qlpack = await loadYaml(await readFile(qlpackPath, "utf8"), { + filename: qlpackPath, + }); + if (typeof qlpack !== "object" || qlpack === null) { + void showAndLogErrorMessage(`Could not parse ${qlpackPath}`); + return undefined; + } + + const dataExtensionPatternsValue = qlpack.dataExtensions; + if ( + !( + Array.isArray(dataExtensionPatternsValue) || + typeof dataExtensionPatternsValue === "string" + ) + ) { + void showAndLogErrorMessage( + `Expected 'dataExtensions' to be a string or an array in ${qlpackPath}`, + ); + return undefined; + } + + // The YAML allows either a string or an array of strings + const dataExtensionPatterns = Array.isArray(dataExtensionPatternsValue) + ? dataExtensionPatternsValue + : [dataExtensionPatternsValue]; + + const filename = await window.showInputBox( + { + title: "Enter the name of the new model file", + value: `models/${databaseItem.name.replaceAll("/", ".")}.model.yml`, + validateInput: async (value: string): Promise => { + if (value === "") { + return "File name must not be empty"; + } + + const path = resolve(extensionPackPath, value); + + if (await pathExists(path)) { + return "File already exists"; + } + + const notInExtensionPack = relative(extensionPackPath, path).startsWith( + "..", + ); + if (notInExtensionPack) { + return "File must be in the extension pack"; + } + + const matchesPattern = dataExtensionPatterns.some((pattern) => + minimatch(value, pattern, { matchBase: true }), + ); + if (!matchesPattern) { + return `File must match one of the patterns in 'dataExtensions' in ${qlpackPath}`; + } + + return undefined; + }, + }, + token, + ); + if (!filename) { + return undefined; + } + + return resolve(extensionPackPath, filename); } diff --git a/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts b/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts index a2adecaa8..5d5d7e298 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts @@ -1,25 +1,27 @@ import { CoreCompletedQuery, QueryRunner } from "../queryRunner"; -import { qlpackOfDatabase } from "../contextual/queryResolver"; -import { file } from "tmp-promise"; +import { dir } from "tmp-promise"; import { writeFile } from "fs-extra"; import { dump as dumpYaml } from "js-yaml"; import { getOnDiskWorkspaceFolders, showAndLogExceptionWithTelemetry, } from "../helpers"; -import { Logger, TeeLogger } from "../common"; +import { TeeLogger } from "../common"; import { CancellationToken } from "vscode"; import { CodeQLCliServer } from "../cli"; import { DatabaseItem } from "../local-databases"; import { ProgressCallback } from "../progress"; +import { fetchExternalApiQueries } from "./queries"; +import { QueryResultType } from "../pure/new-messages"; +import { join } from "path"; import { redactableError } from "../pure/errors"; +import { QueryLanguage } from "../common/query-language"; export type RunQueryOptions = { - cliServer: Pick; + cliServer: Pick; queryRunner: Pick; databaseItem: Pick; queryStorageDir: string; - logger: Logger; progress: ProgressCallback; token: CancellationToken; @@ -30,54 +32,53 @@ export async function runQuery({ queryRunner, databaseItem, queryStorageDir, - logger, progress, token, }: RunQueryOptions): Promise { - const qlpacks = await qlpackOfDatabase(cliServer, databaseItem); + // The below code is temporary to allow for rapid prototyping of the queries. Once the queries are stabilized, we will + // move these queries into the `github/codeql` repository and use them like any other contextual (e.g. AST) queries. + // This is intentionally not pretty code, as it will be removed soon. + // For a reference of what this should do in the future, see the previous implementation in + // https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72 - const packsToSearch = [qlpacks.dbschemePack]; - if (qlpacks.queryPack) { - packsToSearch.push(qlpacks.queryPack); + const query = fetchExternalApiQueries[databaseItem.language as QueryLanguage]; + if (!query) { + void showAndLogExceptionWithTelemetry( + redactableError`No external API usage query found for language ${databaseItem.language}`, + ); + return; } - const suiteFile = ( - await file({ - postfix: ".qls", - }) - ).path; - const suiteYaml = []; - for (const qlpack of packsToSearch) { - suiteYaml.push({ - from: qlpack, - queries: ".", - include: { - id: `${databaseItem.language}/telemetry/fetch-external-apis`, - }, - }); + const queryDir = (await dir({ unsafeCleanup: true })).path; + const queryFile = join(queryDir, "FetchExternalApis.ql"); + await writeFile(queryFile, query.mainQuery, "utf8"); + + if (query.dependencies) { + for (const [filename, contents] of Object.entries(query.dependencies)) { + const dependencyFile = join(queryDir, filename); + await writeFile(dependencyFile, contents, "utf8"); + } } - await writeFile(suiteFile, dumpYaml(suiteYaml), "utf8"); + + const syntheticQueryPack = { + name: "codeql/external-api-usage", + version: "0.0.0", + dependencies: { + [`codeql/${databaseItem.language}-all`]: "*", + }, + }; + + const qlpackFile = join(queryDir, "codeql-pack.yml"); + await writeFile(qlpackFile, dumpYaml(syntheticQueryPack), "utf8"); const additionalPacks = getOnDiskWorkspaceFolders(); const extensionPacks = Object.keys( await cliServer.resolveQlpacks(additionalPacks, true), ); - const queries = await cliServer.resolveQueriesInSuite( - suiteFile, - getOnDiskWorkspaceFolders(), - ); - - if (queries.length !== 1) { - void logger.log(`Expected exactly one query, got ${queries.length}`); - return; - } - - const query = queries[0]; - const queryRun = queryRunner.createQueryRun( databaseItem.databaseUri.fsPath, - { queryPath: query, quickEvalPosition: undefined }, + { queryPath: queryFile, quickEvalPosition: undefined }, false, getOnDiskWorkspaceFolders(), extensionPacks, @@ -86,11 +87,22 @@ export async function runQuery({ undefined, ); - return queryRun.evaluate( + const completedQuery = await queryRun.evaluate( progress, token, new TeeLogger(queryRunner.logger, queryRun.outputDir.logPath), ); + + if (completedQuery.resultType !== QueryResultType.SUCCESS) { + void showAndLogExceptionWithTelemetry( + redactableError`External API usage query failed: ${ + completedQuery.message ?? "No message" + }`, + ); + return; + } + + return completedQuery; } export type GetResultsOptions = { diff --git a/extensions/ql-vscode/src/data-extensions-editor/generate-flow-model.ts b/extensions/ql-vscode/src/data-extensions-editor/generate-flow-model.ts index aa7c54acf..fdc6bbf07 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/generate-flow-model.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/generate-flow-model.ts @@ -4,7 +4,7 @@ import { join } from "path"; import { QueryRunner } from "../queryRunner"; import { CodeQLCliServer } from "../cli"; import { TeeLogger } from "../common"; -import { extensiblePredicateDefinitions } from "./yaml"; +import { extensiblePredicateDefinitions } from "./predicates"; import { ProgressCallback } from "../progress"; import { getOnDiskWorkspaceFolders, diff --git a/extensions/ql-vscode/src/data-extensions-editor/predicates.ts b/extensions/ql-vscode/src/data-extensions-editor/predicates.ts new file mode 100644 index 000000000..f52115163 --- /dev/null +++ b/extensions/ql-vscode/src/data-extensions-editor/predicates.ts @@ -0,0 +1,138 @@ +import { ExternalApiUsage } from "./external-api-usage"; +import { + ModeledMethod, + ModeledMethodType, + ModeledMethodWithSignature, +} from "./modeled-method"; + +export type ExternalApiUsageByType = { + externalApiUsage: ExternalApiUsage; + modeledMethod: ModeledMethod; +}; + +export type ExtensiblePredicateDefinition = { + extensiblePredicate: string; + generateMethodDefinition: (method: ExternalApiUsageByType) => Tuple[]; + readModeledMethod: (row: Tuple[]) => ModeledMethodWithSignature; + + supportedKinds?: string[]; +}; + +type Tuple = boolean | number | string; + +function readRowToMethod(row: Tuple[]): string { + return `${row[0]}.${row[1]}#${row[3]}${row[4]}`; +} + +export const extensiblePredicateDefinitions: Record< + Exclude, + ExtensiblePredicateDefinition +> = { + source: { + extensiblePredicate: "sourceModel", + // extensible predicate sourceModel( + // string package, string type, boolean subtypes, string name, string signature, string ext, + // string output, string kind, string provenance + // ); + generateMethodDefinition: (method) => [ + method.externalApiUsage.packageName, + method.externalApiUsage.typeName, + true, + method.externalApiUsage.methodName, + method.externalApiUsage.methodParameters, + "", + method.modeledMethod.output, + method.modeledMethod.kind, + "manual", + ], + readModeledMethod: (row) => ({ + signature: readRowToMethod(row), + modeledMethod: { + type: "source", + input: "", + output: row[6] as string, + kind: row[7] as string, + }, + }), + supportedKinds: ["remote"], + }, + sink: { + extensiblePredicate: "sinkModel", + // extensible predicate sinkModel( + // string package, string type, boolean subtypes, string name, string signature, string ext, + // string input, string kind, string provenance + // ); + generateMethodDefinition: (method) => [ + method.externalApiUsage.packageName, + method.externalApiUsage.typeName, + true, + method.externalApiUsage.methodName, + method.externalApiUsage.methodParameters, + "", + method.modeledMethod.input, + method.modeledMethod.kind, + "manual", + ], + readModeledMethod: (row) => ({ + signature: readRowToMethod(row), + modeledMethod: { + type: "sink", + input: row[6] as string, + output: "", + kind: row[7] as string, + }, + }), + supportedKinds: ["sql", "xss", "logging"], + }, + summary: { + extensiblePredicate: "summaryModel", + // extensible predicate summaryModel( + // string package, string type, boolean subtypes, string name, string signature, string ext, + // string input, string output, string kind, string provenance + // ); + generateMethodDefinition: (method) => [ + method.externalApiUsage.packageName, + method.externalApiUsage.typeName, + true, + method.externalApiUsage.methodName, + method.externalApiUsage.methodParameters, + "", + method.modeledMethod.input, + method.modeledMethod.output, + method.modeledMethod.kind, + "manual", + ], + readModeledMethod: (row) => ({ + signature: readRowToMethod(row), + modeledMethod: { + type: "summary", + input: row[6] as string, + output: row[7] as string, + kind: row[8] as string, + }, + }), + supportedKinds: ["taint", "value"], + }, + neutral: { + extensiblePredicate: "neutralModel", + // extensible predicate neutralModel( + // string package, string type, string name, string signature, string provenance + // ); + generateMethodDefinition: (method) => [ + method.externalApiUsage.packageName, + method.externalApiUsage.typeName, + method.externalApiUsage.methodName, + method.externalApiUsage.methodParameters, + "manual", + ], + readModeledMethod: (row) => ({ + signature: `${row[0]}.${row[1]}#${row[2]}${row[3]}`, + modeledMethod: { + type: "neutral", + input: "", + output: "", + kind: "", + }, + }), + }, +}; diff --git a/extensions/ql-vscode/src/data-extensions-editor/queries/csharp.ts b/extensions/ql-vscode/src/data-extensions-editor/queries/csharp.ts new file mode 100644 index 000000000..5e2bcb93d --- /dev/null +++ b/extensions/ql-vscode/src/data-extensions-editor/queries/csharp.ts @@ -0,0 +1,198 @@ +import { Query } from "./query"; + +export const fetchExternalApisQuery: Query = { + mainQuery: `/** + * @name Usage of APIs coming from external libraries + * @description A list of 3rd party APIs used in the codebase. + * @tags telemetry + * @id cs/telemetry/fetch-external-apis + */ + + import csharp + import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl + import ExternalApi + + private Call aUsage(ExternalApi api) { + result.getTarget().getUnboundDeclaration() = api + } + + private boolean isSupported(ExternalApi api) { + api.isSupported() and result = true + or + not api.isSupported() and + result = false + } + + from ExternalApi api, string apiName, boolean supported, Call usage + where + apiName = api.getApiName() and + supported = isSupported(api) and + usage = aUsage(api) + select apiName, supported, usage +`, + dependencies: { + "ExternalApi.qll": `/** Provides classes and predicates related to handling APIs from external libraries. */ + +private import csharp +private import dotnet +private import semmle.code.csharp.dispatch.Dispatch +private import semmle.code.csharp.dataflow.ExternalFlow +private import semmle.code.csharp.dataflow.FlowSummary +private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate +private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch +private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl +private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate +private import semmle.code.csharp.security.dataflow.flowsources.Remote + +pragma[nomagic] +private predicate isTestNamespace(Namespace ns) { + ns.getFullName() + .matches([ + "NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%" + ]) +} + +/** + * A test library. + */ +class TestLibrary extends RefType { + TestLibrary() { isTestNamespace(this.getNamespace()) } +} + +/** Holds if the given callable is not worth supporting. */ +private predicate isUninteresting(DotNet::Callable c) { + c.getDeclaringType() instanceof TestLibrary or + c.(Constructor).isParameterless() +} + +/** + * An external API from either the C# Standard Library or a 3rd party library. + */ +class ExternalApi extends DotNet::Callable { + ExternalApi() { + this.isUnboundDeclaration() and + this.fromLibrary() and + this.(Modifiable).isEffectivelyPublic() and + not isUninteresting(this) + } + + /** + * Gets the unbound type, name and parameter types of this API. + */ + bindingset[this] + private string getSignature() { + result = + this.getDeclaringType().getUnboundDeclaration() + "." + this.getName() + "(" + + parameterQualifiedTypeNamesToString(this) + ")" + } + + /** + * Gets the namespace of this API. + */ + bindingset[this] + string getNamespace() { this.getDeclaringType().hasQualifiedName(result, _) } + + /** + * Gets the namespace and signature of this API. + */ + bindingset[this] + string getApiName() { result = this.getNamespace() + "#" + this.getSignature() } + + /** Gets a node that is an input to a call to this API. */ + private ArgumentNode getAnInput() { + result + .getCall() + .(DataFlowDispatch::NonDelegateDataFlowCall) + .getATarget(_) + .getUnboundDeclaration() = this + } + + /** Gets a node that is an output from a call to this API. */ + private DataFlow::Node getAnOutput() { + exists( + Call c, DataFlowDispatch::NonDelegateDataFlowCall dc, DataFlowImplCommon::ReturnKindExt ret + | + dc.getDispatchCall().getCall() = c and + c.getTarget().getUnboundDeclaration() = this + | + result = ret.getAnOutNode(dc) + ) + } + + /** Holds if this API has a supported summary. */ + pragma[nomagic] + predicate hasSummary() { + this instanceof SummarizedCallable + or + defaultAdditionalTaintStep(this.getAnInput(), _) + } + + /** Holds if this API is a known source. */ + pragma[nomagic] + predicate isSource() { + this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _) + } + + /** Holds if this API is a known sink. */ + pragma[nomagic] + predicate isSink() { sinkNode(this.getAnInput(), _) } + + /** Holds if this API is a known neutral. */ + pragma[nomagic] + predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable } + + /** + * Holds if this API is supported by existing CodeQL libraries, that is, it is either a + * recognized source, sink or neutral or it has a flow summary. + */ + predicate isSupported() { + this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral() + } +} + +/** + * Gets the limit for the number of results produced by a telemetry query. + */ +int resultLimit() { result = 1000 } + +/** + * Holds if it is relevant to count usages of "api". + */ +signature predicate relevantApi(ExternalApi api); + +/** + * Given a predicate to count relevant API usages, this module provides a predicate + * for restricting the number or returned results based on a certain limit. + */ +module Results { + private int getUsages(string apiName) { + result = + strictcount(Call c, ExternalApi api | + c.getTarget().getUnboundDeclaration() = api and + apiName = api.getApiName() and + getRelevantUsages(api) + ) + } + + private int getOrder(string apiName) { + apiName = + rank[result](string name, int usages | + usages = getUsages(name) + | + name order by usages desc, name + ) + } + + /** + * Holds if there exists an API with "apiName" that is being used "usages" times + * and if it is in the top results (guarded by resultLimit). + */ + predicate restrict(string apiName, int usages) { + usages = getUsages(apiName) and + getOrder(apiName) <= resultLimit() + } +} +`, + }, +}; diff --git a/extensions/ql-vscode/src/data-extensions-editor/queries/index.ts b/extensions/ql-vscode/src/data-extensions-editor/queries/index.ts new file mode 100644 index 000000000..bbf5320ac --- /dev/null +++ b/extensions/ql-vscode/src/data-extensions-editor/queries/index.ts @@ -0,0 +1,9 @@ +import { fetchExternalApisQuery as csharpFetchExternalApisQuery } from "./csharp"; +import { fetchExternalApisQuery as javaFetchExternalApisQuery } from "./java"; +import { Query } from "./query"; +import { QueryLanguage } from "../../common/query-language"; + +export const fetchExternalApiQueries: Partial> = { + [QueryLanguage.CSharp]: csharpFetchExternalApisQuery, + [QueryLanguage.Java]: javaFetchExternalApisQuery, +}; diff --git a/extensions/ql-vscode/src/data-extensions-editor/queries/java.ts b/extensions/ql-vscode/src/data-extensions-editor/queries/java.ts new file mode 100644 index 000000000..433fff8ca --- /dev/null +++ b/extensions/ql-vscode/src/data-extensions-editor/queries/java.ts @@ -0,0 +1,179 @@ +import { Query } from "./query"; + +export const fetchExternalApisQuery: Query = { + mainQuery: `/** + * @name Usage of APIs coming from external libraries + * @description A list of 3rd party APIs used in the codebase. Excludes test and generated code. + * @tags telemetry + * @id java/telemetry/fetch-external-apis + */ + +import java +import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl +import ExternalApi + +private Call aUsage(ExternalApi api) { + result.getCallee().getSourceDeclaration() = api and + not result.getFile() instanceof GeneratedFile +} + +private boolean isSupported(ExternalApi api) { + api.isSupported() and result = true + or + not api.isSupported() and result = false +} + +from ExternalApi api, string apiName, boolean supported, Call usage +where + apiName = api.getApiName() and + supported = isSupported(api) and + usage = aUsage(api) +select apiName, supported, usage +`, + dependencies: { + "ExternalApi.qll": `/** Provides classes and predicates related to handling APIs from external libraries. */ + +private import java +private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.dataflow.ExternalFlow +private import semmle.code.java.dataflow.FlowSources +private import semmle.code.java.dataflow.FlowSummary +private import semmle.code.java.dataflow.internal.DataFlowPrivate +private import semmle.code.java.dataflow.TaintTracking + +pragma[nomagic] +private predicate isTestPackage(Package p) { + p.getName() + .matches([ + "org.junit%", "junit.%", "org.mockito%", "org.assertj%", + "com.github.tomakehurst.wiremock%", "org.hamcrest%", "org.springframework.test.%", + "org.springframework.mock.%", "org.springframework.boot.test.%", "reactor.test%", + "org.xmlunit%", "org.testcontainers.%", "org.opentest4j%", "org.mockserver%", + "org.powermock%", "org.skyscreamer.jsonassert%", "org.rnorth.visibleassertions", + "org.openqa.selenium%", "com.gargoylesoftware.htmlunit%", "org.jboss.arquillian.testng%", + "org.testng%" + ]) +} + +/** + * A test library. + */ +private class TestLibrary extends RefType { + TestLibrary() { isTestPackage(this.getPackage()) } +} + +private string containerAsJar(Container container) { + if container instanceof JarFile then result = container.getBaseName() else result = "rt.jar" +} + +/** Holds if the given callable is not worth supporting. */ +private predicate isUninteresting(Callable c) { + c.getDeclaringType() instanceof TestLibrary or + c.(Constructor).isParameterless() +} + +/** + * An external API from either the Standard Library or a 3rd party library. + */ +class ExternalApi extends Callable { + ExternalApi() { not this.fromSource() and not isUninteresting(this) } + + /** + * Gets information about the external API in the form expected by the MaD modeling framework. + */ + string getApiName() { + result = + this.getDeclaringType().getPackage() + "." + this.getDeclaringType().getSourceDeclaration() + + "#" + this.getName() + paramsString(this) + } + + /** + * Gets the jar file containing this API. Normalizes the Java Runtime to "rt.jar" despite the presence of modules. + */ + string jarContainer() { result = containerAsJar(this.getCompilationUnit().getParentContainer*()) } + + /** Gets a node that is an input to a call to this API. */ + private DataFlow::Node getAnInput() { + exists(Call call | call.getCallee().getSourceDeclaration() = this | + result.asExpr().(Argument).getCall() = call or + result.(ArgumentNode).getCall().asCall() = call + ) + } + + /** Gets a node that is an output from a call to this API. */ + private DataFlow::Node getAnOutput() { + exists(Call call | call.getCallee().getSourceDeclaration() = this | + result.asExpr() = call or + result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call + ) + } + + /** Holds if this API has a supported summary. */ + pragma[nomagic] + predicate hasSummary() { + this = any(SummarizedCallable sc).asCallable() or + TaintTracking::localAdditionalTaintStep(this.getAnInput(), _) + } + + pragma[nomagic] + predicate isSource() { + this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _) + } + + /** Holds if this API is a known sink. */ + pragma[nomagic] + predicate isSink() { sinkNode(this.getAnInput(), _) } + + /** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */ + predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() } +} + +/** DEPRECATED: Alias for ExternalApi */ +deprecated class ExternalAPI = ExternalApi; + +/** + * Gets the limit for the number of results produced by a telemetry query. + */ +int resultLimit() { result = 1000 } + +/** + * Holds if it is relevant to count usages of \`api\`. + */ +signature predicate relevantApi(ExternalApi api); + +/** + * Given a predicate to count relevant API usages, this module provides a predicate + * for restricting the number or returned results based on a certain limit. + */ +module Results { + private int getUsages(string apiName) { + result = + strictcount(Call c, ExternalApi api | + c.getCallee().getSourceDeclaration() = api and + not c.getFile() instanceof GeneratedFile and + apiName = api.getApiName() and + getRelevantUsages(api) + ) + } + + private int getOrder(string apiInfo) { + apiInfo = + rank[result](string info, int usages | + usages = getUsages(info) + | + info order by usages desc, info + ) + } + + /** + * Holds if there exists an API with \`apiName\` that is being used \`usages\` times + * and if it is in the top results (guarded by resultLimit). + */ + predicate restrict(string apiName, int usages) { + usages = getUsages(apiName) and + getOrder(apiName) <= resultLimit() + } +} +`, + }, +}; diff --git a/extensions/ql-vscode/src/data-extensions-editor/queries/query.ts b/extensions/ql-vscode/src/data-extensions-editor/queries/query.ts new file mode 100644 index 000000000..72f239529 --- /dev/null +++ b/extensions/ql-vscode/src/data-extensions-editor/queries/query.ts @@ -0,0 +1,6 @@ +export type Query = { + mainQuery: string; + dependencies?: { + [filename: string]: string; + }; +}; diff --git a/extensions/ql-vscode/src/data-extensions-editor/yaml.ts b/extensions/ql-vscode/src/data-extensions-editor/yaml.ts index b66f21a60..903272748 100644 --- a/extensions/ql-vscode/src/data-extensions-editor/yaml.ts +++ b/extensions/ql-vscode/src/data-extensions-editor/yaml.ts @@ -6,6 +6,7 @@ import { ModeledMethodType, ModeledMethodWithSignature, } from "./modeled-method"; +import { extensiblePredicateDefinitions } from "./predicates"; import * as dataSchemaJson from "./data-schema.json"; @@ -23,120 +24,6 @@ type ExtensiblePredicateDefinition = { readModeledMethod: (row: any[]) => ModeledMethodWithSignature; }; -function readRowToMethod(row: any[]): string { - return `${row[0]}.${row[1]}#${row[3]}${row[4]}`; -} - -export const extensiblePredicateDefinitions: Record< - Exclude, - ExtensiblePredicateDefinition -> = { - source: { - extensiblePredicate: "sourceModel", - // extensible predicate sourceModel( - // string package, string type, boolean subtypes, string name, string signature, string ext, - // string output, string kind, string provenance - // ); - generateMethodDefinition: (method) => [ - method.externalApiUsage.packageName, - method.externalApiUsage.typeName, - true, - method.externalApiUsage.methodName, - method.externalApiUsage.methodParameters, - "", - method.modeledMethod.output, - method.modeledMethod.kind, - "manual", - ], - readModeledMethod: (row) => ({ - signature: readRowToMethod(row), - modeledMethod: { - type: "source", - input: "", - output: row[6], - kind: row[7], - }, - }), - }, - sink: { - extensiblePredicate: "sinkModel", - // extensible predicate sinkModel( - // string package, string type, boolean subtypes, string name, string signature, string ext, - // string input, string kind, string provenance - // ); - generateMethodDefinition: (method) => [ - method.externalApiUsage.packageName, - method.externalApiUsage.typeName, - true, - method.externalApiUsage.methodName, - method.externalApiUsage.methodParameters, - "", - method.modeledMethod.input, - method.modeledMethod.kind, - "manual", - ], - readModeledMethod: (row) => ({ - signature: readRowToMethod(row), - modeledMethod: { - type: "sink", - input: row[6], - output: "", - kind: row[7], - }, - }), - }, - summary: { - extensiblePredicate: "summaryModel", - // extensible predicate summaryModel( - // string package, string type, boolean subtypes, string name, string signature, string ext, - // string input, string output, string kind, string provenance - // ); - generateMethodDefinition: (method) => [ - method.externalApiUsage.packageName, - method.externalApiUsage.typeName, - true, - method.externalApiUsage.methodName, - method.externalApiUsage.methodParameters, - "", - method.modeledMethod.input, - method.modeledMethod.output, - method.modeledMethod.kind, - "manual", - ], - readModeledMethod: (row) => ({ - signature: readRowToMethod(row), - modeledMethod: { - type: "summary", - input: row[6], - output: row[7], - kind: row[8], - }, - }), - }, - neutral: { - extensiblePredicate: "neutralModel", - // extensible predicate neutralModel( - // string package, string type, string name, string signature, string provenance - // ); - generateMethodDefinition: (method) => [ - method.externalApiUsage.packageName, - method.externalApiUsage.typeName, - method.externalApiUsage.methodName, - method.externalApiUsage.methodParameters, - "manual", - ], - readModeledMethod: (row) => ({ - signature: `${row[0]}.${row[1]}#${row[2]}${row[3]}`, - modeledMethod: { - type: "neutral", - input: "", - output: "", - kind: "", - }, - }), - }, -}; - function createDataProperty( methods: ExternalApiUsageByType[], definition: ExtensiblePredicateDefinition, @@ -156,6 +43,7 @@ function createDataProperty( } export function createDataExtensionYaml( + language: string, externalApiUsages: ExternalApiUsage[], modeledMethods: Record, ) { @@ -182,7 +70,7 @@ export function createDataExtensionYaml( const extensions = Object.entries(extensiblePredicateDefinitions).map( ([type, definition]) => ` - addsTo: - pack: codeql/java-all + pack: codeql/${language}-all extensible: ${definition.extensiblePredicate} data:${createDataProperty( methodsByType[type as Exclude], diff --git a/extensions/ql-vscode/src/databases/ui/db-panel.ts b/extensions/ql-vscode/src/databases/ui/db-panel.ts index 80a0eec5b..7ea333681 100644 --- a/extensions/ql-vscode/src/databases/ui/db-panel.ts +++ b/extensions/ql-vscode/src/databases/ui/db-panel.ts @@ -34,11 +34,11 @@ import { DatabasePanelCommands } from "../../common/commands"; import { App } from "../../common/app"; export interface RemoteDatabaseQuickPickItem extends QuickPickItem { - kind: string; + remoteDatabaseKind: string; } export interface AddListQuickPickItem extends QuickPickItem { - kind: DbListKind; + databaseKind: DbListKind; } export class DbPanel extends DisposableObject { @@ -113,19 +113,19 @@ export class DbPanel extends DisposableObject { ) { await this.addNewRemoteRepo(highlightedItem.parentListName); } else { - const quickPickItems = [ + const quickPickItems: RemoteDatabaseQuickPickItem[] = [ { label: "$(repo) From a GitHub repository", detail: "Add a variant analysis repository from GitHub", alwaysShow: true, - kind: "repo", + remoteDatabaseKind: "repo", }, { label: "$(organization) All repositories of a GitHub org or owner", detail: "Add a variant analysis list of repositories from a GitHub organization/owner", alwaysShow: true, - kind: "owner", + remoteDatabaseKind: "owner", }, ]; const databaseKind = @@ -142,9 +142,9 @@ export class DbPanel extends DisposableObject { // We set 'true' to make this a silent exception. throw new UserCancellationException("No repository selected", true); } - if (databaseKind.kind === "repo") { + if (databaseKind.remoteDatabaseKind === "repo") { await this.addNewRemoteRepo(); - } else if (databaseKind.kind === "owner") { + } else if (databaseKind.remoteDatabaseKind === "owner") { await this.addNewRemoteOwner(); } } diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 6c56e0baf..d6e3a1309 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -177,7 +177,13 @@ function getCommands( cliServer.restartCliServer(); await Promise.all([ queryRunner.restartQueryServer(progress, token), - ideServer.restart(), + async () => { + if (ideServer.isRunning()) { + await ideServer.restart(); + } else { + await ideServer.start(); + } + }, ]); void showAndLogInformationMessage("CodeQL Query Server restarted.", { outputLogger: queryServerLogger, diff --git a/extensions/ql-vscode/src/helpers.ts b/extensions/ql-vscode/src/helpers.ts index c8d1839e0..755e9bbba 100644 --- a/extensions/ql-vscode/src/helpers.ts +++ b/extensions/ql-vscode/src/helpers.ts @@ -8,7 +8,7 @@ import { } from "fs-extra"; import { glob } from "glob"; import { load } from "js-yaml"; -import { join, basename } from "path"; +import { join, basename, dirname } from "path"; import { dirSync } from "tmp-promise"; import { ExtensionContext, @@ -16,6 +16,7 @@ import { window as Window, workspace, env, + WorkspaceFolder, } from "vscode"; import { CodeQLCliServer, QlpacksInfo } from "./cli"; import { UserCancellationException } from "./progress"; @@ -249,16 +250,21 @@ export async function showInformationMessageWithAction( } /** Gets all active workspace folders that are on the filesystem. */ -export function getOnDiskWorkspaceFolders() { +export function getOnDiskWorkspaceFoldersObjects() { const workspaceFolders = workspace.workspaceFolders || []; - const diskWorkspaceFolders: string[] = []; + const diskWorkspaceFolders: WorkspaceFolder[] = []; for (const workspaceFolder of workspaceFolders) { if (workspaceFolder.uri.scheme === "file") - diskWorkspaceFolders.push(workspaceFolder.uri.fsPath); + diskWorkspaceFolders.push(workspaceFolder); } return diskWorkspaceFolders; } +/** Gets all active workspace folders that are on the filesystem. */ +export function getOnDiskWorkspaceFolders() { + return getOnDiskWorkspaceFoldersObjects().map((folder) => folder.uri.fsPath); +} + /** Check if folder is already present in workspace */ export function isFolderAlreadyInWorkspace(folderName: string) { const workspaceFolders = workspace.workspaceFolders || []; @@ -785,3 +791,39 @@ export async function* walkDirectory( } } } + +/** + * Returns the path of the first folder in the workspace. + * This is used to decide where to create skeleton QL packs. + * + * If the first folder is a QL pack, then the parent folder is returned. + * This is because the vscode-codeql-starter repo contains a ql pack in + * the first folder. + * + * This is a temporary workaround until we can retire the + * vscode-codeql-starter repo. + */ + +export function getFirstWorkspaceFolder() { + const workspaceFolders = getOnDiskWorkspaceFolders(); + + if (!workspaceFolders || workspaceFolders.length === 0) { + throw new Error("No workspace folders found"); + } + + const firstFolderFsPath = workspaceFolders[0]; + + // For the vscode-codeql-starter repo, the first folder will be a ql pack + // so we need to get the parent folder + if ( + firstFolderFsPath.includes( + join("vscode-codeql-starter", "codeql-custom-queries"), + ) + ) { + // return the parent folder + return dirname(firstFolderFsPath); + } else { + // if the first folder is not a ql pack, then we are in a normal workspace + return firstFolderFsPath; + } +} diff --git a/extensions/ql-vscode/src/json-rpc-server.ts b/extensions/ql-vscode/src/json-rpc-server.ts index d6f7db2c8..88f656b54 100644 --- a/extensions/ql-vscode/src/json-rpc-server.ts +++ b/extensions/ql-vscode/src/json-rpc-server.ts @@ -23,6 +23,7 @@ export class ServerProcess implements Disposable { dispose(): void { void this.logger.log(`Stopping ${this.name}...`); this.connection.dispose(); + this.connection.end(); this.child.stdin!.end(); this.child.stderr!.destroy(); // TODO kill the process if it doesn't terminate after a certain time limit. diff --git a/extensions/ql-vscode/src/local-databases.ts b/extensions/ql-vscode/src/local-databases.ts index a4e32a5d0..9b0b35bd8 100644 --- a/extensions/ql-vscode/src/local-databases.ts +++ b/extensions/ql-vscode/src/local-databases.ts @@ -11,6 +11,7 @@ import { showAndLogExceptionWithTelemetry, isFolderAlreadyInWorkspace, showBinaryChoiceDialog, + getFirstWorkspaceFolder, } from "./helpers"; import { ProgressCallback, withProgress } from "./progress"; import { @@ -29,6 +30,7 @@ import { isCodespacesTemplate } from "./config"; import { QlPackGenerator } from "./qlpack-generator"; import { QueryLanguage } from "./common/query-language"; import { App } from "./common/app"; +import { existsSync } from "fs"; /** * databases.ts @@ -662,8 +664,13 @@ export class DatabaseManager extends DisposableObject { return; } + const firstWorkspaceFolder = getFirstWorkspaceFolder(); const folderName = `codeql-custom-queries-${databaseItem.language}`; - if (isFolderAlreadyInWorkspace(folderName)) { + + if ( + existsSync(join(firstWorkspaceFolder, folderName)) || + isFolderAlreadyInWorkspace(folderName) + ) { return; } @@ -680,7 +687,7 @@ export class DatabaseManager extends DisposableObject { folderName, databaseItem.language as QueryLanguage, this.cli, - this.ctx.storageUri?.fsPath, + firstWorkspaceFolder, ); await qlPackGenerator.generate(); } catch (e: unknown) { @@ -1022,7 +1029,19 @@ export class DatabaseManager extends DisposableObject { token: vscode.CancellationToken, dbItem: DatabaseItem, ) { - await this.qs.deregisterDatabase(progress, token, dbItem); + try { + await this.qs.deregisterDatabase(progress, token, dbItem); + } catch (e) { + const message = getErrorMessage(e); + if (message === "Connection is disposed.") { + // This is expected if the query server is not running. + void extLogger.log( + `Could not de-register database '${dbItem.name}' because query server is not running.`, + ); + return; + } + throw e; + } } private async registerDatabase( progress: ProgressCallback, diff --git a/extensions/ql-vscode/src/qlpack-generator.ts b/extensions/ql-vscode/src/qlpack-generator.ts index a7efc3f3d..b87cf1351 100644 --- a/extensions/ql-vscode/src/qlpack-generator.ts +++ b/extensions/ql-vscode/src/qlpack-generator.ts @@ -1,7 +1,7 @@ -import { writeFile } from "fs-extra"; +import { mkdir, writeFile } from "fs-extra"; import { dump } from "js-yaml"; import { join } from "path"; -import { Uri, workspace } from "vscode"; +import { Uri } from "vscode"; import { CodeQLCliServer } from "./cli"; import { QueryLanguage } from "./common/query-language"; @@ -44,14 +44,7 @@ export class QlPackGenerator { } private async createWorkspaceFolder() { - await workspace.fs.createDirectory(this.folderUri); - - const end = (workspace.workspaceFolders || []).length; - - workspace.updateWorkspaceFolders(end, 0, { - name: this.folderName, - uri: this.folderUri, - }); + await mkdir(this.folderUri.fsPath); } private async createQlPackYaml() { diff --git a/extensions/ql-vscode/src/query-history/store/query-history-domain-mapper.ts b/extensions/ql-vscode/src/query-history/store/query-history-domain-mapper.ts index 05579f224..8df99b18f 100644 --- a/extensions/ql-vscode/src/query-history/store/query-history-domain-mapper.ts +++ b/extensions/ql-vscode/src/query-history/store/query-history-domain-mapper.ts @@ -1,34 +1,15 @@ import { assertNever } from "../../pure/helpers-pure"; -import { - LocalQueryInfo, - InitialQueryInfo, - CompletedQueryInfo, -} from "../../query-results"; -import { QueryEvaluationInfo } from "../../run-queries-shared"; import { QueryHistoryInfo } from "../query-history-info"; -import { - QueryHistoryLocalQueryDto, - InitialQueryInfoDto, - QueryEvaluationInfoDto, - CompletedQueryInfoDto, - SortedResultSetInfoDto, - SortDirectionDto, -} from "./query-history-local-query-dto"; +import { mapLocalQueryInfoToDto } from "./query-history-local-query-domain-mapper"; import { QueryHistoryItemDto } from "./query-history-dto"; -import { QueryHistoryVariantAnalysisDto } from "./query-history-variant-analysis-dto"; -import { - RawResultsSortState, - SortDirection, - SortedResultSetInfo, -} from "../../pure/interface-types"; +import { mapQueryHistoryVariantAnalysisToDto } from "./query-history-variant-analysis-domain-mapper"; export function mapQueryHistoryToDto( queries: QueryHistoryInfo[], ): QueryHistoryItemDto[] { return queries.map((q) => { if (q.t === "variant-analysis") { - const query: QueryHistoryVariantAnalysisDto = q; - return query; + return mapQueryHistoryVariantAnalysisToDto(q); } else if (q.t === "local") { return mapLocalQueryInfoToDto(q); } else { @@ -36,105 +17,3 @@ export function mapQueryHistoryToDto( } }); } - -function mapLocalQueryInfoToDto( - query: LocalQueryInfo, -): QueryHistoryLocalQueryDto { - return { - initialInfo: mapInitialQueryInfoToDto(query.initialInfo), - t: "local", - evalLogLocation: query.evalLogLocation, - evalLogSummaryLocation: query.evalLogSummaryLocation, - jsonEvalLogSummaryLocation: query.jsonEvalLogSummaryLocation, - evalLogSummarySymbolsLocation: query.evalLogSummarySymbolsLocation, - failureReason: query.failureReason, - completedQuery: - query.completedQuery && mapCompletedQueryToDto(query.completedQuery), - }; -} - -function mapCompletedQueryToDto( - query: CompletedQueryInfo, -): CompletedQueryInfoDto { - const sortedResults = Object.fromEntries( - Object.entries(query.sortedResultsInfo).map(([key, value]) => { - return [key, mapSortedResultSetInfoToDto(value)]; - }), - ); - - return { - query: mapQueryEvaluationInfoToDto(query.query), - result: { - runId: query.result.runId, - queryId: query.result.queryId, - resultType: query.result.resultType, - evaluationTime: query.result.evaluationTime, - message: query.result.message, - logFileLocation: query.result.logFileLocation, - }, - logFileLocation: query.logFileLocation, - successful: query.successful, - message: query.message, - resultCount: query.resultCount, - sortedResultsInfo: sortedResults, - }; -} - -function mapSortDirectionToDto(sortDirection: SortDirection): SortDirectionDto { - switch (sortDirection) { - case SortDirection.asc: - return SortDirectionDto.asc; - case SortDirection.desc: - return SortDirectionDto.desc; - } -} - -function mapRawResultsSortStateToDto( - sortState: RawResultsSortState, -): SortedResultSetInfoDto["sortState"] { - return { - columnIndex: sortState.columnIndex, - sortDirection: mapSortDirectionToDto(sortState.sortDirection), - }; -} - -function mapSortedResultSetInfoToDto( - resultSet: SortedResultSetInfo, -): SortedResultSetInfoDto { - return { - resultsPath: resultSet.resultsPath, - sortState: mapRawResultsSortStateToDto(resultSet.sortState), - }; -} - -function mapInitialQueryInfoToDto( - localQueryInitialInfo: InitialQueryInfo, -): InitialQueryInfoDto { - return { - userSpecifiedLabel: localQueryInitialInfo.userSpecifiedLabel, - queryText: localQueryInitialInfo.queryText, - isQuickQuery: localQueryInitialInfo.isQuickQuery, - isQuickEval: localQueryInitialInfo.isQuickEval, - quickEvalPosition: localQueryInitialInfo.quickEvalPosition, - queryPath: localQueryInitialInfo.queryPath, - databaseInfo: { - databaseUri: localQueryInitialInfo.databaseInfo.databaseUri, - name: localQueryInitialInfo.databaseInfo.name, - }, - start: localQueryInitialInfo.start, - id: localQueryInitialInfo.id, - }; -} - -function mapQueryEvaluationInfoToDto( - queryEvaluationInfo: QueryEvaluationInfo, -): QueryEvaluationInfoDto { - return { - querySaveDir: queryEvaluationInfo.querySaveDir, - dbItemPath: queryEvaluationInfo.dbItemPath, - databaseHasMetadataFile: queryEvaluationInfo.databaseHasMetadataFile, - quickEvalPosition: queryEvaluationInfo.quickEvalPosition, - metadata: queryEvaluationInfo.metadata, - resultsPaths: queryEvaluationInfo.resultsPaths, - }; -} diff --git a/extensions/ql-vscode/src/query-history/store/query-history-dto-mapper.ts b/extensions/ql-vscode/src/query-history/store/query-history-dto-mapper.ts index 22bbdf6ba..282e5fe2a 100644 --- a/extensions/ql-vscode/src/query-history/store/query-history-dto-mapper.ts +++ b/extensions/ql-vscode/src/query-history/store/query-history-dto-mapper.ts @@ -1,36 +1,14 @@ -import { - LocalQueryInfo, - CompletedQueryInfo, - InitialQueryInfo, -} from "../../query-results"; -import { QueryEvaluationInfo } from "../../run-queries-shared"; import { QueryHistoryInfo } from "../query-history-info"; -import { VariantAnalysisHistoryItem } from "../variant-analysis-history-item"; -import { - CompletedQueryInfoDto, - QueryEvaluationInfoDto, - InitialQueryInfoDto, - QueryHistoryLocalQueryDto, - SortDirectionDto, - InterpretedResultsSortStateDto, - SortedResultSetInfoDto, - RawResultsSortStateDto, -} from "./query-history-local-query-dto"; import { QueryHistoryItemDto } from "./query-history-dto"; -import { - InterpretedResultsSortState, - RawResultsSortState, - SortDirection, - SortedResultSetInfo, -} from "../../pure/interface-types"; +import { mapQueryHistoryVariantAnalysisToDomainModel } from "./query-history-variant-analysis-dto-mapper"; +import { mapLocalQueryItemToDomainModel } from "./query-history-local-query-dto-mapper"; export function mapQueryHistoryToDomainModel( queries: QueryHistoryItemDto[], ): QueryHistoryInfo[] { return queries.map((d) => { if (d.t === "variant-analysis") { - const query: VariantAnalysisHistoryItem = d; - return query; + return mapQueryHistoryVariantAnalysisToDomainModel(d); } else if (d.t === "local") { return mapLocalQueryItemToDomainModel(d); } @@ -42,122 +20,3 @@ export function mapQueryHistoryToDomainModel( ); }); } - -function mapLocalQueryItemToDomainModel( - localQuery: QueryHistoryLocalQueryDto, -): LocalQueryInfo { - return new LocalQueryInfo( - mapInitialQueryInfoToDomainModel(localQuery.initialInfo), - undefined, - localQuery.failureReason, - localQuery.completedQuery && - mapCompletedQueryInfoToDomainModel(localQuery.completedQuery), - localQuery.evalLogLocation, - localQuery.evalLogSummaryLocation, - localQuery.jsonEvalLogSummaryLocation, - localQuery.evalLogSummarySymbolsLocation, - ); -} - -function mapCompletedQueryInfoToDomainModel( - completedQuery: CompletedQueryInfoDto, -): CompletedQueryInfo { - const sortState = - completedQuery.interpretedResultsSortState && - mapSortStateToDomainModel(completedQuery.interpretedResultsSortState); - - const sortedResults = Object.fromEntries( - Object.entries(completedQuery.sortedResultsInfo).map(([key, value]) => { - return [key, mapSortedResultSetInfoToDomainModel(value)]; - }), - ); - - return new CompletedQueryInfo( - mapQueryEvaluationInfoToDomainModel(completedQuery.query), - { - runId: completedQuery.result.runId, - queryId: completedQuery.result.queryId, - resultType: completedQuery.result.resultType, - evaluationTime: completedQuery.result.evaluationTime, - message: completedQuery.result.message, - logFileLocation: completedQuery.result.logFileLocation, - }, - completedQuery.logFileLocation, - completedQuery.successful ?? completedQuery.sucessful, - completedQuery.message, - sortState, - completedQuery.resultCount, - sortedResults, - ); -} - -function mapInitialQueryInfoToDomainModel( - initialInfo: InitialQueryInfoDto, -): InitialQueryInfo { - return { - userSpecifiedLabel: initialInfo.userSpecifiedLabel, - queryText: initialInfo.queryText, - isQuickQuery: initialInfo.isQuickQuery, - isQuickEval: initialInfo.isQuickEval, - quickEvalPosition: initialInfo.quickEvalPosition, - queryPath: initialInfo.queryPath, - databaseInfo: { - databaseUri: initialInfo.databaseInfo.databaseUri, - name: initialInfo.databaseInfo.name, - }, - start: new Date(initialInfo.start), - id: initialInfo.id, - }; -} - -function mapQueryEvaluationInfoToDomainModel( - evaluationInfo: QueryEvaluationInfoDto, -): QueryEvaluationInfo { - return new QueryEvaluationInfo( - evaluationInfo.querySaveDir, - evaluationInfo.dbItemPath, - evaluationInfo.databaseHasMetadataFile, - evaluationInfo.quickEvalPosition, - evaluationInfo.metadata, - ); -} - -function mapSortDirectionToDomainModel( - sortDirection: SortDirectionDto, -): SortDirection { - switch (sortDirection) { - case SortDirectionDto.asc: - return SortDirection.asc; - case SortDirectionDto.desc: - return SortDirection.desc; - } -} - -function mapSortStateToDomainModel( - sortState: InterpretedResultsSortStateDto, -): InterpretedResultsSortState { - return { - sortBy: sortState.sortBy, - sortDirection: mapSortDirectionToDomainModel(sortState.sortDirection), - }; -} - -function mapSortedResultSetInfoToDomainModel( - sortedResultSetInfo: SortedResultSetInfoDto, -): SortedResultSetInfo { - return { - resultsPath: sortedResultSetInfo.resultsPath, - sortState: mapRawResultsSortStateToDomainModel( - sortedResultSetInfo.sortState, - ), - }; -} - -function mapRawResultsSortStateToDomainModel( - sortState: RawResultsSortStateDto, -): RawResultsSortState { - return { - columnIndex: sortState.columnIndex, - sortDirection: mapSortDirectionToDomainModel(sortState.sortDirection), - }; -} diff --git a/extensions/ql-vscode/src/query-history/store/query-history-local-query-domain-mapper.ts b/extensions/ql-vscode/src/query-history/store/query-history-local-query-domain-mapper.ts new file mode 100644 index 000000000..db2019a68 --- /dev/null +++ b/extensions/ql-vscode/src/query-history/store/query-history-local-query-domain-mapper.ts @@ -0,0 +1,121 @@ +import { + LocalQueryInfo, + InitialQueryInfo, + CompletedQueryInfo, +} from "../../query-results"; +import { QueryEvaluationInfo } from "../../run-queries-shared"; +import { + QueryHistoryLocalQueryDto, + InitialQueryInfoDto, + QueryEvaluationInfoDto, + CompletedQueryInfoDto, + SortedResultSetInfoDto, + SortDirectionDto, +} from "./query-history-local-query-dto"; +import { + RawResultsSortState, + SortDirection, + SortedResultSetInfo, +} from "../../pure/interface-types"; + +export function mapLocalQueryInfoToDto( + query: LocalQueryInfo, +): QueryHistoryLocalQueryDto { + return { + initialInfo: mapInitialQueryInfoToDto(query.initialInfo), + t: "local", + evalLogLocation: query.evalLogLocation, + evalLogSummaryLocation: query.evalLogSummaryLocation, + jsonEvalLogSummaryLocation: query.jsonEvalLogSummaryLocation, + evalLogSummarySymbolsLocation: query.evalLogSummarySymbolsLocation, + failureReason: query.failureReason, + completedQuery: + query.completedQuery && mapCompletedQueryToDto(query.completedQuery), + }; +} + +function mapCompletedQueryToDto( + query: CompletedQueryInfo, +): CompletedQueryInfoDto { + const sortedResults = Object.fromEntries( + Object.entries(query.sortedResultsInfo).map(([key, value]) => { + return [key, mapSortedResultSetInfoToDto(value)]; + }), + ); + + return { + query: mapQueryEvaluationInfoToDto(query.query), + result: { + runId: query.result.runId, + queryId: query.result.queryId, + resultType: query.result.resultType, + evaluationTime: query.result.evaluationTime, + message: query.result.message, + logFileLocation: query.result.logFileLocation, + }, + logFileLocation: query.logFileLocation, + successful: query.successful, + message: query.message, + resultCount: query.resultCount, + sortedResultsInfo: sortedResults, + }; +} + +function mapSortDirectionToDto(sortDirection: SortDirection): SortDirectionDto { + switch (sortDirection) { + case SortDirection.asc: + return SortDirectionDto.asc; + case SortDirection.desc: + return SortDirectionDto.desc; + } +} + +function mapRawResultsSortStateToDto( + sortState: RawResultsSortState, +): SortedResultSetInfoDto["sortState"] { + return { + columnIndex: sortState.columnIndex, + sortDirection: mapSortDirectionToDto(sortState.sortDirection), + }; +} + +function mapSortedResultSetInfoToDto( + resultSet: SortedResultSetInfo, +): SortedResultSetInfoDto { + return { + resultsPath: resultSet.resultsPath, + sortState: mapRawResultsSortStateToDto(resultSet.sortState), + }; +} + +function mapInitialQueryInfoToDto( + localQueryInitialInfo: InitialQueryInfo, +): InitialQueryInfoDto { + return { + userSpecifiedLabel: localQueryInitialInfo.userSpecifiedLabel, + queryText: localQueryInitialInfo.queryText, + isQuickQuery: localQueryInitialInfo.isQuickQuery, + isQuickEval: localQueryInitialInfo.isQuickEval, + quickEvalPosition: localQueryInitialInfo.quickEvalPosition, + queryPath: localQueryInitialInfo.queryPath, + databaseInfo: { + databaseUri: localQueryInitialInfo.databaseInfo.databaseUri, + name: localQueryInitialInfo.databaseInfo.name, + }, + start: localQueryInitialInfo.start, + id: localQueryInitialInfo.id, + }; +} + +function mapQueryEvaluationInfoToDto( + queryEvaluationInfo: QueryEvaluationInfo, +): QueryEvaluationInfoDto { + return { + querySaveDir: queryEvaluationInfo.querySaveDir, + dbItemPath: queryEvaluationInfo.dbItemPath, + databaseHasMetadataFile: queryEvaluationInfo.databaseHasMetadataFile, + quickEvalPosition: queryEvaluationInfo.quickEvalPosition, + metadata: queryEvaluationInfo.metadata, + resultsPaths: queryEvaluationInfo.resultsPaths, + }; +} diff --git a/extensions/ql-vscode/src/query-history/store/query-history-local-query-dto-mapper.ts b/extensions/ql-vscode/src/query-history/store/query-history-local-query-dto-mapper.ts new file mode 100644 index 000000000..63f0f763e --- /dev/null +++ b/extensions/ql-vscode/src/query-history/store/query-history-local-query-dto-mapper.ts @@ -0,0 +1,141 @@ +import { + LocalQueryInfo, + CompletedQueryInfo, + InitialQueryInfo, +} from "../../query-results"; +import { QueryEvaluationInfo } from "../../run-queries-shared"; +import { + CompletedQueryInfoDto, + QueryEvaluationInfoDto, + InitialQueryInfoDto, + QueryHistoryLocalQueryDto, + SortDirectionDto, + InterpretedResultsSortStateDto, + SortedResultSetInfoDto, + RawResultsSortStateDto, +} from "./query-history-local-query-dto"; +import { + InterpretedResultsSortState, + RawResultsSortState, + SortDirection, + SortedResultSetInfo, +} from "../../pure/interface-types"; + +export function mapLocalQueryItemToDomainModel( + localQuery: QueryHistoryLocalQueryDto, +): LocalQueryInfo { + return new LocalQueryInfo( + mapInitialQueryInfoToDomainModel(localQuery.initialInfo), + undefined, + localQuery.failureReason, + localQuery.completedQuery && + mapCompletedQueryInfoToDomainModel(localQuery.completedQuery), + localQuery.evalLogLocation, + localQuery.evalLogSummaryLocation, + localQuery.jsonEvalLogSummaryLocation, + localQuery.evalLogSummarySymbolsLocation, + ); +} + +function mapCompletedQueryInfoToDomainModel( + completedQuery: CompletedQueryInfoDto, +): CompletedQueryInfo { + const sortState = + completedQuery.interpretedResultsSortState && + mapSortStateToDomainModel(completedQuery.interpretedResultsSortState); + + const sortedResults = Object.fromEntries( + Object.entries(completedQuery.sortedResultsInfo).map(([key, value]) => { + return [key, mapSortedResultSetInfoToDomainModel(value)]; + }), + ); + + return new CompletedQueryInfo( + mapQueryEvaluationInfoToDomainModel(completedQuery.query), + { + runId: completedQuery.result.runId, + queryId: completedQuery.result.queryId, + resultType: completedQuery.result.resultType, + evaluationTime: completedQuery.result.evaluationTime, + message: completedQuery.result.message, + logFileLocation: completedQuery.result.logFileLocation, + }, + completedQuery.logFileLocation, + completedQuery.successful ?? completedQuery.sucessful, + completedQuery.message, + sortState, + completedQuery.resultCount, + sortedResults, + ); +} + +function mapInitialQueryInfoToDomainModel( + initialInfo: InitialQueryInfoDto, +): InitialQueryInfo { + return { + userSpecifiedLabel: initialInfo.userSpecifiedLabel, + queryText: initialInfo.queryText, + isQuickQuery: initialInfo.isQuickQuery, + isQuickEval: initialInfo.isQuickEval, + quickEvalPosition: initialInfo.quickEvalPosition, + queryPath: initialInfo.queryPath, + databaseInfo: { + databaseUri: initialInfo.databaseInfo.databaseUri, + name: initialInfo.databaseInfo.name, + }, + start: new Date(initialInfo.start), + id: initialInfo.id, + }; +} + +function mapQueryEvaluationInfoToDomainModel( + evaluationInfo: QueryEvaluationInfoDto, +): QueryEvaluationInfo { + return new QueryEvaluationInfo( + evaluationInfo.querySaveDir, + evaluationInfo.dbItemPath, + evaluationInfo.databaseHasMetadataFile, + evaluationInfo.quickEvalPosition, + evaluationInfo.metadata, + ); +} + +function mapSortDirectionToDomainModel( + sortDirection: SortDirectionDto, +): SortDirection { + switch (sortDirection) { + case SortDirectionDto.asc: + return SortDirection.asc; + case SortDirectionDto.desc: + return SortDirection.desc; + } +} + +function mapSortStateToDomainModel( + sortState: InterpretedResultsSortStateDto, +): InterpretedResultsSortState { + return { + sortBy: sortState.sortBy, + sortDirection: mapSortDirectionToDomainModel(sortState.sortDirection), + }; +} + +function mapSortedResultSetInfoToDomainModel( + sortedResultSetInfo: SortedResultSetInfoDto, +): SortedResultSetInfo { + return { + resultsPath: sortedResultSetInfo.resultsPath, + sortState: mapRawResultsSortStateToDomainModel( + sortedResultSetInfo.sortState, + ), + }; +} + +function mapRawResultsSortStateToDomainModel( + sortState: RawResultsSortStateDto, +): RawResultsSortState { + return { + columnIndex: sortState.columnIndex, + sortDirection: mapSortDirectionToDomainModel(sortState.sortDirection), + }; +} diff --git a/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-domain-mapper.ts b/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-domain-mapper.ts new file mode 100644 index 000000000..24b22582b --- /dev/null +++ b/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-domain-mapper.ts @@ -0,0 +1,235 @@ +import { + QueryHistoryVariantAnalysisDto, + QueryLanguageDto, + QueryStatusDto, + VariantAnalysisDto, + VariantAnalysisFailureReasonDto, + VariantAnalysisRepoStatusDto, + VariantAnalysisScannedRepositoryDto, + VariantAnalysisSkippedRepositoriesDto, + VariantAnalysisSkippedRepositoryDto, + VariantAnalysisSkippedRepositoryGroupDto, + VariantAnalysisStatusDto, +} from "./query-history-variant-analysis-dto"; +import { + VariantAnalysis, + VariantAnalysisFailureReason, + VariantAnalysisRepoStatus, + VariantAnalysisScannedRepository, + VariantAnalysisSkippedRepositories, + VariantAnalysisSkippedRepository, + VariantAnalysisSkippedRepositoryGroup, + VariantAnalysisStatus, +} from "../../variant-analysis/shared/variant-analysis"; +import { assertNever } from "../../pure/helpers-pure"; +import { QueryLanguage } from "../../common/query-language"; +import { QueryStatus } from "../../query-status"; +import { VariantAnalysisHistoryItem } from "../variant-analysis-history-item"; + +export function mapQueryHistoryVariantAnalysisToDto( + item: VariantAnalysisHistoryItem, +): QueryHistoryVariantAnalysisDto { + return { + t: "variant-analysis", + failureReason: item.failureReason, + resultCount: item.resultCount, + status: mapQueryStatusToDto(item.status), + completed: item.completed, + variantAnalysis: mapVariantAnalysisDtoToDto(item.variantAnalysis), + userSpecifiedLabel: item.userSpecifiedLabel, + }; +} + +function mapVariantAnalysisDtoToDto( + variantAnalysis: VariantAnalysis, +): VariantAnalysisDto { + return { + id: variantAnalysis.id, + controllerRepo: { + id: variantAnalysis.controllerRepo.id, + fullName: variantAnalysis.controllerRepo.fullName, + private: variantAnalysis.controllerRepo.private, + }, + query: { + name: variantAnalysis.query.name, + filePath: variantAnalysis.query.filePath, + language: mapQueryLanguageToDto(variantAnalysis.query.language), + text: variantAnalysis.query.text, + }, + databases: { + repositories: variantAnalysis.databases.repositories, + repositoryLists: variantAnalysis.databases.repositoryLists, + repositoryOwners: variantAnalysis.databases.repositoryOwners, + }, + createdAt: variantAnalysis.createdAt, + updatedAt: variantAnalysis.updatedAt, + executionStartTime: variantAnalysis.executionStartTime, + status: mapVariantAnalysisStatusToDto(variantAnalysis.status), + completedAt: variantAnalysis.completedAt, + actionsWorkflowRunId: variantAnalysis.actionsWorkflowRunId, + failureReason: + variantAnalysis.failureReason && + mapVariantAnalysisFailureReasonToDto(variantAnalysis.failureReason), + scannedRepos: + variantAnalysis.scannedRepos && + mapVariantAnalysisScannedRepositoriesToDto(variantAnalysis.scannedRepos), + skippedRepos: + variantAnalysis.skippedRepos && + mapVariantAnalysisSkippedRepositoriesToDto(variantAnalysis.skippedRepos), + }; +} + +function mapVariantAnalysisScannedRepositoriesToDto( + repos: VariantAnalysisScannedRepository[], +): VariantAnalysisScannedRepositoryDto[] { + return repos.map(mapVariantAnalysisScannedRepositoryToDto); +} + +function mapVariantAnalysisScannedRepositoryToDto( + repo: VariantAnalysisScannedRepository, +): VariantAnalysisScannedRepositoryDto { + return { + repository: { + id: repo.repository.id, + fullName: repo.repository.fullName, + private: repo.repository.private, + stargazersCount: repo.repository.stargazersCount, + updatedAt: repo.repository.updatedAt, + }, + analysisStatus: mapVariantAnalysisRepoStatusToDto(repo.analysisStatus), + resultCount: repo.resultCount, + artifactSizeInBytes: repo.artifactSizeInBytes, + failureMessage: repo.failureMessage, + }; +} + +function mapVariantAnalysisSkippedRepositoriesToDto( + repos: VariantAnalysisSkippedRepositories, +): VariantAnalysisSkippedRepositoriesDto { + return { + accessMismatchRepos: + repos.accessMismatchRepos && + mapVariantAnalysisSkippedRepositoryGroupToDto(repos.accessMismatchRepos), + notFoundRepos: + repos.notFoundRepos && + mapVariantAnalysisSkippedRepositoryGroupToDto(repos.notFoundRepos), + noCodeqlDbRepos: + repos.noCodeqlDbRepos && + mapVariantAnalysisSkippedRepositoryGroupToDto(repos.noCodeqlDbRepos), + overLimitRepos: + repos.overLimitRepos && + mapVariantAnalysisSkippedRepositoryGroupToDto(repos.overLimitRepos), + }; +} + +function mapVariantAnalysisSkippedRepositoryGroupToDto( + repoGroup: VariantAnalysisSkippedRepositoryGroup, +): VariantAnalysisSkippedRepositoryGroupDto { + return { + repositoryCount: repoGroup.repositoryCount, + repositories: repoGroup.repositories.map( + mapVariantAnalysisSkippedRepositoryToDto, + ), + }; +} + +function mapVariantAnalysisSkippedRepositoryToDto( + repo: VariantAnalysisSkippedRepository, +): VariantAnalysisSkippedRepositoryDto { + return { + id: repo.id, + fullName: repo.fullName, + private: repo.private, + stargazersCount: repo.stargazersCount, + updatedAt: repo.updatedAt, + }; +} + +function mapVariantAnalysisFailureReasonToDto( + failureReason: VariantAnalysisFailureReason, +): VariantAnalysisFailureReasonDto { + switch (failureReason) { + case VariantAnalysisFailureReason.NoReposQueried: + return VariantAnalysisFailureReasonDto.NoReposQueried; + case VariantAnalysisFailureReason.ActionsWorkflowRunFailed: + return VariantAnalysisFailureReasonDto.ActionsWorkflowRunFailed; + case VariantAnalysisFailureReason.InternalError: + return VariantAnalysisFailureReasonDto.InternalError; + default: + assertNever(failureReason); + } +} + +function mapVariantAnalysisRepoStatusToDto( + status: VariantAnalysisRepoStatus, +): VariantAnalysisRepoStatusDto { + switch (status) { + case VariantAnalysisRepoStatus.Pending: + return VariantAnalysisRepoStatusDto.Pending; + case VariantAnalysisRepoStatus.InProgress: + return VariantAnalysisRepoStatusDto.InProgress; + case VariantAnalysisRepoStatus.Succeeded: + return VariantAnalysisRepoStatusDto.Succeeded; + case VariantAnalysisRepoStatus.Failed: + return VariantAnalysisRepoStatusDto.Failed; + case VariantAnalysisRepoStatus.Canceled: + return VariantAnalysisRepoStatusDto.Canceled; + case VariantAnalysisRepoStatus.TimedOut: + return VariantAnalysisRepoStatusDto.TimedOut; + default: + assertNever(status); + } +} + +function mapVariantAnalysisStatusToDto( + status: VariantAnalysisStatus, +): VariantAnalysisStatusDto { + switch (status) { + case VariantAnalysisStatus.InProgress: + return VariantAnalysisStatusDto.InProgress; + case VariantAnalysisStatus.Succeeded: + return VariantAnalysisStatusDto.Succeeded; + case VariantAnalysisStatus.Failed: + return VariantAnalysisStatusDto.Failed; + case VariantAnalysisStatus.Canceled: + return VariantAnalysisStatusDto.Canceled; + default: + assertNever(status); + } +} + +function mapQueryLanguageToDto(language: QueryLanguage): QueryLanguageDto { + switch (language) { + case QueryLanguage.CSharp: + return QueryLanguageDto.CSharp; + case QueryLanguage.Cpp: + return QueryLanguageDto.Cpp; + case QueryLanguage.Go: + return QueryLanguageDto.Go; + case QueryLanguage.Java: + return QueryLanguageDto.Java; + case QueryLanguage.Javascript: + return QueryLanguageDto.Javascript; + case QueryLanguage.Python: + return QueryLanguageDto.Python; + case QueryLanguage.Ruby: + return QueryLanguageDto.Ruby; + case QueryLanguage.Swift: + return QueryLanguageDto.Swift; + default: + assertNever(language); + } +} + +function mapQueryStatusToDto(status: QueryStatus): QueryStatusDto { + switch (status) { + case QueryStatus.InProgress: + return QueryStatusDto.InProgress; + case QueryStatus.Completed: + return QueryStatusDto.Completed; + case QueryStatus.Failed: + return QueryStatusDto.Failed; + default: + assertNever(status); + } +} diff --git a/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto-mapper.ts b/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto-mapper.ts new file mode 100644 index 000000000..e05451bf0 --- /dev/null +++ b/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto-mapper.ts @@ -0,0 +1,253 @@ +import { + QueryHistoryVariantAnalysisDto, + QueryLanguageDto, + QueryStatusDto, + VariantAnalysisDto, + VariantAnalysisFailureReasonDto, + VariantAnalysisRepoStatusDto, + VariantAnalysisScannedRepositoryDto, + VariantAnalysisSkippedRepositoriesDto, + VariantAnalysisSkippedRepositoryDto, + VariantAnalysisSkippedRepositoryGroupDto, + VariantAnalysisStatusDto, +} from "./query-history-variant-analysis-dto"; +import { + VariantAnalysis, + VariantAnalysisFailureReason, + VariantAnalysisRepoStatus, + VariantAnalysisScannedRepository, + VariantAnalysisSkippedRepositories, + VariantAnalysisSkippedRepository, + VariantAnalysisSkippedRepositoryGroup, + VariantAnalysisStatus, +} from "../../variant-analysis/shared/variant-analysis"; +import { assertNever } from "../../pure/helpers-pure"; +import { QueryLanguage } from "../../common/query-language"; +import { QueryStatus } from "../../query-status"; +import { VariantAnalysisHistoryItem } from "../variant-analysis-history-item"; + +export function mapQueryHistoryVariantAnalysisToDomainModel( + item: QueryHistoryVariantAnalysisDto, +): VariantAnalysisHistoryItem { + return { + t: "variant-analysis", + failureReason: item.failureReason, + resultCount: item.resultCount, + status: mapQueryStatusToDomainModel(item.status), + completed: item.completed, + variantAnalysis: mapVariantAnalysisToDomainModel(item.variantAnalysis), + userSpecifiedLabel: item.userSpecifiedLabel, + }; +} + +function mapVariantAnalysisToDomainModel( + variantAnalysis: VariantAnalysisDto, +): VariantAnalysis { + return { + id: variantAnalysis.id, + controllerRepo: { + id: variantAnalysis.controllerRepo.id, + fullName: variantAnalysis.controllerRepo.fullName, + private: variantAnalysis.controllerRepo.private, + }, + query: { + name: variantAnalysis.query.name, + filePath: variantAnalysis.query.filePath, + language: mapQueryLanguageToDomainModel(variantAnalysis.query.language), + text: variantAnalysis.query.text, + }, + databases: { + repositories: variantAnalysis.databases.repositories, + repositoryLists: variantAnalysis.databases.repositoryLists, + repositoryOwners: variantAnalysis.databases.repositoryOwners, + }, + createdAt: variantAnalysis.createdAt, + updatedAt: variantAnalysis.updatedAt, + executionStartTime: variantAnalysis.executionStartTime, + status: mapVariantAnalysisStatusToDomainModel(variantAnalysis.status), + completedAt: variantAnalysis.completedAt, + actionsWorkflowRunId: variantAnalysis.actionsWorkflowRunId, + failureReason: + variantAnalysis.failureReason && + mapVariantAnalysisFailureReasonToDomainModel( + variantAnalysis.failureReason, + ), + scannedRepos: + variantAnalysis.scannedRepos && + mapVariantAnalysisScannedRepositoriesToDomainModel( + variantAnalysis.scannedRepos, + ), + skippedRepos: + variantAnalysis.skippedRepos && + mapVariantAnalysisSkippedRepositoriesToDomainModel( + variantAnalysis.skippedRepos, + ), + }; +} + +function mapVariantAnalysisScannedRepositoriesToDomainModel( + repos: VariantAnalysisScannedRepositoryDto[], +): VariantAnalysisScannedRepository[] { + return repos.map(mapVariantAnalysisScannedRepositoryToDomainModel); +} + +function mapVariantAnalysisScannedRepositoryToDomainModel( + repo: VariantAnalysisScannedRepositoryDto, +): VariantAnalysisScannedRepository { + return { + repository: { + id: repo.repository.id, + fullName: repo.repository.fullName, + private: repo.repository.private, + stargazersCount: repo.repository.stargazersCount, + updatedAt: repo.repository.updatedAt, + }, + analysisStatus: mapVariantAnalysisRepoStatusToDomainModel( + repo.analysisStatus, + ), + resultCount: repo.resultCount, + artifactSizeInBytes: repo.artifactSizeInBytes, + failureMessage: repo.failureMessage, + }; +} + +function mapVariantAnalysisSkippedRepositoriesToDomainModel( + repos: VariantAnalysisSkippedRepositoriesDto, +): VariantAnalysisSkippedRepositories { + return { + accessMismatchRepos: + repos.accessMismatchRepos && + mapVariantAnalysisSkippedRepositoryGroupToDomainModel( + repos.accessMismatchRepos, + ), + notFoundRepos: + repos.notFoundRepos && + mapVariantAnalysisSkippedRepositoryGroupToDomainModel( + repos.notFoundRepos, + ), + noCodeqlDbRepos: + repos.noCodeqlDbRepos && + mapVariantAnalysisSkippedRepositoryGroupToDomainModel( + repos.noCodeqlDbRepos, + ), + overLimitRepos: + repos.overLimitRepos && + mapVariantAnalysisSkippedRepositoryGroupToDomainModel( + repos.overLimitRepos, + ), + }; +} + +function mapVariantAnalysisSkippedRepositoryGroupToDomainModel( + repoGroup: VariantAnalysisSkippedRepositoryGroupDto, +): VariantAnalysisSkippedRepositoryGroup { + return { + repositoryCount: repoGroup.repositoryCount, + repositories: repoGroup.repositories.map( + mapVariantAnalysisSkippedRepositoryToDomainModel, + ), + }; +} + +function mapVariantAnalysisSkippedRepositoryToDomainModel( + repo: VariantAnalysisSkippedRepositoryDto, +): VariantAnalysisSkippedRepository { + return { + id: repo.id, + fullName: repo.fullName, + private: repo.private, + stargazersCount: repo.stargazersCount, + updatedAt: repo.updatedAt, + }; +} + +function mapVariantAnalysisFailureReasonToDomainModel( + failureReason: VariantAnalysisFailureReasonDto, +): VariantAnalysisFailureReason { + switch (failureReason) { + case VariantAnalysisFailureReasonDto.NoReposQueried: + return VariantAnalysisFailureReason.NoReposQueried; + case VariantAnalysisFailureReasonDto.ActionsWorkflowRunFailed: + return VariantAnalysisFailureReason.ActionsWorkflowRunFailed; + case VariantAnalysisFailureReasonDto.InternalError: + return VariantAnalysisFailureReason.InternalError; + default: + assertNever(failureReason); + } +} + +function mapVariantAnalysisRepoStatusToDomainModel( + status: VariantAnalysisRepoStatusDto, +): VariantAnalysisRepoStatus { + switch (status) { + case VariantAnalysisRepoStatusDto.Pending: + return VariantAnalysisRepoStatus.Pending; + case VariantAnalysisRepoStatusDto.InProgress: + return VariantAnalysisRepoStatus.InProgress; + case VariantAnalysisRepoStatusDto.Succeeded: + return VariantAnalysisRepoStatus.Succeeded; + case VariantAnalysisRepoStatusDto.Failed: + return VariantAnalysisRepoStatus.Failed; + case VariantAnalysisRepoStatusDto.Canceled: + return VariantAnalysisRepoStatus.Canceled; + case VariantAnalysisRepoStatusDto.TimedOut: + return VariantAnalysisRepoStatus.TimedOut; + default: + assertNever(status); + } +} + +function mapVariantAnalysisStatusToDomainModel( + status: VariantAnalysisStatusDto, +): VariantAnalysisStatus { + switch (status) { + case VariantAnalysisStatusDto.InProgress: + return VariantAnalysisStatus.InProgress; + case VariantAnalysisStatusDto.Succeeded: + return VariantAnalysisStatus.Succeeded; + case VariantAnalysisStatusDto.Failed: + return VariantAnalysisStatus.Failed; + case VariantAnalysisStatusDto.Canceled: + return VariantAnalysisStatus.Canceled; + default: + assertNever(status); + } +} + +function mapQueryLanguageToDomainModel( + language: QueryLanguageDto, +): QueryLanguage { + switch (language) { + case QueryLanguageDto.CSharp: + return QueryLanguage.CSharp; + case QueryLanguageDto.Cpp: + return QueryLanguage.Cpp; + case QueryLanguageDto.Go: + return QueryLanguage.Go; + case QueryLanguageDto.Java: + return QueryLanguage.Java; + case QueryLanguageDto.Javascript: + return QueryLanguage.Javascript; + case QueryLanguageDto.Python: + return QueryLanguage.Python; + case QueryLanguageDto.Ruby: + return QueryLanguage.Ruby; + case QueryLanguageDto.Swift: + return QueryLanguage.Swift; + default: + assertNever(language); + } +} + +function mapQueryStatusToDomainModel(status: QueryStatusDto): QueryStatus { + switch (status) { + case QueryStatusDto.InProgress: + return QueryStatus.InProgress; + case QueryStatusDto.Completed: + return QueryStatus.Completed; + case QueryStatusDto.Failed: + return QueryStatus.Failed; + default: + assertNever(status); + } +} diff --git a/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto.ts b/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto.ts index 06c79b542..786545100 100644 --- a/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto.ts +++ b/extensions/ql-vscode/src/query-history/store/query-history-variant-analysis-dto.ts @@ -1,27 +1,17 @@ // Contains models and consts for the data we want to store in the query history store. // Changes to these models should be done carefully and account for backwards compatibility of data. -import { QueryLanguage } from "../../common/query-language"; -import { QueryStatus } from "../../query-status"; -import { - VariantAnalysisFailureReason, - VariantAnalysisRepoStatus, - VariantAnalysisStatus, -} from "../../variant-analysis/shared/variant-analysis"; - -// All data points are modelled, except enums. - export interface QueryHistoryVariantAnalysisDto { readonly t: "variant-analysis"; failureReason?: string; resultCount?: number; - status: QueryStatus; + status: QueryStatusDto; completed: boolean; - variantAnalysis: VariantAnalysisQueryHistoryDto; + variantAnalysis: VariantAnalysisDto; userSpecifiedLabel?: string; } -export interface VariantAnalysisQueryHistoryDto { +export interface VariantAnalysisDto { id: number; controllerRepo: { id: number; @@ -31,7 +21,7 @@ export interface VariantAnalysisQueryHistoryDto { query: { name: string; filePath: string; - language: QueryLanguage; + language: QueryLanguageDto; text: string; }; databases: { @@ -42,10 +32,10 @@ export interface VariantAnalysisQueryHistoryDto { createdAt: string; updatedAt: string; executionStartTime: number; - status: VariantAnalysisStatus; + status: VariantAnalysisStatusDto; completedAt?: string; actionsWorkflowRunId?: number; - failureReason?: VariantAnalysisFailureReason; + failureReason?: VariantAnalysisFailureReasonDto; scannedRepos?: VariantAnalysisScannedRepositoryDto[]; skippedRepos?: VariantAnalysisSkippedRepositoriesDto; } @@ -58,7 +48,7 @@ export interface VariantAnalysisScannedRepositoryDto { stargazersCount: number; updatedAt: string | null; }; - analysisStatus: VariantAnalysisRepoStatus; + analysisStatus: VariantAnalysisRepoStatusDto; resultCount?: number; artifactSizeInBytes?: number; failureMessage?: string; @@ -83,3 +73,42 @@ export interface VariantAnalysisSkippedRepositoryDto { stargazersCount?: number; updatedAt?: string | null; } + +export enum VariantAnalysisFailureReasonDto { + NoReposQueried = "noReposQueried", + ActionsWorkflowRunFailed = "actionsWorkflowRunFailed", + InternalError = "internalError", +} + +export enum VariantAnalysisRepoStatusDto { + Pending = "pending", + InProgress = "inProgress", + Succeeded = "succeeded", + Failed = "failed", + Canceled = "canceled", + TimedOut = "timedOut", +} + +export enum VariantAnalysisStatusDto { + InProgress = "inProgress", + Succeeded = "succeeded", + Failed = "failed", + Canceled = "canceled", +} + +export enum QueryLanguageDto { + CSharp = "csharp", + Cpp = "cpp", + Go = "go", + Java = "java", + Javascript = "javascript", + Python = "python", + Ruby = "ruby", + Swift = "swift", +} + +export enum QueryStatusDto { + InProgress = "InProgress", + Completed = "Completed", + Failed = "Failed", +} diff --git a/extensions/ql-vscode/src/query-server/queryserver-client.ts b/extensions/ql-vscode/src/query-server/queryserver-client.ts index e992d323e..1c84482a8 100644 --- a/extensions/ql-vscode/src/query-server/queryserver-client.ts +++ b/extensions/ql-vscode/src/query-server/queryserver-client.ts @@ -1,6 +1,6 @@ import { ensureFile } from "fs-extra"; -import { DisposableObject } from "../pure/disposable-object"; +import { DisposableObject, DisposeHandler } from "../pure/disposable-object"; import { CancellationToken } from "vscode"; import { createMessageConnection, RequestType } from "vscode-jsonrpc/node"; import * as cli from "../cli"; @@ -224,4 +224,10 @@ export class QueryServerClient extends DisposableObject { delete this.progressCallbacks[id]; } } + + public dispose(disposeHandler?: DisposeHandler | undefined): void { + this.progressCallbacks = {}; + this.stopQueryServer(); + super.dispose(disposeHandler); + } } diff --git a/extensions/ql-vscode/src/skeleton-query-wizard.ts b/extensions/ql-vscode/src/skeleton-query-wizard.ts index 078a03c6d..0c5ddca9f 100644 --- a/extensions/ql-vscode/src/skeleton-query-wizard.ts +++ b/extensions/ql-vscode/src/skeleton-query-wizard.ts @@ -1,15 +1,20 @@ -import { join, dirname } from "path"; +import { join } from "path"; import { CancellationToken, Uri, workspace, window as Window } from "vscode"; import { CodeQLCliServer } from "./cli"; import { OutputChannelLogger } from "./common"; import { Credentials } from "./common/authentication"; import { QueryLanguage } from "./common/query-language"; -import { askForLanguage, isFolderAlreadyInWorkspace } from "./helpers"; +import { + askForLanguage, + getFirstWorkspaceFolder, + isFolderAlreadyInWorkspace, +} from "./helpers"; import { getErrorMessage } from "./pure/helpers-pure"; import { QlPackGenerator } from "./qlpack-generator"; import { DatabaseItem, DatabaseManager } from "./local-databases"; import { ProgressCallback, UserCancellationException } from "./progress"; import { askForGitHubRepo, downloadGitHubDatabase } from "./databaseFetcher"; +import { existsSync } from "fs"; type QueryLanguagesToDatabaseMap = Record; @@ -50,11 +55,11 @@ export class SkeletonQueryWizard { return; } - this.qlPackStoragePath = this.getFirstStoragePath(); + this.qlPackStoragePath = getFirstWorkspaceFolder(); - const skeletonPackAlreadyExists = isFolderAlreadyInWorkspace( - this.folderName, - ); + const skeletonPackAlreadyExists = + existsSync(join(this.qlPackStoragePath, this.folderName)) || + isFolderAlreadyInWorkspace(this.folderName); if (skeletonPackAlreadyExists) { // just create a new example query file in skeleton QL pack @@ -93,27 +98,6 @@ export class SkeletonQueryWizard { }); } - public getFirstStoragePath() { - const workspaceFolders = workspace.workspaceFolders; - - if (!workspaceFolders || workspaceFolders.length === 0) { - throw new Error("No workspace folders found"); - } - - const firstFolder = workspaceFolders[0]; - const firstFolderFsPath = firstFolder.uri.fsPath; - - // For the vscode-codeql-starter repo, the first folder will be a ql pack - // so we need to get the parent folder - if (firstFolderFsPath.includes("codeql-custom-queries")) { - // return the parent folder - return dirname(firstFolderFsPath); - } else { - // if the first folder is not a ql pack, then we are in a normal workspace - return firstFolderFsPath; - } - } - private async chooseLanguage() { this.progress({ message: "Choose language", diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx b/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx index 998ade270..4b7598765 100644 --- a/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx +++ b/extensions/ql-vscode/src/view/data-extensions-editor/DataExtensionsEditor.tsx @@ -16,7 +16,7 @@ import { ModeledMethod } from "../../data-extensions-editor/modeled-method"; import { MethodRow } from "./MethodRow"; import { assertNever } from "../../pure/helpers-pure"; import { vscode } from "../vscode-api"; -import { calculateSupportedPercentage } from "./supported"; +import { calculateModeledPercentage } from "./modeled"; export const DataExtensionsEditorContainer = styled.div` margin-top: 1rem; @@ -97,12 +97,12 @@ export function DataExtensionsEditor({ }; }, []); - const supportedPercentage = useMemo( - () => calculateSupportedPercentage(externalApiUsages), + const modeledPercentage = useMemo( + () => calculateModeledPercentage(externalApiUsages), [externalApiUsages], ); - const unsupportedPercentage = 100 - supportedPercentage; + const unModeledPercentage = 100 - modeledPercentage; const onChange = useCallback( (method: ExternalApiUsage, model: ModeledMethod) => { @@ -140,10 +140,10 @@ export function DataExtensionsEditor({ {externalApiUsages.length > 0 && ( <>
-

External API support stats

+

External API model stats

    -
  • Supported: {supportedPercentage.toFixed(2)}%
  • -
  • Unsupported: {unsupportedPercentage.toFixed(2)}%
  • +
  • Modeled: {modeledPercentage.toFixed(2)}%
  • +
  • Unmodeled: {unModeledPercentage.toFixed(2)}%
diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/KindInput.tsx b/extensions/ql-vscode/src/view/data-extensions-editor/KindInput.tsx new file mode 100644 index 000000000..52f49f6b6 --- /dev/null +++ b/extensions/ql-vscode/src/view/data-extensions-editor/KindInput.tsx @@ -0,0 +1,48 @@ +import * as React from "react"; +import { useCallback, useEffect } from "react"; +import styled from "styled-components"; +import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"; + +import type { ModeledMethod } from "../../data-extensions-editor/modeled-method"; + +const Dropdown = styled(VSCodeDropdown)` + width: 100%; +`; + +type Props = { + kinds: Array; + + value: ModeledMethod["kind"] | undefined; + onChange: (value: ModeledMethod["kind"]) => void; +}; + +export const KindInput = ({ kinds, value, onChange }: Props) => { + const handleInput = useCallback( + (e: InputEvent) => { + const target = e.target as HTMLSelectElement; + + onChange(target.value as ModeledMethod["kind"]); + }, + [onChange], + ); + + useEffect(() => { + if (value === undefined && kinds.length > 0) { + onChange(kinds[0]); + } + + if (value !== undefined && !kinds.includes(value)) { + onChange(kinds[0]); + } + }, [value, kinds, onChange]); + + return ( + + {kinds.map((kind) => ( + + {kind} + + ))} + + ); +}; diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/MethodRow.tsx b/extensions/ql-vscode/src/view/data-extensions-editor/MethodRow.tsx index 1d97b0ced..6c0191b9b 100644 --- a/extensions/ql-vscode/src/view/data-extensions-editor/MethodRow.tsx +++ b/extensions/ql-vscode/src/view/data-extensions-editor/MethodRow.tsx @@ -3,7 +3,6 @@ import { VSCodeDataGridRow, VSCodeDropdown, VSCodeOption, - VSCodeTextField, } from "@vscode/webview-ui-toolkit/react"; import * as React from "react"; import { useCallback, useMemo } from "react"; @@ -15,15 +14,13 @@ import { ModeledMethod, ModeledMethodType, } from "../../data-extensions-editor/modeled-method"; +import { KindInput } from "./KindInput"; +import { extensiblePredicateDefinitions } from "../../data-extensions-editor/predicates"; const Dropdown = styled(VSCodeDropdown)` width: 100%; `; -const TextField = styled(VSCodeTextField)` - width: 100%; -`; - type SupportedUnsupportedSpanProps = { supported: boolean; }; @@ -107,17 +104,15 @@ export const MethodRow = ({ }, [onChange, externalApiUsage, modeledMethod], ); - const handleKindInput = useCallback( - (e: InputEvent) => { + const handleKindChange = useCallback( + (kind: string) => { if (!modeledMethod) { return; } - const target = e.target as HTMLSelectElement; - onChange(externalApiUsage, { ...modeledMethod, - kind: target.value as ModeledMethod["kind"], + kind, }); }, [onChange, externalApiUsage, modeledMethod], @@ -130,6 +125,11 @@ export const MethodRow = ({ }); }, [externalApiUsage]); + const predicate = + modeledMethod?.type && modeledMethod.type !== "none" + ? extensiblePredicateDefinitions[modeledMethod.type] + : undefined; + return ( @@ -155,7 +155,7 @@ export const MethodRow = ({ value={modeledMethod?.type ?? "none"} onInput={handleTypeInput} > - Unmodelled + Unmodeled Source Sink Flow summary @@ -195,10 +195,13 @@ export const MethodRow = ({ )} - {modeledMethod?.type && - ["source", "sink", "summary"].includes(modeledMethod?.type) && ( - - )} + {predicate?.supportedKinds && ( + + )} ); diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/__tests__/supported.spec.ts b/extensions/ql-vscode/src/view/data-extensions-editor/__tests__/modeled.spec.ts similarity index 55% rename from extensions/ql-vscode/src/view/data-extensions-editor/__tests__/supported.spec.ts rename to extensions/ql-vscode/src/view/data-extensions-editor/__tests__/modeled.spec.ts index 16e8b9b13..6156ecd42 100644 --- a/extensions/ql-vscode/src/view/data-extensions-editor/__tests__/supported.spec.ts +++ b/extensions/ql-vscode/src/view/data-extensions-editor/__tests__/modeled.spec.ts @@ -1,13 +1,13 @@ -import { calculateSupportedPercentage } from "../supported"; +import { calculateModeledPercentage } from "../modeled"; -describe("calculateSupportedPercentage", () => { +describe("calculateModeledPercentage", () => { it("when there are no external API usages", () => { - expect(calculateSupportedPercentage([])).toBe(0); + expect(calculateModeledPercentage([])).toBe(0); }); - it("when there are is 1 supported external API usage", () => { + it("when there are is 1 modeled external API usage", () => { expect( - calculateSupportedPercentage([ + calculateModeledPercentage([ { supported: true, }, @@ -15,9 +15,9 @@ describe("calculateSupportedPercentage", () => { ).toBe(100); }); - it("when there are is 1 unsupported external API usage", () => { + it("when there are is 1 unmodeled external API usage", () => { expect( - calculateSupportedPercentage([ + calculateModeledPercentage([ { supported: false, }, @@ -25,9 +25,9 @@ describe("calculateSupportedPercentage", () => { ).toBe(0); }); - it("when there are multiple supporte and unsupported external API usage", () => { + it("when there are multiple modeled and unmodeled external API usage", () => { expect( - calculateSupportedPercentage([ + calculateModeledPercentage([ { supported: false, }, diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/modeled.ts b/extensions/ql-vscode/src/view/data-extensions-editor/modeled.ts new file mode 100644 index 000000000..dd29df262 --- /dev/null +++ b/extensions/ql-vscode/src/view/data-extensions-editor/modeled.ts @@ -0,0 +1,15 @@ +import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage"; + +export function calculateModeledPercentage( + externalApiUsages: Array>, +): number { + if (externalApiUsages.length === 0) { + return 0; + } + + const modeledExternalApiUsages = externalApiUsages.filter((m) => m.supported); + + const modeledRatio = + modeledExternalApiUsages.length / externalApiUsages.length; + return modeledRatio * 100; +} diff --git a/extensions/ql-vscode/src/view/data-extensions-editor/supported.ts b/extensions/ql-vscode/src/view/data-extensions-editor/supported.ts deleted file mode 100644 index 670b7b58d..000000000 --- a/extensions/ql-vscode/src/view/data-extensions-editor/supported.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ExternalApiUsage } from "../../data-extensions-editor/external-api-usage"; - -export function calculateSupportedPercentage( - externalApiUsages: Array>, -): number { - if (externalApiUsages.length === 0) { - return 0; - } - - const supportedExternalApiUsages = externalApiUsages.filter( - (m) => m.supported, - ); - - const supportedRatio = - supportedExternalApiUsages.length / externalApiUsages.length; - return supportedRatio * 100; -} diff --git a/extensions/ql-vscode/test/unit-tests/data-extensions-editor/yaml.test.ts b/extensions/ql-vscode/test/unit-tests/data-extensions-editor/yaml.test.ts index dde07e6a4..a499e12eb 100644 --- a/extensions/ql-vscode/test/unit-tests/data-extensions-editor/yaml.test.ts +++ b/extensions/ql-vscode/test/unit-tests/data-extensions-editor/yaml.test.ts @@ -6,6 +6,7 @@ import { describe("createDataExtensionYaml", () => { it("creates the correct YAML file", () => { const yaml = createDataExtensionYaml( + "java", [ { signature: "org.sql2o.Connection#createQuery(String)", @@ -99,6 +100,32 @@ describe("createDataExtensionYaml", () => { pack: codeql/java-all extensible: neutralModel data: [] +`); + }); + + it("includes the correct language", () => { + const yaml = createDataExtensionYaml("csharp", [], {}); + + expect(yaml).toEqual(`extensions: + - addsTo: + pack: codeql/csharp-all + extensible: sourceModel + data: [] + + - addsTo: + pack: codeql/csharp-all + extensible: sinkModel + data: [] + + - addsTo: + pack: codeql/csharp-all + extensible: summaryModel + data: [] + + - addsTo: + pack: codeql/csharp-all + extensible: neutralModel + data: [] `); }); }); diff --git a/extensions/ql-vscode/test/vscode-tests/activated-extension/databases/db-panel.test.ts b/extensions/ql-vscode/test/vscode-tests/activated-extension/databases/db-panel.test.ts index 8dd3f19d4..7b72a571b 100644 --- a/extensions/ql-vscode/test/vscode-tests/activated-extension/databases/db-panel.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/activated-extension/databases/db-panel.test.ts @@ -53,7 +53,7 @@ describe("Db panel UI commands", () => { it.skip("should add new local db list", async () => { // Add db list jest.spyOn(window, "showQuickPick").mockResolvedValue({ - kind: DbListKind.Local, + databaseKind: DbListKind.Local, } as AddListQuickPickItem); jest.spyOn(window, "showInputBox").mockResolvedValue("my-list-1"); await commandManager.execute( @@ -73,7 +73,7 @@ describe("Db panel UI commands", () => { it("should add new remote repository", async () => { // Add db jest.spyOn(window, "showQuickPick").mockResolvedValue({ - kind: "repo", + remoteDatabaseKind: "repo", } as RemoteDatabaseQuickPickItem); jest.spyOn(window, "showInputBox").mockResolvedValue("owner1/repo1"); @@ -96,7 +96,7 @@ describe("Db panel UI commands", () => { it("should add new remote owner", async () => { // Add owner jest.spyOn(window, "showQuickPick").mockResolvedValue({ - kind: "owner", + remoteDatabaseKind: "owner", } as RemoteDatabaseQuickPickItem); jest.spyOn(window, "showInputBox").mockResolvedValue("owner1"); diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts index f7efd3cc0..9a17a9442 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/databaseFetcher.test.ts @@ -16,8 +16,6 @@ import { } from "../global.helper"; import { createMockCommandManager } from "../../__mocks__/commandsMock"; -jest.setTimeout(60_000); - /** * Run various integration tests for databases */ diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/helpers.test.ts index 7f8561bc6..7ef35d062 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/helpers.test.ts @@ -4,9 +4,6 @@ import { CodeQLCliServer } from "../../../src/cli"; import { tryGetQueryMetadata } from "../../../src/helpers"; import { getActivatedExtension } from "../global.helper"; -// up to 3 minutes per test -jest.setTimeout(3 * 60 * 1000); - describe("helpers (with CLI)", () => { const baseDir = __dirname; diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/jest.config.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/jest.config.ts index 3bd6d399c..ff7eac9da 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/jest.config.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/jest.config.ts @@ -6,6 +6,9 @@ const config: Config = { ...baseConfig, runner: "/../jest-runner-installed-extensions.ts", setupFilesAfterEnv: ["/jest.setup.ts"], + // CLI integration tests call into the CLI and execute queries, so these are expected to take a lot longer + // than the default 5 seconds. + testTimeout: 180_000, // 3 minutes }; export default config; diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts index 2b76797b4..546c055c1 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/legacy-query.test.ts @@ -98,8 +98,6 @@ const db: messages.Dataset = { workingSet: "default", }; -jest.setTimeout(60_000); - describeWithCodeQL()("using the legacy query server", () => { const nullProgressReporter: ProgressReporter = { report: () => { diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts index dbc4ac848..1aab15ab4 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/new-query.test.ts @@ -104,8 +104,6 @@ const nullProgressReporter: ProgressReporter = { }, }; -jest.setTimeout(20_000); - describeWithCodeQL()("using the new query server", () => { let qs: qsClient.QueryServerClient; let cliServer: cli.CodeQLCliServer; diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/packaging.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/packaging.test.ts index cd6940ccd..5d4c5c298 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/packaging.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/packaging.test.ts @@ -12,9 +12,6 @@ import { import { mockedQuickPickItem } from "../utils/mocking.helpers"; import { getActivatedExtension } from "../global.helper"; -// up to 3 minutes per test -jest.setTimeout(3 * 60 * 1000); - describe("Packaging commands", () => { let cli: CodeQLCliServer; const progress = jest.fn(); diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts index 073e4c6ad..de5d0071b 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/queries.test.ts @@ -27,8 +27,6 @@ import { QueryResultType } from "../../../src/pure/new-messages"; import { createVSCodeCommandManager } from "../../../src/common/vscode/commands"; import { AllCommands, QueryServerCommands } from "../../../src/common/commands"; -jest.setTimeout(20_000); - /** * Integration tests for queries */ diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts index 25adbd34a..9ce307b7f 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/run-cli.test.ts @@ -14,8 +14,6 @@ import { KeyType } from "../../../src/contextual/keyType"; import { faker } from "@faker-js/faker"; import { getActivatedExtension } from "../global.helper"; -jest.setTimeout(60_000); - /** * Perform proper integration tests by running the CLI */ diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/skeleton-query-wizard.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/skeleton-query-wizard.test.ts index d42c21197..e101cbf17 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/skeleton-query-wizard.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/skeleton-query-wizard.test.ts @@ -22,8 +22,6 @@ import * as databaseFetcher from "../../../src/databaseFetcher"; import { createMockDB } from "../../factories/databases/databases"; import { asError } from "../../../src/pure/helpers-pure"; -jest.setTimeout(80_000); - describe("SkeletonQueryWizard", () => { let mockCli: CodeQLCliServer; let wizard: SkeletonQueryWizard; @@ -84,11 +82,11 @@ describe("SkeletonQueryWizard", () => { jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([ { name: `codespaces-codeql`, - uri: { fsPath: storagePath }, + uri: { fsPath: storagePath, scheme: "file" }, }, { name: "/second/folder/path", - uri: { fsPath: storagePath }, + uri: { fsPath: storagePath, scheme: "file" }, }, ] as WorkspaceFolder[]); @@ -304,66 +302,6 @@ describe("SkeletonQueryWizard", () => { }); }); - describe("getFirstStoragePath", () => { - it("should return the first workspace folder", async () => { - jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([ - { - name: "codespaces-codeql", - uri: { fsPath: "codespaces-codeql" }, - }, - ] as WorkspaceFolder[]); - - wizard = new SkeletonQueryWizard( - mockCli, - jest.fn(), - credentials, - extLogger, - mockDatabaseManager, - token, - storagePath, - ); - - expect(wizard.getFirstStoragePath()).toEqual("codespaces-codeql"); - }); - - describe("if user is in vscode-codeql-starter workspace", () => { - it("should set storage path to parent folder", async () => { - jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([ - { - name: "codeql-custom-queries-cpp", - uri: { - fsPath: join( - "vscode-codeql-starter", - "codeql-custom-queries-cpp", - ), - }, - }, - { - name: "codeql-custom-queries-csharp", - uri: { - fsPath: join( - "vscode-codeql-starter", - "codeql-custom-queries-csharp", - ), - }, - }, - ] as WorkspaceFolder[]); - - wizard = new SkeletonQueryWizard( - mockCli, - jest.fn(), - credentials, - extLogger, - mockDatabaseManager, - token, - storagePath, - ); - - expect(wizard.getFirstStoragePath()).toEqual("vscode-codeql-starter"); - }); - }); - }); - describe("findDatabaseItemByNwo", () => { describe("when the item exists", () => { it("should return the database item", async () => { diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/sourcemap.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/sourcemap.test.ts index 615f10b30..763ee6294 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/sourcemap.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/sourcemap.test.ts @@ -5,8 +5,6 @@ import { readFile, writeFile, ensureDir, copy } from "fs-extra"; import { createVSCodeCommandManager } from "../../../src/common/vscode/commands"; import { AllCommands } from "../../../src/common/commands"; -jest.setTimeout(20_000); - /** * Integration tests for queries */ diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts index fd0f2accf..d1a3ac719 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-manager.test.ts @@ -29,9 +29,6 @@ import { QueryLanguage } from "../../../../src/common/query-language"; import { readBundledPack } from "../../utils/bundled-pack-helpers"; import { load } from "js-yaml"; -// up to 3 minutes per test -jest.setTimeout(3 * 60 * 1000); - describe("Variant Analysis Manager", () => { let cli: CodeQLCliServer; let cancellationTokenSource: CancellationTokenSource; diff --git a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-submission-integration.test.ts b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-submission-integration.test.ts index 70a6e93a9..fb3cabe72 100644 --- a/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-submission-integration.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/cli-integration/variant-analysis/variant-analysis-submission-integration.test.ts @@ -15,8 +15,6 @@ import { getActivatedExtension } from "../../global.helper"; import { createVSCodeCommandManager } from "../../../../src/common/vscode/commands"; import { AllCommands } from "../../../../src/common/commands"; -jest.setTimeout(30_000); - const mockServer = new MockGitHubApiServer(); beforeAll(() => mockServer.startServer()); afterEach(() => mockServer.unloadScenario()); diff --git a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts index 4e6fbaaa1..92d4c0164 100644 --- a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-databases.test.ts @@ -687,6 +687,22 @@ describe("local databases", () => { ); }); }); + + describe("when the QL pack already exists", () => { + beforeEach(() => { + fs.mkdirSync(join(dir.name, `codeql-custom-queries-${language}`)); + }); + + it("should exit early", async () => { + showBinaryChoiceDialogSpy = jest + .spyOn(helpers, "showBinaryChoiceDialog") + .mockResolvedValue(false); + + await (databaseManager as any).createSkeletonPacks(mockDbItem); + + expect(generateSpy).not.toBeCalled(); + }); + }); }); describe("openDatabase", () => { diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts index 6ee680d98..88ae01773 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/extension-pack-picker.test.ts @@ -1,4 +1,8 @@ -import { QuickPickItem, window } from "vscode"; +import { CancellationTokenSource, QuickPickItem, window } from "vscode"; +import { dump as dumpYaml, load as loadYaml } from "js-yaml"; +import { outputFile, readFile } from "fs-extra"; +import { join } from "path"; +import { dir } from "tmp-promise"; import { pickExtensionPackModelFile } from "../../../../src/data-extensions-editor/extension-pack-picker"; import { QlpacksInfo, ResolveExtensionsResult } from "../../../../src/cli"; @@ -21,14 +25,33 @@ describe("pickExtensionPackModelFile", () => { ], }, }; + const databaseItem = { + name: "github/vscode-codeql", + language: "java", + }; + + const cancellationTokenSource = new CancellationTokenSource(); + const token = cancellationTokenSource.token; const progress = jest.fn(); let showQuickPickSpy: jest.SpiedFunction; + let showInputBoxSpy: jest.SpiedFunction; + let showAndLogErrorMessageSpy: jest.SpiedFunction< + typeof helpers.showAndLogErrorMessage + >; beforeEach(() => { showQuickPickSpy = jest .spyOn(window, "showQuickPick") .mockRejectedValue(new Error("Unexpected call to showQuickPick")); + showInputBoxSpy = jest + .spyOn(window, "showInputBox") + .mockRejectedValue(new Error("Unexpected call to showInputBox")); + showAndLogErrorMessageSpy = jest + .spyOn(helpers, "showAndLogErrorMessage") + .mockImplementation((msg) => { + throw new Error(`Unexpected call to showAndLogErrorMessage: ${msg}`); + }); }); it("allows choosing an existing extension pack and model file", async () => { @@ -43,9 +66,14 @@ describe("pickExtensionPackModelFile", () => { file: "/a/b/c/my-extension-pack/models/model.yml", } as QuickPickItem); - expect(await pickExtensionPackModelFile(cliServer, progress)).toEqual( - "/a/b/c/my-extension-pack/models/model.yml", - ); + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual("/a/b/c/my-extension-pack/models/model.yml"); expect(showQuickPickSpy).toHaveBeenCalledTimes(2); expect(showQuickPickSpy).toHaveBeenCalledWith( [ @@ -57,10 +85,15 @@ describe("pickExtensionPackModelFile", () => { label: "another-extension-pack", extensionPack: "another-extension-pack", }, + { + label: expect.stringMatching(/create/i), + extensionPack: null, + }, ], { title: expect.any(String), }, + token, ); expect(showQuickPickSpy).toHaveBeenCalledWith( [ @@ -68,10 +101,15 @@ describe("pickExtensionPackModelFile", () => { label: "models/model.yml", file: "/a/b/c/my-extension-pack/models/model.yml", }, + { + label: expect.stringMatching(/create/i), + file: null, + }, ], { title: expect.any(String), }, + token, ); expect(cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); expect(cliServer.resolveQlpacks).toHaveBeenCalledWith([], true); @@ -82,39 +120,300 @@ describe("pickExtensionPackModelFile", () => { ); }); + it("allows choosing an existing extension pack and creating a new model file", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + ...qlPacks, + "my-extension-pack": [tmpDir.path], + }, + { + models: extensions.models, + data: { + [tmpDir.path]: [ + { + file: join(tmpDir.path, "models/model.yml"), + index: 0, + predicate: "sinkModel", + }, + ], + }, + }, + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce({ + label: "create", + file: null, + } as QuickPickItem); + showInputBoxSpy.mockResolvedValue("models/my-model.yml"); + + await outputFile( + join(tmpDir.path, "codeql-pack.yml"), + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: ["models/**/*.yml"], + }), + ); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(join(tmpDir.path, "models/my-model.yml")); + expect(showQuickPickSpy).toHaveBeenCalledTimes(2); + expect(showQuickPickSpy).toHaveBeenCalledWith( + [ + { + label: "my-extension-pack", + extensionPack: "my-extension-pack", + }, + { + label: "another-extension-pack", + extensionPack: "another-extension-pack", + }, + { + label: expect.stringMatching(/create/i), + extensionPack: null, + }, + ], + { + title: expect.any(String), + }, + token, + ); + expect(showQuickPickSpy).toHaveBeenCalledWith( + [ + { + label: "models/model.yml", + file: join(tmpDir.path, "models/model.yml"), + }, + { + label: expect.stringMatching(/create/i), + file: null, + }, + ], + { + title: expect.any(String), + }, + token, + ); + expect(showInputBoxSpy).toHaveBeenCalledWith( + { + title: expect.any(String), + value: "models/github.vscode-codeql.model.yml", + validateInput: expect.any(Function), + }, + token, + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); + expect(cliServer.resolveQlpacks).toHaveBeenCalledWith([], true); + expect(cliServer.resolveExtensions).toHaveBeenCalledTimes(1); + expect(cliServer.resolveExtensions).toHaveBeenCalledWith(tmpDir.path, []); + }); + it("allows cancelling the extension pack prompt", async () => { const cliServer = mockCliServer(qlPacks, extensions); showQuickPickSpy.mockResolvedValueOnce(undefined); - expect(await pickExtensionPackModelFile(cliServer, progress)).toEqual( - undefined, - ); + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); expect(cliServer.resolveExtensions).not.toHaveBeenCalled(); }); - it("does not show any options when there are no extension packs", async () => { + it("allows user to create an extension pack when there are no extension packs", async () => { + const cliServer = mockCliServer({}, { models: [], data: {} }); + + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "codeql-custom-queries-java", + path: tmpDir.path, + } as QuickPickItem); + showInputBoxSpy.mockResolvedValueOnce("my-extension-pack"); + showInputBoxSpy.mockResolvedValue("models/my-model.yml"); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(join(tmpDir.path, "my-extension-pack", "models", "my-model.yml")); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).toHaveBeenCalledTimes(2); + expect(showInputBoxSpy).toHaveBeenCalledWith( + { + title: expect.stringMatching(/extension pack/i), + prompt: expect.stringMatching(/extension pack/i), + placeHolder: expect.stringMatching(/github\/vscode-codeql-extensions/), + validateInput: expect.any(Function), + }, + token, + ); + expect(showInputBoxSpy).toHaveBeenCalledWith( + { + title: expect.stringMatching(/model file/), + value: "models/github.vscode-codeql.model.yml", + validateInput: expect.any(Function), + }, + token, + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + + expect( + loadYaml( + await readFile( + join(tmpDir.path, "my-extension-pack", "codeql-pack.yml"), + "utf8", + ), + ), + ).toEqual({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: ["models/**/*.yml"], + }); + }); + + it("allows user to create an extension pack when there are no extension packs with a different language", async () => { + const cliServer = mockCliServer({}, { models: [], data: {} }); + + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "codeql-custom-queries-java", + path: tmpDir.path, + } as QuickPickItem); + showInputBoxSpy.mockResolvedValueOnce("my-extension-pack"); + showInputBoxSpy.mockResolvedValue("models/my-model.yml"); + + expect( + await pickExtensionPackModelFile( + cliServer, + { + ...databaseItem, + language: "csharp", + }, + progress, + token, + ), + ).toEqual(join(tmpDir.path, "my-extension-pack", "models", "my-model.yml")); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).toHaveBeenCalledTimes(2); + expect(showInputBoxSpy).toHaveBeenCalledWith( + { + title: expect.stringMatching(/extension pack/i), + prompt: expect.stringMatching(/extension pack/i), + placeHolder: expect.stringMatching(/github\/vscode-codeql-extensions/), + validateInput: expect.any(Function), + }, + token, + ); + expect(showInputBoxSpy).toHaveBeenCalledWith( + { + title: expect.stringMatching(/model file/), + value: "models/github.vscode-codeql.model.yml", + validateInput: expect.any(Function), + }, + token, + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + + expect( + loadYaml( + await readFile( + join(tmpDir.path, "my-extension-pack", "codeql-pack.yml"), + "utf8", + ), + ), + ).toEqual({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/csharp-all": "*", + }, + dataExtensions: ["models/**/*.yml"], + }); + }); + + it("allows cancelling the workspace folder selection", async () => { const cliServer = mockCliServer({}, { models: [], data: {} }); showQuickPickSpy.mockResolvedValueOnce(undefined); - expect(await pickExtensionPackModelFile(cliServer, progress)).toEqual( - undefined, - ); + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); expect(showQuickPickSpy).toHaveBeenCalledTimes(1); - expect(showQuickPickSpy).toHaveBeenCalledWith([], { - title: expect.any(String), - }); + expect(showInputBoxSpy).toHaveBeenCalledTimes(0); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).not.toHaveBeenCalled(); + }); + + it("allows cancelling the extension pack name input", async () => { + const cliServer = mockCliServer({}, { models: [], data: {} }); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "codeql-custom-queries-java", + path: "/a/b/c", + } as QuickPickItem); + showInputBoxSpy.mockResolvedValueOnce(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).toHaveBeenCalledTimes(1); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); expect(cliServer.resolveExtensions).not.toHaveBeenCalled(); }); it("shows an error when an extension pack resolves to more than 1 location", async () => { - const showAndLogErrorMessageSpy = jest.spyOn( - helpers, - "showAndLogErrorMessage", - ); + showAndLogErrorMessageSpy.mockResolvedValue(undefined); const cliServer = mockCliServer( { @@ -131,9 +430,14 @@ describe("pickExtensionPackModelFile", () => { extensionPack: "my-extension-pack", } as QuickPickItem); - expect(await pickExtensionPackModelFile(cliServer, progress)).toEqual( - undefined, - ); + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); expect(showAndLogErrorMessageSpy).toHaveBeenCalledTimes(1); expect(showAndLogErrorMessageSpy).toHaveBeenCalledWith( expect.stringMatching(/could not be resolved to a single location/), @@ -153,47 +457,468 @@ describe("pickExtensionPackModelFile", () => { } as QuickPickItem); showQuickPickSpy.mockResolvedValueOnce(undefined); - expect(await pickExtensionPackModelFile(cliServer, progress)).toEqual( - undefined, - ); + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); expect(cliServer.resolveExtensions).toHaveBeenCalled(); }); - it("does not show any options when there are no model files", async () => { - const cliServer = mockCliServer(qlPacks, { models: [], data: {} }); + it("shows create input box when there are no model files", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + await outputFile( + join(tmpDir.path, "codeql-pack.yml"), + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: ["models/**/*.yml"], + }), + ); showQuickPickSpy.mockResolvedValueOnce({ label: "my-extension-pack", extensionPack: "my-extension-pack", } as QuickPickItem); showQuickPickSpy.mockResolvedValueOnce(undefined); + showInputBoxSpy.mockResolvedValue("models/my-model.yml"); - expect(await pickExtensionPackModelFile(cliServer, progress)).toEqual( - undefined, - ); - expect(showQuickPickSpy).toHaveBeenCalledTimes(2); - expect(showQuickPickSpy).toHaveBeenCalledWith( - [ - { - label: "my-extension-pack", - extensionPack: "my-extension-pack", - }, - { - label: "another-extension-pack", - extensionPack: "another-extension-pack", - }, - ], + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(join(tmpDir.path, "models/my-model.yml")); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).toHaveBeenCalledWith( { title: expect.any(String), + value: "models/github.vscode-codeql.model.yml", + validateInput: expect.any(Function), }, + token, ); - expect(showQuickPickSpy).toHaveBeenCalledWith([], { - title: expect.any(String), - }); expect(cliServer.resolveQlpacks).toHaveBeenCalled(); expect(cliServer.resolveExtensions).toHaveBeenCalled(); }); + + it("shows an error when there is no pack YAML file", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showAndLogErrorMessageSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).not.toHaveBeenCalled(); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledTimes(1); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledWith( + expect.stringMatching(/codeql-pack\.yml/), + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + }); + + it("shows an error when the pack YAML file is invalid", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + await outputFile(join(tmpDir.path, "codeql-pack.yml"), dumpYaml("java")); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showAndLogErrorMessageSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).not.toHaveBeenCalled(); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledTimes(1); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledWith( + expect.stringMatching(/Could not parse/), + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + }); + + it("shows an error when the pack YAML does not contain dataExtensions", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + await outputFile( + join(tmpDir.path, "codeql-pack.yml"), + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + }), + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showAndLogErrorMessageSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).not.toHaveBeenCalled(); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledTimes(1); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledWith( + expect.stringMatching(/Expected 'dataExtensions' to be/), + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + }); + + it("shows an error when the pack YAML dataExtensions is invalid", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + await outputFile( + join(tmpDir.path, "codeql-pack.yml"), + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: { + "codeql/java-all": "invalid", + }, + }), + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showAndLogErrorMessageSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).not.toHaveBeenCalled(); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledTimes(1); + expect(showAndLogErrorMessageSpy).toHaveBeenCalledWith( + expect.stringMatching(/Expected 'dataExtensions' to be/), + ); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + }); + + it("allows cancelling the new file input box", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + await outputFile( + join(tmpDir.path, "codeql-pack.yml"), + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: ["models/**/*.yml"], + }), + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showInputBoxSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + expect(showQuickPickSpy).toHaveBeenCalledTimes(1); + expect(showInputBoxSpy).toHaveBeenCalledTimes(1); + expect(cliServer.resolveQlpacks).toHaveBeenCalled(); + expect(cliServer.resolveExtensions).toHaveBeenCalled(); + }); + + it("validates the pack name input", async () => { + const cliServer = mockCliServer({}, { models: [], data: {} }); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "a", + path: "/a/b/c", + } as QuickPickItem); + showInputBoxSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + + const validateFile = showInputBoxSpy.mock.calls[0][0]?.validateInput; + expect(validateFile).toBeDefined(); + if (!validateFile) { + return; + } + + expect(await validateFile("")).toEqual("Pack name must not be empty"); + expect(await validateFile("a".repeat(129))).toEqual( + "Pack name must be no longer than 128 characters", + ); + expect(await validateFile("github/vscode-codeql/extensions")).toEqual( + "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", + ); + expect(await validateFile("VSCODE")).toEqual( + "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", + ); + expect(await validateFile("github/vscode-codeql-")).toEqual( + "Invalid package name: a pack name must contain only lowercase ASCII letters, ASCII digits, and hyphens", + ); + expect( + await validateFile("github/vscode-codeql-extensions"), + ).toBeUndefined(); + expect(await validateFile("vscode-codeql-extensions")).toBeUndefined(); + }); + + it("validates the file input", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + const qlpackPath = join(tmpDir.path, "codeql-pack.yml"); + await outputFile( + qlpackPath, + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: ["models/**/*.yml", "data/**/*.yml"], + }), + ); + await outputFile( + join(tmpDir.path, "models", "model.yml"), + dumpYaml({ + extensions: [], + }), + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showInputBoxSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + + const validateFile = showInputBoxSpy.mock.calls[0][0]?.validateInput; + expect(validateFile).toBeDefined(); + if (!validateFile) { + return; + } + + expect(await validateFile("")).toEqual("File name must not be empty"); + expect(await validateFile("models/model.yml")).toEqual( + "File already exists", + ); + expect(await validateFile("../model.yml")).toEqual( + "File must be in the extension pack", + ); + expect(await validateFile("/home/user/model.yml")).toEqual( + "File must be in the extension pack", + ); + expect(await validateFile("model.yml")).toEqual( + `File must match one of the patterns in 'dataExtensions' in ${qlpackPath}`, + ); + expect(await validateFile("models/model.yaml")).toEqual( + `File must match one of the patterns in 'dataExtensions' in ${qlpackPath}`, + ); + expect(await validateFile("models/my-model.yml")).toBeUndefined(); + expect(await validateFile("models/nested/model.yml")).toBeUndefined(); + expect(await validateFile("data/model.yml")).toBeUndefined(); + }); + + it("allows the dataExtensions to be a string", async () => { + const tmpDir = await dir({ + unsafeCleanup: true, + }); + + const cliServer = mockCliServer( + { + "my-extension-pack": [tmpDir.path], + }, + { models: [], data: {} }, + ); + + const qlpackPath = join(tmpDir.path, "codeql-pack.yml"); + await outputFile( + qlpackPath, + dumpYaml({ + name: "my-extension-pack", + version: "0.0.0", + library: true, + extensionTargets: { + "codeql/java-all": "*", + }, + dataExtensions: "models/**/*.yml", + }), + ); + await outputFile( + join(tmpDir.path, "models", "model.yml"), + dumpYaml({ + extensions: [], + }), + ); + + showQuickPickSpy.mockResolvedValueOnce({ + label: "my-extension-pack", + extensionPack: "my-extension-pack", + } as QuickPickItem); + showQuickPickSpy.mockResolvedValueOnce(undefined); + showInputBoxSpy.mockResolvedValue(undefined); + + expect( + await pickExtensionPackModelFile( + cliServer, + databaseItem, + progress, + token, + ), + ).toEqual(undefined); + + const validateFile = showInputBoxSpy.mock.calls[0][0]?.validateInput; + expect(validateFile).toBeDefined(); + if (!validateFile) { + return; + } + + expect(await validateFile("models/my-model.yml")).toBeUndefined(); + }); }); function mockCliServer( diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts index 4d5d47b66..dd289ed14 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/external-api-usage-query.test.ts @@ -5,11 +5,12 @@ import { import { createMockLogger } from "../../../__mocks__/loggerMock"; import type { Uri } from "vscode"; import { DatabaseKind } from "../../../../src/local-databases"; -import * as queryResolver from "../../../../src/contextual/queryResolver"; import { file } from "tmp-promise"; import { QueryResultType } from "../../../../src/pure/new-messages"; -import { readFile } from "fs-extra"; +import { readdir, readFile } from "fs-extra"; import { load } from "js-yaml"; +import { dirname, join } from "path"; +import { fetchExternalApiQueries } from "../../../../src/data-extensions-editor/queries/index"; import * as helpers from "../../../../src/helpers"; import { RedactableError } from "../../../../src/pure/errors"; @@ -27,98 +28,98 @@ function createMockUri(path = "/a/b/c/foo"): Uri { } describe("runQuery", () => { - it("runs the query", async () => { - jest.spyOn(queryResolver, "qlpackOfDatabase").mockResolvedValue({ - dbschemePack: "codeql/java-all", - dbschemePackIsLibraryPack: false, - queryPack: "codeql/java-queries", - }); - + it("runs all queries", async () => { const logPath = (await file()).path; - const options = { - cliServer: { - resolveQlpacks: jest.fn().mockResolvedValue({ - "my/java-extensions": "/a/b/c/", - }), - resolveQueriesInSuite: jest - .fn() - .mockResolvedValue([ - "/home/github/codeql/java/ql/src/Telemetry/FetchExternalAPIs.ql", - ]), - }, - queryRunner: { - createQueryRun: jest.fn().mockReturnValue({ - evaluate: jest.fn().mockResolvedValue({ - resultType: QueryResultType.SUCCESS, + // Test all queries + for (const [lang, query] of Object.entries(fetchExternalApiQueries)) { + const options = { + cliServer: { + resolveQlpacks: jest.fn().mockResolvedValue({ + "my/extensions": "/a/b/c/", }), - outputDir: { - logPath, + }, + queryRunner: { + createQueryRun: jest.fn().mockReturnValue({ + evaluate: jest.fn().mockResolvedValue({ + resultType: QueryResultType.SUCCESS, + }), + outputDir: { + logPath, + }, + }), + logger: createMockLogger(), + }, + databaseItem: { + databaseUri: createMockUri("/a/b/c/src.zip"), + contents: { + kind: DatabaseKind.Database, + name: "foo", + datasetUri: createMockUri(), }, - }), - logger: createMockLogger(), - }, - logger: createMockLogger(), - databaseItem: { - databaseUri: createMockUri("/a/b/c/src.zip"), - contents: { - kind: DatabaseKind.Database, - name: "foo", - datasetUri: createMockUri(), + language: lang, }, - language: "java", - }, - queryStorageDir: "/tmp/queries", - progress: jest.fn(), - token: { - isCancellationRequested: false, - onCancellationRequested: jest.fn(), - }, - }; - const result = await runQuery(options); - - expect(result?.resultType).toEqual(QueryResultType.SUCCESS); - - expect(options.cliServer.resolveQueriesInSuite).toHaveBeenCalledWith( - expect.anything(), - [], - ); - const suiteFile = options.cliServer.resolveQueriesInSuite.mock.calls[0][0]; - const suiteFileContents = await readFile(suiteFile, "utf8"); - const suiteYaml = load(suiteFileContents); - expect(suiteYaml).toEqual([ - { - from: "codeql/java-all", - queries: ".", - include: { - id: "java/telemetry/fetch-external-apis", + queryStorageDir: "/tmp/queries", + progress: jest.fn(), + token: { + isCancellationRequested: false, + onCancellationRequested: jest.fn(), }, - }, - { - from: "codeql/java-queries", - queries: ".", - include: { - id: "java/telemetry/fetch-external-apis", - }, - }, - ]); + }; + const result = await runQuery(options); - expect(options.cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); - expect(options.cliServer.resolveQlpacks).toHaveBeenCalledWith([], true); - expect(options.queryRunner.createQueryRun).toHaveBeenCalledWith( - "/a/b/c/src.zip", - { - queryPath: - "/home/github/codeql/java/ql/src/Telemetry/FetchExternalAPIs.ql", - quickEvalPosition: undefined, - }, - false, - [], - ["my/java-extensions"], - "/tmp/queries", - undefined, - undefined, - ); + expect(result?.resultType).toEqual(QueryResultType.SUCCESS); + + expect(options.cliServer.resolveQlpacks).toHaveBeenCalledTimes(1); + expect(options.cliServer.resolveQlpacks).toHaveBeenCalledWith([], true); + expect(options.queryRunner.createQueryRun).toHaveBeenCalledWith( + "/a/b/c/src.zip", + { + queryPath: expect.stringMatching(/FetchExternalApis\.ql/), + quickEvalPosition: undefined, + }, + false, + [], + ["my/extensions"], + "/tmp/queries", + undefined, + undefined, + ); + + const queryPath = + options.queryRunner.createQueryRun.mock.calls[0][1].queryPath; + const queryDirectory = dirname(queryPath); + + const queryFiles = await readdir(queryDirectory); + expect(queryFiles.sort()).toEqual( + ["codeql-pack.yml", "FetchExternalApis.ql", "ExternalApi.qll"].sort(), + ); + + const suiteFileContents = await readFile( + join(queryDirectory, "codeql-pack.yml"), + "utf8", + ); + const suiteYaml = load(suiteFileContents); + expect(suiteYaml).toEqual({ + name: "codeql/external-api-usage", + version: "0.0.0", + dependencies: { + [`codeql/${lang}-all`]: "*", + }, + }); + + expect( + await readFile(join(queryDirectory, "FetchExternalApis.ql"), "utf8"), + ).toEqual(query.mainQuery); + + for (const [filename, contents] of Object.entries( + query.dependencies ?? {}, + )) { + expect(await readFile(join(queryDirectory, filename), "utf8")).toEqual( + contents, + ); + } + } }); }); diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/data/variant-analysis/workspace-query-history.json b/extensions/ql-vscode/test/vscode-tests/no-workspace/data/variant-analysis/workspace-query-history.json index add4195f2..d17874be9 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/data/variant-analysis/workspace-query-history.json +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/data/variant-analysis/workspace-query-history.json @@ -7,7 +7,11 @@ "completed": true, "variantAnalysis": { "id": 98574321397, - "controllerRepoId": 128321, + "controllerRepo": { + "id": 128321, + "fullName": "github/codeql", + "private": false + }, "query": { "name": "Variant Analysis Integration Test 1", "filePath": "PLACEHOLDER/q2.ql", @@ -30,7 +34,11 @@ "completed": true, "variantAnalysis": { "id": 98574321397, - "controllerRepoId": 128321, + "controllerRepo": { + "id": 128321, + "fullName": "github/codeql", + "private": false + }, "query": { "name": "Variant Analysis Integration Test 2", "filePath": "PLACEHOLDER/q2.ql", diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts index 98919219d..757525004 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/helpers.test.ts @@ -26,6 +26,7 @@ import { import { DirResult } from "tmp"; import { + getFirstWorkspaceFolder, getInitialQueryContents, InvocationRateLimiter, isFolderAlreadyInWorkspace, @@ -272,6 +273,13 @@ describe("helpers", () => { class MockEnvironmentVariableCollection implements EnvironmentVariableCollection { + [Symbol.iterator](): Iterator< + [variable: string, mutator: EnvironmentVariableMutator], + any, + undefined + > { + throw new Error("Method not implemented."); + } persistent = false; replace(_variable: string, _value: string): void { throw new Error("Method not implemented."); @@ -671,3 +679,42 @@ describe("prepareCodeTour", () => { }); }); }); + +describe("getFirstWorkspaceFolder", () => { + it("should return the first workspace folder", async () => { + jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([ + { + name: "codespaces-codeql", + uri: { fsPath: "codespaces-codeql", scheme: "file" }, + }, + ] as WorkspaceFolder[]); + + expect(getFirstWorkspaceFolder()).toEqual("codespaces-codeql"); + }); + + describe("if user is in vscode-codeql-starter workspace", () => { + it("should set storage path to parent folder", async () => { + jest.spyOn(workspace, "workspaceFolders", "get").mockReturnValue([ + { + name: "codeql-custom-queries-cpp", + uri: { + fsPath: join("vscode-codeql-starter", "codeql-custom-queries-cpp"), + scheme: "file", + }, + }, + { + name: "codeql-custom-queries-csharp", + uri: { + fsPath: join( + "vscode-codeql-starter", + "codeql-custom-queries-csharp", + ), + scheme: "file", + }, + }, + ] as WorkspaceFolder[]); + + expect(getFirstWorkspaceFolder()).toEqual("vscode-codeql-starter"); + }); + }); +});