diff --git a/.github/workflows/cli-test.yml b/.github/workflows/cli-test.yml
index afb9b01e0..5e2463d00 100644
--- a/.github/workflows/cli-test.yml
+++ b/.github/workflows/cli-test.yml
@@ -11,6 +11,7 @@ on:
- extensions/ql-vscode/src/language-support/**
- extensions/ql-vscode/src/query-server/**
- extensions/ql-vscode/supported_cli_versions.json
+ - extensions/ql-vscode/src/variant-analysis/run-remote-query.ts
jobs:
find-nightly:
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
new file mode 100644
index 000000000..26c8837e0
--- /dev/null
+++ b/.github/workflows/e2e-tests.yml
@@ -0,0 +1,46 @@
+name: Run E2E Playwright tests
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+jobs:
+ e2e-test:
+ name: E2E Test
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version-file: extensions/ql-vscode/.nvmrc
+ cache: 'npm'
+ cache-dependency-path: extensions/ql-vscode/package-lock.json
+
+ - name: Install dependencies
+ working-directory: extensions/ql-vscode
+ run: npm ci
+
+ - name: Start containers
+ working-directory: extensions/ql-vscode/test/e2e
+ run: docker-compose -f "docker-compose.yml" up -d --build
+
+ - name: Install Playwright Browsers
+ working-directory: extensions/ql-vscode
+ run: npx playwright install --with-deps
+ - name: Run Playwright tests
+ working-directory: extensions/ql-vscode/test/e2e
+ run: npx playwright test
+ - uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: playwright-report
+ path: extensions/ql-vscode/playwright-report/
+ retention-days: 30
+ - name: Stop containers
+ working-directory: extensions/ql-vscode/test/e2e
+ if: always()
+ run: docker-compose -f "docker-compose.yml" down -v
diff --git a/.gitignore b/.gitignore
index 94107c69e..4784b9ab8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,7 @@ artifacts/
# CodeQL metadata
.cache/
.codeql/
+
+# E2E Reports
+**/playwright-report/**
+**/test-results/**
\ No newline at end of file
diff --git a/extensions/ql-vscode/.eslintrc.js b/extensions/ql-vscode/.eslintrc.js
index 5621731a1..6b28409c4 100644
--- a/extensions/ql-vscode/.eslintrc.js
+++ b/extensions/ql-vscode/.eslintrc.js
@@ -28,6 +28,7 @@ const baseConfig = {
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
+ "plugin:deprecation/recommended",
],
rules: {
"@typescript-eslint/await-thenable": "error",
diff --git a/extensions/ql-vscode/.storybook/vscode-theme-addon/manager.tsx b/extensions/ql-vscode/.storybook/vscode-theme-addon/manager.tsx
index 9ab2d0b6c..8d7881ffb 100644
--- a/extensions/ql-vscode/.storybook/vscode-theme-addon/manager.tsx
+++ b/extensions/ql-vscode/.storybook/vscode-theme-addon/manager.tsx
@@ -1,5 +1,6 @@
import * as React from "react";
-import { addons, types } from "@storybook/manager-api";
+import { addons } from "@storybook/manager-api";
+import { Addon_TypesEnum } from "@storybook/types";
import { ThemeSelector } from "./ThemeSelector";
const ADDON_ID = "vscode-theme-addon";
@@ -7,7 +8,7 @@ const ADDON_ID = "vscode-theme-addon";
addons.register(ADDON_ID, () => {
addons.add(ADDON_ID, {
title: "VSCode Themes",
- type: types.TOOL,
+ type: Addon_TypesEnum.TOOL,
match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
render: () => ,
});
diff --git a/extensions/ql-vscode/package-lock.json b/extensions/ql-vscode/package-lock.json
index e72683471..170e7469d 100644
--- a/extensions/ql-vscode/package-lock.json
+++ b/extensions/ql-vscode/package-lock.json
@@ -34,7 +34,7 @@
"source-map": "^0.7.4",
"source-map-support": "^0.5.21",
"stream-json": "^1.7.3",
- "styled-components": "^6.0.2",
+ "styled-components": "^6.1.8",
"tmp": "^0.2.1",
"tmp-promise": "^3.0.2",
"tree-kill": "^1.2.2",
@@ -42,7 +42,7 @@
"vscode-jsonrpc": "^8.0.2",
"vscode-languageclient": "^8.0.2",
"yauzl": "^2.10.0",
- "zip-a-folder": "^3.1.3"
+ "zip-a-folder": "^3.1.6"
},
"devDependencies": {
"@babel/core": "^7.18.13",
@@ -53,6 +53,7 @@
"@faker-js/faker": "^8.0.2",
"@github/markdownlint-github": "^0.6.0",
"@octokit/plugin-throttling": "^8.0.0",
+ "@playwright/test": "^1.40.1",
"@storybook/addon-a11y": "^7.6.9",
"@storybook/addon-actions": "^7.1.0",
"@storybook/addon-essentials": "^7.1.0",
@@ -81,7 +82,7 @@
"@types/node": "18.15.*",
"@types/node-fetch": "^2.5.2",
"@types/react": "^18.0.28",
- "@types/react-dom": "^18.0.11",
+ "@types/react-dom": "^18.2.18",
"@types/sarif": "^2.1.2",
"@types/semver": "^7.2.0",
"@types/stream-json": "^1.7.1",
@@ -105,6 +106,7 @@
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.1",
+ "eslint-plugin-deprecation": "^2.0.0",
"eslint-plugin-etc": "^2.0.2",
"eslint-plugin-github": "^4.4.1",
"eslint-plugin-import": "^2.29.1",
@@ -124,13 +126,13 @@
"jest-environment-jsdom": "^29.0.3",
"jest-runner-vscode": "^3.0.1",
"lint-staged": "^15.0.2",
- "markdownlint-cli2": "^0.11.0",
+ "markdownlint-cli2": "^0.12.1",
"markdownlint-cli2-formatter-pretty": "^0.0.5",
"mini-css-extract-plugin": "^2.6.1",
"npm-run-all": "^4.1.5",
"patch-package": "^8.0.0",
- "prettier": "^3.0.0",
- "storybook": "^7.6.7",
+ "prettier": "^3.2.4",
+ "storybook": "^7.6.10",
"tar-stream": "^3.0.0",
"through2": "^4.0.2",
"ts-jest": "^29.0.1",
@@ -2473,9 +2475,9 @@
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
},
"node_modules/@emotion/unitless": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
- "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz",
+ "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw=="
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.0.1",
@@ -4442,6 +4444,21 @@
"node": ">= 8"
}
},
+ "node_modules/@playwright/test": {
+ "version": "1.40.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz",
+ "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==",
+ "dev": true,
+ "dependencies": {
+ "playwright": "1.40.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.11",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz",
@@ -5671,15 +5688,15 @@
}
},
"node_modules/@storybook/builder-manager": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.7.tgz",
- "integrity": "sha512-6HYpj6+g/qbDMvImVz/G/aANbkhppyBa1ozfHxLK7tRD79YvozCWmj2Z9umRekPv9VIeMxnI5EEzJXOsoMX5DQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.10.tgz",
+ "integrity": "sha512-f+YrjZwohGzvfDtH8BHzqM3xW0p4vjjg9u7uzRorqUiNIAAKHpfNrZ/WvwPlPYmrpAHt4xX/nXRJae4rFSygPw==",
"dev": true,
"dependencies": {
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
- "@storybook/core-common": "7.6.7",
- "@storybook/manager": "7.6.7",
- "@storybook/node-logger": "7.6.7",
+ "@storybook/core-common": "7.6.10",
+ "@storybook/manager": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
"@types/ejs": "^3.1.1",
"@types/find-cache-dir": "^3.2.1",
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10",
@@ -5699,13 +5716,13 @@
}
},
"node_modules/@storybook/builder-manager/node_modules/@storybook/channels": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.7.tgz",
- "integrity": "sha512-u1hURhfQHHtZyRIDUENRCp+CRRm7IQfcjQaoWI06XCevQPuhVEtFUfXHjG+J74aA/JuuTLFUtqwNm1zGqbXTAQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.10.tgz",
+ "integrity": "sha512-ITCLhFuDBKgxetuKnWwYqMUWlU7zsfH3gEKZltTb+9/2OAWR7ez0iqU7H6bXP1ridm0DCKkt2UMWj2mmr9iQqg==",
"dev": true,
"dependencies": {
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/global": "^5.0.0",
"qs": "^6.10.0",
"telejson": "^7.2.0",
@@ -5717,9 +5734,9 @@
}
},
"node_modules/@storybook/builder-manager/node_modules/@storybook/client-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.7.tgz",
- "integrity": "sha512-A16zpWgsa0gSdXMR9P3bWVdC9u/1B1oG4H7Z1+JhNzgnL3CdyOYO0qFSiAtNBso4nOjIAJVb6/AoBzdRhmSVQg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.10.tgz",
+ "integrity": "sha512-U7bbpu21ntgePMz/mKM18qvCSWCUGCUlYru8mgVlXLCKqFqfTeP887+CsPEQf29aoE3cLgDrxqbRJ1wxX9kL9A==",
"dev": true,
"dependencies": {
"@storybook/global": "^5.0.0"
@@ -5730,14 +5747,14 @@
}
},
"node_modules/@storybook/builder-manager/node_modules/@storybook/core-common": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.7.tgz",
- "integrity": "sha512-F1fJnauVSPQtAlpicbN/O4XW38Ai8kf/IoU0Hgm9gEwurIk6MF5hiVLsaTI/5GUbrepMl9d9J+iIL4lHAT8IyA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.10.tgz",
+ "integrity": "sha512-K3YWqjCKMnpvYsWNjOciwTH6zWbuuZzmOiipziZaVJ+sB1XYmH52Y3WGEm07TZI8AYK9DRgwA13dR/7W0nw72Q==",
"dev": true,
"dependencies": {
- "@storybook/core-events": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/core-events": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/find-cache-dir": "^3.2.1",
"@types/node": "^18.0.0",
"@types/node-fetch": "^2.6.4",
@@ -5765,9 +5782,9 @@
}
},
"node_modules/@storybook/builder-manager/node_modules/@storybook/core-events": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.7.tgz",
- "integrity": "sha512-KZ5d03c47pnr5/kY26pJtWq7WpmCPXLbgyjJZDSc+TTY153BdZksvlBXRHtqM1yj2UM6QsSyIuiJaADJNAbP2w==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.10.tgz",
+ "integrity": "sha512-yccDH67KoROrdZbRKwxgTswFMAco5nlCyxszCDASCLygGSV2Q2e+YuywrhchQl3U6joiWi3Ps1qWu56NeNafag==",
"dev": true,
"dependencies": {
"ts-dedent": "^2.0.0"
@@ -5778,9 +5795,9 @@
}
},
"node_modules/@storybook/builder-manager/node_modules/@storybook/node-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.7.tgz",
- "integrity": "sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.10.tgz",
+ "integrity": "sha512-ZBuqrv4bjJzKXyfRGFkVIi+z6ekn6rOPoQao4KmsfLNQAUUsEdR8Baw/zMnnU417zw5dSEaZdpuwx75SCQAeOA==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -5788,12 +5805,12 @@
}
},
"node_modules/@storybook/builder-manager/node_modules/@storybook/types": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.7.tgz",
- "integrity": "sha512-VcGwrI4AkBENxkoAUJ+Z7SyMK73hpoY0TTtw2J7tc05/xdiXhkQTX15Qa12IBWIkoXCyNrtaU+q7KR8Tjzi+uw==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.10.tgz",
+ "integrity": "sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==",
"dev": true,
"dependencies": {
- "@storybook/channels": "7.6.7",
+ "@storybook/channels": "7.6.10",
"@types/babel__core": "^7.0.0",
"@types/express": "^4.7.0",
"file-system-cache": "2.3.0"
@@ -6111,23 +6128,23 @@
}
},
"node_modules/@storybook/cli": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.6.7.tgz",
- "integrity": "sha512-DwDWzkifBH17ry+n+d+u52Sv69dZQ+04ETJdDDzghcyAcKnFzrRNukj4tJ21cm+ZAU/r0fKR9d4Qpbogca9fAg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.6.10.tgz",
+ "integrity": "sha512-pK1MEseMm73OMO2OVoSz79QWX8ymxgIGM8IeZTCo9gImiVRChMNDFYcv8yPWkjuyesY8c15CoO48aR7pdA1OjQ==",
"dev": true,
"dependencies": {
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/types": "^7.23.0",
"@ndelangen/get-tarball": "^3.0.7",
- "@storybook/codemod": "7.6.7",
- "@storybook/core-common": "7.6.7",
- "@storybook/core-events": "7.6.7",
- "@storybook/core-server": "7.6.7",
- "@storybook/csf-tools": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/telemetry": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/codemod": "7.6.10",
+ "@storybook/core-common": "7.6.10",
+ "@storybook/core-events": "7.6.10",
+ "@storybook/core-server": "7.6.10",
+ "@storybook/csf-tools": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/telemetry": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/semver": "^7.3.4",
"@yarnpkg/fslib": "2.10.3",
"@yarnpkg/libzip": "2.3.0",
@@ -6152,7 +6169,6 @@
"puppeteer-core": "^2.1.1",
"read-pkg-up": "^7.0.1",
"semver": "^7.3.7",
- "simple-update-notifier": "^2.0.0",
"strip-json-comments": "^3.0.1",
"tempy": "^1.0.1",
"ts-dedent": "^2.0.0",
@@ -6168,13 +6184,13 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/channels": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.7.tgz",
- "integrity": "sha512-u1hURhfQHHtZyRIDUENRCp+CRRm7IQfcjQaoWI06XCevQPuhVEtFUfXHjG+J74aA/JuuTLFUtqwNm1zGqbXTAQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.10.tgz",
+ "integrity": "sha512-ITCLhFuDBKgxetuKnWwYqMUWlU7zsfH3gEKZltTb+9/2OAWR7ez0iqU7H6bXP1ridm0DCKkt2UMWj2mmr9iQqg==",
"dev": true,
"dependencies": {
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/global": "^5.0.0",
"qs": "^6.10.0",
"telejson": "^7.2.0",
@@ -6186,9 +6202,9 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/client-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.7.tgz",
- "integrity": "sha512-A16zpWgsa0gSdXMR9P3bWVdC9u/1B1oG4H7Z1+JhNzgnL3CdyOYO0qFSiAtNBso4nOjIAJVb6/AoBzdRhmSVQg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.10.tgz",
+ "integrity": "sha512-U7bbpu21ntgePMz/mKM18qvCSWCUGCUlYru8mgVlXLCKqFqfTeP887+CsPEQf29aoE3cLgDrxqbRJ1wxX9kL9A==",
"dev": true,
"dependencies": {
"@storybook/global": "^5.0.0"
@@ -6199,14 +6215,14 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/core-common": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.7.tgz",
- "integrity": "sha512-F1fJnauVSPQtAlpicbN/O4XW38Ai8kf/IoU0Hgm9gEwurIk6MF5hiVLsaTI/5GUbrepMl9d9J+iIL4lHAT8IyA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.10.tgz",
+ "integrity": "sha512-K3YWqjCKMnpvYsWNjOciwTH6zWbuuZzmOiipziZaVJ+sB1XYmH52Y3WGEm07TZI8AYK9DRgwA13dR/7W0nw72Q==",
"dev": true,
"dependencies": {
- "@storybook/core-events": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/core-events": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/find-cache-dir": "^3.2.1",
"@types/node": "^18.0.0",
"@types/node-fetch": "^2.6.4",
@@ -6234,9 +6250,9 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/core-events": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.7.tgz",
- "integrity": "sha512-KZ5d03c47pnr5/kY26pJtWq7WpmCPXLbgyjJZDSc+TTY153BdZksvlBXRHtqM1yj2UM6QsSyIuiJaADJNAbP2w==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.10.tgz",
+ "integrity": "sha512-yccDH67KoROrdZbRKwxgTswFMAco5nlCyxszCDASCLygGSV2Q2e+YuywrhchQl3U6joiWi3Ps1qWu56NeNafag==",
"dev": true,
"dependencies": {
"ts-dedent": "^2.0.0"
@@ -6247,9 +6263,9 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/csf-tools": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.7.tgz",
- "integrity": "sha512-hyRbUGa2Uxvz3U09BjcOfMNf/5IYgRum1L6XszqK2O8tK9DGte1r6hArCIAcqiEmFMC40d0kalPzqu6WMNn7sg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.10.tgz",
+ "integrity": "sha512-TnDNAwIALcN6SA4l00Cb67G02XMOrYU38bIpFJk5VMDX2dvgPjUtJNBuLmEbybGcOt7nPyyFIHzKcY5FCVGoWA==",
"dev": true,
"dependencies": {
"@babel/generator": "^7.23.0",
@@ -6257,7 +6273,7 @@
"@babel/traverse": "^7.23.2",
"@babel/types": "^7.23.0",
"@storybook/csf": "^0.1.2",
- "@storybook/types": "7.6.7",
+ "@storybook/types": "7.6.10",
"fs-extra": "^11.1.0",
"recast": "^0.23.1",
"ts-dedent": "^2.0.0"
@@ -6268,9 +6284,9 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/node-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.7.tgz",
- "integrity": "sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.10.tgz",
+ "integrity": "sha512-ZBuqrv4bjJzKXyfRGFkVIi+z6ekn6rOPoQao4KmsfLNQAUUsEdR8Baw/zMnnU417zw5dSEaZdpuwx75SCQAeOA==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -6278,12 +6294,12 @@
}
},
"node_modules/@storybook/cli/node_modules/@storybook/types": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.7.tgz",
- "integrity": "sha512-VcGwrI4AkBENxkoAUJ+Z7SyMK73hpoY0TTtw2J7tc05/xdiXhkQTX15Qa12IBWIkoXCyNrtaU+q7KR8Tjzi+uw==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.10.tgz",
+ "integrity": "sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==",
"dev": true,
"dependencies": {
- "@storybook/channels": "7.6.7",
+ "@storybook/channels": "7.6.10",
"@types/babel__core": "^7.0.0",
"@types/express": "^4.7.0",
"file-system-cache": "2.3.0"
@@ -6403,18 +6419,18 @@
}
},
"node_modules/@storybook/codemod": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.6.7.tgz",
- "integrity": "sha512-an2pD5OHqO7CE8Wb7JxjrDnpQgeoxB22MyOs8PPJ9Rvclhpjg+Ku9RogoObYm//zR4g406l7Ec8mTltUkVCEOA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.6.10.tgz",
+ "integrity": "sha512-pzFR0nocBb94vN9QCJLC3C3dP734ZigqyPmd0ZCDj9Xce2ytfHK3v1lKB6TZWzKAZT8zztauECYxrbo4LVuagw==",
"dev": true,
"dependencies": {
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/types": "^7.23.0",
"@storybook/csf": "^0.1.2",
- "@storybook/csf-tools": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/csf-tools": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/cross-spawn": "^6.0.2",
"cross-spawn": "^7.0.3",
"globby": "^11.0.2",
@@ -6429,13 +6445,13 @@
}
},
"node_modules/@storybook/codemod/node_modules/@storybook/channels": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.7.tgz",
- "integrity": "sha512-u1hURhfQHHtZyRIDUENRCp+CRRm7IQfcjQaoWI06XCevQPuhVEtFUfXHjG+J74aA/JuuTLFUtqwNm1zGqbXTAQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.10.tgz",
+ "integrity": "sha512-ITCLhFuDBKgxetuKnWwYqMUWlU7zsfH3gEKZltTb+9/2OAWR7ez0iqU7H6bXP1ridm0DCKkt2UMWj2mmr9iQqg==",
"dev": true,
"dependencies": {
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/global": "^5.0.0",
"qs": "^6.10.0",
"telejson": "^7.2.0",
@@ -6447,9 +6463,9 @@
}
},
"node_modules/@storybook/codemod/node_modules/@storybook/client-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.7.tgz",
- "integrity": "sha512-A16zpWgsa0gSdXMR9P3bWVdC9u/1B1oG4H7Z1+JhNzgnL3CdyOYO0qFSiAtNBso4nOjIAJVb6/AoBzdRhmSVQg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.10.tgz",
+ "integrity": "sha512-U7bbpu21ntgePMz/mKM18qvCSWCUGCUlYru8mgVlXLCKqFqfTeP887+CsPEQf29aoE3cLgDrxqbRJ1wxX9kL9A==",
"dev": true,
"dependencies": {
"@storybook/global": "^5.0.0"
@@ -6460,9 +6476,9 @@
}
},
"node_modules/@storybook/codemod/node_modules/@storybook/core-events": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.7.tgz",
- "integrity": "sha512-KZ5d03c47pnr5/kY26pJtWq7WpmCPXLbgyjJZDSc+TTY153BdZksvlBXRHtqM1yj2UM6QsSyIuiJaADJNAbP2w==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.10.tgz",
+ "integrity": "sha512-yccDH67KoROrdZbRKwxgTswFMAco5nlCyxszCDASCLygGSV2Q2e+YuywrhchQl3U6joiWi3Ps1qWu56NeNafag==",
"dev": true,
"dependencies": {
"ts-dedent": "^2.0.0"
@@ -6473,9 +6489,9 @@
}
},
"node_modules/@storybook/codemod/node_modules/@storybook/csf-tools": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.7.tgz",
- "integrity": "sha512-hyRbUGa2Uxvz3U09BjcOfMNf/5IYgRum1L6XszqK2O8tK9DGte1r6hArCIAcqiEmFMC40d0kalPzqu6WMNn7sg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.10.tgz",
+ "integrity": "sha512-TnDNAwIALcN6SA4l00Cb67G02XMOrYU38bIpFJk5VMDX2dvgPjUtJNBuLmEbybGcOt7nPyyFIHzKcY5FCVGoWA==",
"dev": true,
"dependencies": {
"@babel/generator": "^7.23.0",
@@ -6483,7 +6499,7 @@
"@babel/traverse": "^7.23.2",
"@babel/types": "^7.23.0",
"@storybook/csf": "^0.1.2",
- "@storybook/types": "7.6.7",
+ "@storybook/types": "7.6.10",
"fs-extra": "^11.1.0",
"recast": "^0.23.1",
"ts-dedent": "^2.0.0"
@@ -6494,9 +6510,9 @@
}
},
"node_modules/@storybook/codemod/node_modules/@storybook/node-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.7.tgz",
- "integrity": "sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.10.tgz",
+ "integrity": "sha512-ZBuqrv4bjJzKXyfRGFkVIi+z6ekn6rOPoQao4KmsfLNQAUUsEdR8Baw/zMnnU417zw5dSEaZdpuwx75SCQAeOA==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -6504,12 +6520,12 @@
}
},
"node_modules/@storybook/codemod/node_modules/@storybook/types": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.7.tgz",
- "integrity": "sha512-VcGwrI4AkBENxkoAUJ+Z7SyMK73hpoY0TTtw2J7tc05/xdiXhkQTX15Qa12IBWIkoXCyNrtaU+q7KR8Tjzi+uw==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.10.tgz",
+ "integrity": "sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==",
"dev": true,
"dependencies": {
- "@storybook/channels": "7.6.7",
+ "@storybook/channels": "7.6.10",
"@types/babel__core": "^7.0.0",
"@types/express": "^4.7.0",
"file-system-cache": "2.3.0"
@@ -6870,26 +6886,26 @@
}
},
"node_modules/@storybook/core-server": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.6.7.tgz",
- "integrity": "sha512-elKRv/DNahNNkGcQY/FdOBrLPmZF0T0fwmAmbc4qqeAisjl+to9TO77zdo2ieaEHKyRwE3B3dOB4EXomdF4N/g==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.6.10.tgz",
+ "integrity": "sha512-2icnqJkn3vwq0eJPP0rNaHd7IOvxYf5q4lSVl2AWTxo/Ae19KhokI6j/2vvS2XQJMGQszwshlIwrZUNsj5p0yw==",
"dev": true,
"dependencies": {
"@aw-web-design/x-default-browser": "1.4.126",
"@discoveryjs/json-ext": "^0.5.3",
- "@storybook/builder-manager": "7.6.7",
- "@storybook/channels": "7.6.7",
- "@storybook/core-common": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/builder-manager": "7.6.10",
+ "@storybook/channels": "7.6.10",
+ "@storybook/core-common": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/csf": "^0.1.2",
- "@storybook/csf-tools": "7.6.7",
+ "@storybook/csf-tools": "7.6.10",
"@storybook/docs-mdx": "^0.1.0",
"@storybook/global": "^5.0.0",
- "@storybook/manager": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/preview-api": "7.6.7",
- "@storybook/telemetry": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/manager": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/preview-api": "7.6.10",
+ "@storybook/telemetry": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/detect-port": "^1.3.0",
"@types/node": "^18.0.0",
"@types/pretty-hrtime": "^1.0.0",
@@ -6923,13 +6939,13 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/channels": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.7.tgz",
- "integrity": "sha512-u1hURhfQHHtZyRIDUENRCp+CRRm7IQfcjQaoWI06XCevQPuhVEtFUfXHjG+J74aA/JuuTLFUtqwNm1zGqbXTAQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.10.tgz",
+ "integrity": "sha512-ITCLhFuDBKgxetuKnWwYqMUWlU7zsfH3gEKZltTb+9/2OAWR7ez0iqU7H6bXP1ridm0DCKkt2UMWj2mmr9iQqg==",
"dev": true,
"dependencies": {
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/global": "^5.0.0",
"qs": "^6.10.0",
"telejson": "^7.2.0",
@@ -6941,9 +6957,9 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/client-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.7.tgz",
- "integrity": "sha512-A16zpWgsa0gSdXMR9P3bWVdC9u/1B1oG4H7Z1+JhNzgnL3CdyOYO0qFSiAtNBso4nOjIAJVb6/AoBzdRhmSVQg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.10.tgz",
+ "integrity": "sha512-U7bbpu21ntgePMz/mKM18qvCSWCUGCUlYru8mgVlXLCKqFqfTeP887+CsPEQf29aoE3cLgDrxqbRJ1wxX9kL9A==",
"dev": true,
"dependencies": {
"@storybook/global": "^5.0.0"
@@ -6954,14 +6970,14 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/core-common": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.7.tgz",
- "integrity": "sha512-F1fJnauVSPQtAlpicbN/O4XW38Ai8kf/IoU0Hgm9gEwurIk6MF5hiVLsaTI/5GUbrepMl9d9J+iIL4lHAT8IyA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.10.tgz",
+ "integrity": "sha512-K3YWqjCKMnpvYsWNjOciwTH6zWbuuZzmOiipziZaVJ+sB1XYmH52Y3WGEm07TZI8AYK9DRgwA13dR/7W0nw72Q==",
"dev": true,
"dependencies": {
- "@storybook/core-events": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/core-events": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/find-cache-dir": "^3.2.1",
"@types/node": "^18.0.0",
"@types/node-fetch": "^2.6.4",
@@ -6989,9 +7005,9 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/core-events": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.7.tgz",
- "integrity": "sha512-KZ5d03c47pnr5/kY26pJtWq7WpmCPXLbgyjJZDSc+TTY153BdZksvlBXRHtqM1yj2UM6QsSyIuiJaADJNAbP2w==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.10.tgz",
+ "integrity": "sha512-yccDH67KoROrdZbRKwxgTswFMAco5nlCyxszCDASCLygGSV2Q2e+YuywrhchQl3U6joiWi3Ps1qWu56NeNafag==",
"dev": true,
"dependencies": {
"ts-dedent": "^2.0.0"
@@ -7002,9 +7018,9 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/csf-tools": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.7.tgz",
- "integrity": "sha512-hyRbUGa2Uxvz3U09BjcOfMNf/5IYgRum1L6XszqK2O8tK9DGte1r6hArCIAcqiEmFMC40d0kalPzqu6WMNn7sg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.10.tgz",
+ "integrity": "sha512-TnDNAwIALcN6SA4l00Cb67G02XMOrYU38bIpFJk5VMDX2dvgPjUtJNBuLmEbybGcOt7nPyyFIHzKcY5FCVGoWA==",
"dev": true,
"dependencies": {
"@babel/generator": "^7.23.0",
@@ -7012,7 +7028,7 @@
"@babel/traverse": "^7.23.2",
"@babel/types": "^7.23.0",
"@storybook/csf": "^0.1.2",
- "@storybook/types": "7.6.7",
+ "@storybook/types": "7.6.10",
"fs-extra": "^11.1.0",
"recast": "^0.23.1",
"ts-dedent": "^2.0.0"
@@ -7023,9 +7039,9 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/node-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.7.tgz",
- "integrity": "sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.10.tgz",
+ "integrity": "sha512-ZBuqrv4bjJzKXyfRGFkVIi+z6ekn6rOPoQao4KmsfLNQAUUsEdR8Baw/zMnnU417zw5dSEaZdpuwx75SCQAeOA==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -7033,17 +7049,17 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/preview-api": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz",
- "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.10.tgz",
+ "integrity": "sha512-5A3etoIwZCx05yuv3KSTv1wynN4SR4rrzaIs/CTBp3BC4q1RBL+Or/tClk0IJPXQMlx/4Y134GtNIBbkiDofpw==",
"dev": true,
"dependencies": {
- "@storybook/channels": "7.6.7",
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/channels": "7.6.10",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/csf": "^0.1.2",
"@storybook/global": "^5.0.0",
- "@storybook/types": "7.6.7",
+ "@storybook/types": "7.6.10",
"@types/qs": "^6.9.5",
"dequal": "^2.0.2",
"lodash": "^4.17.21",
@@ -7059,12 +7075,12 @@
}
},
"node_modules/@storybook/core-server/node_modules/@storybook/types": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.7.tgz",
- "integrity": "sha512-VcGwrI4AkBENxkoAUJ+Z7SyMK73hpoY0TTtw2J7tc05/xdiXhkQTX15Qa12IBWIkoXCyNrtaU+q7KR8Tjzi+uw==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.10.tgz",
+ "integrity": "sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==",
"dev": true,
"dependencies": {
- "@storybook/channels": "7.6.7",
+ "@storybook/channels": "7.6.10",
"@types/babel__core": "^7.0.0",
"@types/express": "^4.7.0",
"file-system-cache": "2.3.0"
@@ -7402,9 +7418,9 @@
"dev": true
},
"node_modules/@storybook/manager": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.7.tgz",
- "integrity": "sha512-ZCrkB2zEXogzdOcVzD242ZVm4tlHqrayotnI6iOn9uiun0Pgny0m2d7s9Zge6K2dTOO1vZiOHuA/Mr6nnIDjsA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.10.tgz",
+ "integrity": "sha512-Co3sLCbNYY6O4iH2ggmRDLCPWLj03JE5s/DOG8OVoXc6vBwTc/Qgiyrsxxp6BHQnPpM0mxL6aKAxE3UjsW/Nog==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -8183,14 +8199,14 @@
}
},
"node_modules/@storybook/telemetry": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.7.tgz",
- "integrity": "sha512-NHGzC/LGLXpK4AFbVj8ln5ab86ZiiNFvORQMn3+LNGwUt3ZdsHBzExN+WPZdw7OPtfk4ubUY89FXH2GedhTALw==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.10.tgz",
+ "integrity": "sha512-p3mOSUtIyy2tF1z6pQXxNh1JzYFcAm97nUgkwLzF07GfEdVAPM+ftRSLFbD93zVvLEkmLTlsTiiKaDvOY/lQWg==",
"dev": true,
"dependencies": {
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-common": "7.6.7",
- "@storybook/csf-tools": "7.6.7",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-common": "7.6.10",
+ "@storybook/csf-tools": "7.6.10",
"chalk": "^4.1.0",
"detect-package-manager": "^2.0.1",
"fetch-retry": "^5.0.2",
@@ -8203,13 +8219,13 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/channels": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.7.tgz",
- "integrity": "sha512-u1hURhfQHHtZyRIDUENRCp+CRRm7IQfcjQaoWI06XCevQPuhVEtFUfXHjG+J74aA/JuuTLFUtqwNm1zGqbXTAQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.10.tgz",
+ "integrity": "sha512-ITCLhFuDBKgxetuKnWwYqMUWlU7zsfH3gEKZltTb+9/2OAWR7ez0iqU7H6bXP1ridm0DCKkt2UMWj2mmr9iQqg==",
"dev": true,
"dependencies": {
- "@storybook/client-logger": "7.6.7",
- "@storybook/core-events": "7.6.7",
+ "@storybook/client-logger": "7.6.10",
+ "@storybook/core-events": "7.6.10",
"@storybook/global": "^5.0.0",
"qs": "^6.10.0",
"telejson": "^7.2.0",
@@ -8221,9 +8237,9 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/client-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.7.tgz",
- "integrity": "sha512-A16zpWgsa0gSdXMR9P3bWVdC9u/1B1oG4H7Z1+JhNzgnL3CdyOYO0qFSiAtNBso4nOjIAJVb6/AoBzdRhmSVQg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.10.tgz",
+ "integrity": "sha512-U7bbpu21ntgePMz/mKM18qvCSWCUGCUlYru8mgVlXLCKqFqfTeP887+CsPEQf29aoE3cLgDrxqbRJ1wxX9kL9A==",
"dev": true,
"dependencies": {
"@storybook/global": "^5.0.0"
@@ -8234,14 +8250,14 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/core-common": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.7.tgz",
- "integrity": "sha512-F1fJnauVSPQtAlpicbN/O4XW38Ai8kf/IoU0Hgm9gEwurIk6MF5hiVLsaTI/5GUbrepMl9d9J+iIL4lHAT8IyA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.10.tgz",
+ "integrity": "sha512-K3YWqjCKMnpvYsWNjOciwTH6zWbuuZzmOiipziZaVJ+sB1XYmH52Y3WGEm07TZI8AYK9DRgwA13dR/7W0nw72Q==",
"dev": true,
"dependencies": {
- "@storybook/core-events": "7.6.7",
- "@storybook/node-logger": "7.6.7",
- "@storybook/types": "7.6.7",
+ "@storybook/core-events": "7.6.10",
+ "@storybook/node-logger": "7.6.10",
+ "@storybook/types": "7.6.10",
"@types/find-cache-dir": "^3.2.1",
"@types/node": "^18.0.0",
"@types/node-fetch": "^2.6.4",
@@ -8269,9 +8285,9 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/core-events": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.7.tgz",
- "integrity": "sha512-KZ5d03c47pnr5/kY26pJtWq7WpmCPXLbgyjJZDSc+TTY153BdZksvlBXRHtqM1yj2UM6QsSyIuiJaADJNAbP2w==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.10.tgz",
+ "integrity": "sha512-yccDH67KoROrdZbRKwxgTswFMAco5nlCyxszCDASCLygGSV2Q2e+YuywrhchQl3U6joiWi3Ps1qWu56NeNafag==",
"dev": true,
"dependencies": {
"ts-dedent": "^2.0.0"
@@ -8282,9 +8298,9 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/csf-tools": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.7.tgz",
- "integrity": "sha512-hyRbUGa2Uxvz3U09BjcOfMNf/5IYgRum1L6XszqK2O8tK9DGte1r6hArCIAcqiEmFMC40d0kalPzqu6WMNn7sg==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.10.tgz",
+ "integrity": "sha512-TnDNAwIALcN6SA4l00Cb67G02XMOrYU38bIpFJk5VMDX2dvgPjUtJNBuLmEbybGcOt7nPyyFIHzKcY5FCVGoWA==",
"dev": true,
"dependencies": {
"@babel/generator": "^7.23.0",
@@ -8292,7 +8308,7 @@
"@babel/traverse": "^7.23.2",
"@babel/types": "^7.23.0",
"@storybook/csf": "^0.1.2",
- "@storybook/types": "7.6.7",
+ "@storybook/types": "7.6.10",
"fs-extra": "^11.1.0",
"recast": "^0.23.1",
"ts-dedent": "^2.0.0"
@@ -8303,9 +8319,9 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/node-logger": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.7.tgz",
- "integrity": "sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.10.tgz",
+ "integrity": "sha512-ZBuqrv4bjJzKXyfRGFkVIi+z6ekn6rOPoQao4KmsfLNQAUUsEdR8Baw/zMnnU417zw5dSEaZdpuwx75SCQAeOA==",
"dev": true,
"funding": {
"type": "opencollective",
@@ -8313,12 +8329,12 @@
}
},
"node_modules/@storybook/telemetry/node_modules/@storybook/types": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.7.tgz",
- "integrity": "sha512-VcGwrI4AkBENxkoAUJ+Z7SyMK73hpoY0TTtw2J7tc05/xdiXhkQTX15Qa12IBWIkoXCyNrtaU+q7KR8Tjzi+uw==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.10.tgz",
+ "integrity": "sha512-hcS2HloJblaMpCAj2axgGV+53kgSRYPT0a1PG1IHsZaYQILfHSMmBqM8XzXXYTsgf9250kz3dqFX1l0n3EqMlQ==",
"dev": true,
"dependencies": {
- "@storybook/channels": "7.6.7",
+ "@storybook/channels": "7.6.10",
"@types/babel__core": "^7.0.0",
"@types/express": "^4.7.0",
"file-system-cache": "2.3.0"
@@ -9658,9 +9674,9 @@
}
},
"node_modules/@types/react-dom": {
- "version": "18.2.17",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz",
- "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==",
+ "version": "18.2.18",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz",
+ "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==",
"dev": true,
"dependencies": {
"@types/react": "*"
@@ -9768,9 +9784,9 @@
}
},
"node_modules/@types/stylis": {
- "version": "4.2.4",
- "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.4.tgz",
- "integrity": "sha512-36ZrGJ8fgtBr6nwNnuJ9jXIj+bn/pF6UoqmrQT7+Y99+tFFeHHsoR54+194dHdyhPjgbeoNz3Qru0oRt0l6ASQ=="
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw=="
},
"node_modules/@types/tar-stream": {
"version": "3.1.3",
@@ -13849,7 +13865,8 @@
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
- "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "dev": true
},
"node_modules/d": {
"version": "1.0.1",
@@ -14676,9 +14693,9 @@
}
},
"node_modules/defu": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.3.tgz",
- "integrity": "sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==",
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
+ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
"dev": true
},
"node_modules/del": {
@@ -15648,6 +15665,21 @@
"ms": "^2.1.1"
}
},
+ "node_modules/eslint-plugin-deprecation": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-deprecation/-/eslint-plugin-deprecation-2.0.0.tgz",
+ "integrity": "sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/utils": "^6.0.0",
+ "tslib": "^2.3.1",
+ "tsutils": "^3.21.0"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0",
+ "typescript": "^4.2.4 || ^5.0.0"
+ }
+ },
"node_modules/eslint-plugin-escompat": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-escompat/-/eslint-plugin-escompat-3.4.0.tgz",
@@ -17447,9 +17479,9 @@
"dev": true
},
"node_modules/flow-parser": {
- "version": "0.225.1",
- "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.225.1.tgz",
- "integrity": "sha512-50fjR6zbLQcpq5IFNkheUSY/AFPxVeeLiBM5B3NQBSKId2G0cUuExOlDDOguxc49dl9lnh8hI1xcYlPJWNp4KQ==",
+ "version": "0.227.0",
+ "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.227.0.tgz",
+ "integrity": "sha512-nOygtGKcX/siZK/lFzpfdHEfOkfGcTW7rNroR1Zsz6T/JxSahPALXVt5qVHq/fgvMJuv096BTKbgxN3PzVBaDA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
@@ -24377,13 +24409,13 @@
}
},
"node_modules/markdownlint": {
- "version": "0.32.1",
- "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.32.1.tgz",
- "integrity": "sha512-3sx9xpi4xlHlokGyHO9k0g3gJbNY4DI6oNEeEYq5gQ4W7UkiJ90VDAnuDl2U+yyXOUa6BX+0gf69ZlTUGIBp6A==",
+ "version": "0.33.0",
+ "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.33.0.tgz",
+ "integrity": "sha512-4lbtT14A3m0LPX1WS/3d1m7Blg+ZwiLq36WvjQqFGsX3Gik99NV+VXp/PW3n+Q62xyPdbvGOCfjPqjW+/SKMig==",
"dev": true,
"dependencies": {
- "markdown-it": "13.0.2",
- "markdownlint-micromark": "0.1.7"
+ "markdown-it": "14.0.0",
+ "markdownlint-micromark": "0.1.8"
},
"engines": {
"node": ">=18"
@@ -24393,22 +24425,20 @@
}
},
"node_modules/markdownlint-cli2": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.11.0.tgz",
- "integrity": "sha512-RmFpr+My5in8KT+H/A6ozKIVYVzZtL5t9c8DYdv0YJdljl385z44CcCVBrclpHxCGMY2tr0hZ/ca+meGGvgdnQ==",
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.12.1.tgz",
+ "integrity": "sha512-RcK+l5FjJEyrU3REhrThiEUXNK89dLYNJCYbvOUKypxqIGfkcgpz8g08EKqhrmUbYfYoLC5nEYQy53NhJSEtfQ==",
"dev": true,
"dependencies": {
"globby": "14.0.0",
- "markdownlint": "0.32.1",
+ "jsonc-parser": "3.2.0",
+ "markdownlint": "0.33.0",
"markdownlint-cli2-formatter-default": "0.0.4",
"micromatch": "4.0.5",
- "strip-json-comments": "5.0.1",
"yaml": "2.3.4"
},
"bin": {
- "markdownlint-cli2": "markdownlint-cli2.js",
- "markdownlint-cli2-config": "markdownlint-cli2-config.js",
- "markdownlint-cli2-fix": "markdownlint-cli2-fix.js"
+ "markdownlint-cli2": "markdownlint-cli2.js"
},
"engines": {
"node": ">=18"
@@ -24498,64 +24528,56 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/markdownlint-cli2/node_modules/strip-json-comments": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz",
- "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==",
- "dev": true,
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/markdownlint-micromark": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz",
- "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==",
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.8.tgz",
+ "integrity": "sha512-1ouYkMRo9/6gou9gObuMDnvZM8jC/ly3QCFQyoSPCS2XV1ZClU0xpKbL1Ar3bWWRT1RnBZkWUEiNKrI2CwiBQA==",
"dev": true,
"engines": {
"node": ">=16"
- }
- },
- "node_modules/markdownlint/node_modules/entities": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
- "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
- "dev": true,
- "engines": {
- "node": ">=0.12"
},
"funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
+ "url": "https://github.com/sponsors/DavidAnson"
}
},
"node_modules/markdownlint/node_modules/linkify-it": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
- "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"dev": true,
"dependencies": {
- "uc.micro": "^1.0.1"
+ "uc.micro": "^2.0.0"
}
},
"node_modules/markdownlint/node_modules/markdown-it": {
- "version": "13.0.2",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz",
- "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.0.0.tgz",
+ "integrity": "sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1",
- "entities": "~3.0.1",
- "linkify-it": "^4.0.1",
- "mdurl": "^1.0.1",
- "uc.micro": "^1.0.5"
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.0.0"
},
"bin": {
- "markdown-it": "bin/markdown-it.js"
+ "markdown-it": "bin/markdown-it.mjs"
}
},
+ "node_modules/markdownlint/node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "dev": true
+ },
+ "node_modules/markdownlint/node_modules/uc.micro": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.0.0.tgz",
+ "integrity": "sha512-DffL94LsNOccVn4hyfRe5rdKa273swqeA5DJpMOeFmEn1wCDc7nAbbB0gXlgBCL7TNzeTv6G7XVWzan7iJtfig==",
+ "dev": true
+ },
"node_modules/matchdep": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
@@ -25563,14 +25585,14 @@
"dev": true
},
"node_modules/nypm": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.4.tgz",
- "integrity": "sha512-1JLkp/zHBrkS3pZ692IqOaIKSYHmQXgqfELk6YTOfVBnwealAmPA1q2kKK7PHJAHSMBozerThEFZXP3G6o7Ukg==",
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.6.tgz",
+ "integrity": "sha512-2CATJh3pd6CyNfU5VZM7qSwFu0ieyabkEdnogE30Obn1czrmOYiZ8DOZLe1yBdLKWoyD3Mcy2maUs+0MR3yVjQ==",
"dev": true,
"dependencies": {
"citty": "^0.1.5",
"execa": "^8.0.1",
- "pathe": "^1.1.1",
+ "pathe": "^1.1.2",
"ufo": "^1.3.2"
},
"bin": {
@@ -26712,9 +26734,9 @@
}
},
"node_modules/pathe": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
- "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
"dev": true
},
"node_modules/peek-stream": {
@@ -26822,6 +26844,50 @@
"node": ">=10"
}
},
+ "node_modules/playwright": {
+ "version": "1.40.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz",
+ "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==",
+ "dev": true,
+ "dependencies": {
+ "playwright-core": "1.40.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.40.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz",
+ "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==",
+ "dev": true,
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/playwright/node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/plugin-error": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz",
@@ -26871,6 +26937,7 @@
"version": "8.4.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -26975,6 +27042,7 @@
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "dev": true,
"funding": [
{
"type": "github",
@@ -27025,9 +27093,9 @@
}
},
"node_modules/prettier": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
- "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz",
+ "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
@@ -27223,6 +27291,15 @@
"node": ">=6"
}
},
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/puppeteer-core": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-2.1.1.tgz",
@@ -29019,18 +29096,6 @@
"simple-concat": "^1.0.0"
}
},
- "node_modules/simple-update-notifier": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
- "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
- "dev": true,
- "dependencies": {
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -29442,12 +29507,12 @@
"dev": true
},
"node_modules/storybook": {
- "version": "7.6.7",
- "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.6.7.tgz",
- "integrity": "sha512-1Cd895dqYIT5MOUOCDlD73OTWoJubLq/sWC7AMzkMrLu76yD4Cu6f+wv1HDrRAheRaCaeT3yhYEhsMB6qHIcaA==",
+ "version": "7.6.10",
+ "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.6.10.tgz",
+ "integrity": "sha512-ypFeGhQTUBBfqSUVZYh7wS5ghn3O2wILCiQc4459SeUpvUn+skcqw/TlrwGSoF5EWjDA7gtRrWDxO3mnlPt5Cw==",
"dev": true,
"dependencies": {
- "@storybook/cli": "7.6.7"
+ "@storybook/cli": "7.6.10"
},
"bin": {
"sb": "index.js",
@@ -29767,19 +29832,19 @@
}
},
"node_modules/styled-components": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.1.tgz",
- "integrity": "sha512-cpZZP5RrKRIClBW5Eby4JM1wElLVP4NQrJbJ0h10TidTyJf4SIIwa3zLXOoPb4gJi8MsJ8mjq5mu2IrEhZIAcQ==",
+ "version": "6.1.8",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz",
+ "integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==",
"dependencies": {
- "@emotion/is-prop-valid": "^1.2.1",
- "@emotion/unitless": "^0.8.0",
- "@types/stylis": "^4.0.2",
- "css-to-react-native": "^3.2.0",
- "csstype": "^3.1.2",
- "postcss": "^8.4.31",
- "shallowequal": "^1.1.0",
- "stylis": "^4.3.0",
- "tslib": "^2.5.0"
+ "@emotion/is-prop-valid": "1.2.1",
+ "@emotion/unitless": "0.8.0",
+ "@types/stylis": "4.2.0",
+ "css-to-react-native": "3.2.0",
+ "csstype": "3.1.2",
+ "postcss": "8.4.31",
+ "shallowequal": "1.1.0",
+ "stylis": "4.3.1",
+ "tslib": "2.5.0"
},
"engines": {
"node": ">= 16"
@@ -29793,10 +29858,64 @@
"react-dom": ">= 16.8.0"
}
},
+ "node_modules/styled-components/node_modules/csstype": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+ "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+ },
+ "node_modules/styled-components/node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/styled-components/node_modules/postcss": {
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/styled-components/node_modules/tslib": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+ },
"node_modules/stylis": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz",
- "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ=="
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz",
+ "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ=="
},
"node_modules/supports-color": {
"version": "5.5.0",
@@ -32701,9 +32820,9 @@
}
},
"node_modules/zip-a-folder": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/zip-a-folder/-/zip-a-folder-3.1.5.tgz",
- "integrity": "sha512-w7ZOjJS17MYqdjVEFiqa537H/hxVGcwxnmCcmOaUXDoezttVrWkbSob7nit4lqUqha+Q0pOFTCVsBttBx6hs5A==",
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/zip-a-folder/-/zip-a-folder-3.1.6.tgz",
+ "integrity": "sha512-u+qRL0sSsq2T2mDFcDzdgCSVO8sChsJ4swd2aZlzyoIoNwyVL7HBHPKDQVq1t0utd8nPXzCq44gAKzXAhbvpXA==",
"dependencies": {
"archiver": "^6.0.1",
"glob": "^10.3.10",
diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json
index 3df7cb0e2..73fa13147 100644
--- a/extensions/ql-vscode/package.json
+++ b/extensions/ql-vscode/package.json
@@ -1952,7 +1952,7 @@
"source-map": "^0.7.4",
"source-map-support": "^0.5.21",
"stream-json": "^1.7.3",
- "styled-components": "^6.0.2",
+ "styled-components": "^6.1.8",
"tmp": "^0.2.1",
"tmp-promise": "^3.0.2",
"tree-kill": "^1.2.2",
@@ -1960,7 +1960,7 @@
"vscode-jsonrpc": "^8.0.2",
"vscode-languageclient": "^8.0.2",
"yauzl": "^2.10.0",
- "zip-a-folder": "^3.1.3"
+ "zip-a-folder": "^3.1.6"
},
"devDependencies": {
"@babel/core": "^7.18.13",
@@ -1971,6 +1971,7 @@
"@faker-js/faker": "^8.0.2",
"@github/markdownlint-github": "^0.6.0",
"@octokit/plugin-throttling": "^8.0.0",
+ "@playwright/test": "^1.40.1",
"@storybook/addon-a11y": "^7.6.9",
"@storybook/addon-actions": "^7.1.0",
"@storybook/addon-essentials": "^7.1.0",
@@ -1999,7 +2000,7 @@
"@types/node": "18.15.*",
"@types/node-fetch": "^2.5.2",
"@types/react": "^18.0.28",
- "@types/react-dom": "^18.0.11",
+ "@types/react-dom": "^18.2.18",
"@types/sarif": "^2.1.2",
"@types/semver": "^7.2.0",
"@types/stream-json": "^1.7.1",
@@ -2023,6 +2024,7 @@
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.1",
+ "eslint-plugin-deprecation": "^2.0.0",
"eslint-plugin-etc": "^2.0.2",
"eslint-plugin-github": "^4.4.1",
"eslint-plugin-import": "^2.29.1",
@@ -2042,13 +2044,13 @@
"jest-environment-jsdom": "^29.0.3",
"jest-runner-vscode": "^3.0.1",
"lint-staged": "^15.0.2",
- "markdownlint-cli2": "^0.11.0",
+ "markdownlint-cli2": "^0.12.1",
"markdownlint-cli2-formatter-pretty": "^0.0.5",
"mini-css-extract-plugin": "^2.6.1",
"npm-run-all": "^4.1.5",
"patch-package": "^8.0.0",
- "prettier": "^3.0.0",
- "storybook": "^7.6.7",
+ "prettier": "^3.2.4",
+ "storybook": "^7.6.10",
"tar-stream": "^3.0.0",
"through2": "^4.0.2",
"ts-jest": "^29.0.1",
diff --git a/extensions/ql-vscode/scripts/find-deadcode.ts b/extensions/ql-vscode/scripts/find-deadcode.ts
index 12e3fb03e..9e21286b4 100644
--- a/extensions/ql-vscode/scripts/find-deadcode.ts
+++ b/extensions/ql-vscode/scripts/find-deadcode.ts
@@ -14,7 +14,8 @@ function ignoreFile(file: string): boolean {
) ||
basename(file) === "jest.config.ts" ||
basename(file) === "index.tsx" ||
- basename(file) === "index.ts"
+ basename(file) === "index.ts" ||
+ basename(file) === "playwright.config.ts"
);
}
diff --git a/extensions/ql-vscode/scripts/util/vscode-versions.ts b/extensions/ql-vscode/scripts/util/vscode-versions.ts
index d18c247f6..ce7853620 100644
--- a/extensions/ql-vscode/scripts/util/vscode-versions.ts
+++ b/extensions/ql-vscode/scripts/util/vscode-versions.ts
@@ -45,8 +45,9 @@ export async function getVersionInformation(
vscodeVersion: string,
): Promise {
const vsCodePackageJson = await getVsCodePackageJson(vscodeVersion);
- const electronVersion = minVersion(vsCodePackageJson.devDependencies.electron)
- ?.version;
+ const electronVersion = minVersion(
+ vsCodePackageJson.devDependencies.electron,
+ )?.version;
if (!electronVersion) {
throw new Error("Could not find Electron version");
}
diff --git a/extensions/ql-vscode/src/codeql-cli/cli.ts b/extensions/ql-vscode/src/codeql-cli/cli.ts
index 064a013fe..9d963d820 100644
--- a/extensions/ql-vscode/src/codeql-cli/cli.ts
+++ b/extensions/ql-vscode/src/codeql-cli/cli.ts
@@ -1739,6 +1739,15 @@ export class CliVersionConstraint {
*/
public static CLI_VERSION_WITH_TRIM_CACHE = new SemVer("2.15.1");
+ public static CLI_VERSION_WITHOUT_MRVA_EXTENSIBLE_PREDICATE_HACK = new SemVer(
+ "2.16.1",
+ );
+
+ /**
+ * CLI version where there is support for multiple queries on the pack create command.
+ */
+ public static CLI_VERSION_WITH_MULTI_QUERY_PACK_CREATE = new SemVer("2.16.1");
+
constructor(private readonly cli: CodeQLCliServer) {
/**/
}
@@ -1781,6 +1790,19 @@ export class CliVersionConstraint {
);
}
+ async preservesExtensiblePredicatesInMrvaPack() {
+ // Negated, because we _stopped_ preserving these in 2.16.1.
+ return !(await this.isVersionAtLeast(
+ CliVersionConstraint.CLI_VERSION_WITHOUT_MRVA_EXTENSIBLE_PREDICATE_HACK,
+ ));
+ }
+
+ async supportsPackCreateWithMultipleQueries() {
+ return this.isVersionAtLeast(
+ CliVersionConstraint.CLI_VERSION_WITH_MULTI_QUERY_PACK_CREATE,
+ );
+ }
+
async supportsMrvaPackCreate(): Promise {
return (await this.cli.getFeatures()).mrvaPackCreate === true;
}
diff --git a/extensions/ql-vscode/src/common/ql.ts b/extensions/ql-vscode/src/common/ql.ts
index 6bb08d674..691a08dbc 100644
--- a/extensions/ql-vscode/src/common/ql.ts
+++ b/extensions/ql-vscode/src/common/ql.ts
@@ -1,4 +1,4 @@
-import { join } from "path";
+import { dirname, join, parse } from "path";
import { pathExists } from "fs-extra";
export const QLPACK_FILENAMES = ["qlpack.yml", "codeql-pack.yml"];
@@ -8,7 +8,13 @@ export const QLPACK_LOCK_FILENAMES = [
];
export const FALLBACK_QLPACK_FILENAME = QLPACK_FILENAMES[0];
-export async function getQlPackPath(
+/**
+ * Gets the path to the QL pack file (a qlpack.yml or
+ * codeql-pack.yml).
+ * @param packRoot The root of the pack.
+ * @returns The path to the qlpack file, or undefined if it doesn't exist.
+ */
+export async function getQlPackFilePath(
packRoot: string,
): Promise {
for (const filename of QLPACK_FILENAMES) {
@@ -21,3 +27,28 @@ export async function getQlPackPath(
return undefined;
}
+
+/**
+ * Recursively find the directory containing qlpack.yml or codeql-pack.yml. If
+ * no such directory is found, the directory containing the query file is returned.
+ * @param queryFile The query file to start from.
+ * @returns The path to the pack root.
+ */
+export async function findPackRoot(queryFile: string): Promise {
+ let dir = dirname(queryFile);
+ while (!(await getQlPackFilePath(dir))) {
+ dir = dirname(dir);
+ if (isFileSystemRoot(dir)) {
+ // there is no qlpack.yml or codeql-pack.yml in this directory or any parent directory.
+ // just use the query file's directory as the pack root.
+ return dirname(queryFile);
+ }
+ }
+
+ return dir;
+}
+
+function isFileSystemRoot(dir: string): boolean {
+ const pathObj = parse(dir);
+ return pathObj.root === dir && pathObj.base === "";
+}
diff --git a/extensions/ql-vscode/src/common/readonly.ts b/extensions/ql-vscode/src/common/readonly.ts
index d6bf75098..19a4ad963 100644
--- a/extensions/ql-vscode/src/common/readonly.ts
+++ b/extensions/ql-vscode/src/common/readonly.ts
@@ -1,11 +1,12 @@
-export type DeepReadonly = T extends Array
- ? DeepReadonlyArray
- : // eslint-disable-next-line @typescript-eslint/ban-types
- T extends Function
- ? T
- : T extends object
- ? DeepReadonlyObject
- : T;
+export type DeepReadonly =
+ T extends Array
+ ? DeepReadonlyArray
+ : // eslint-disable-next-line @typescript-eslint/ban-types
+ T extends Function
+ ? T
+ : T extends object
+ ? DeepReadonlyObject
+ : T;
interface DeepReadonlyArray extends ReadonlyArray> {}
diff --git a/extensions/ql-vscode/src/config.ts b/extensions/ql-vscode/src/config.ts
index 095b53d96..faa71f864 100644
--- a/extensions/ql-vscode/src/config.ts
+++ b/extensions/ql-vscode/src/config.ts
@@ -716,12 +716,17 @@ const LLM_GENERATION_DEV_ENDPOINT = new Setting(
);
const EXTENSIONS_DIRECTORY = new Setting("extensionsDirectory", MODEL_SETTING);
const ENABLE_RUBY = new Setting("enableRuby", MODEL_SETTING);
+const ENABLE_ACCESS_PATH_SUGGESTIONS = new Setting(
+ "enableAccessPathSuggestions",
+ MODEL_SETTING,
+);
export interface ModelConfig {
flowGeneration: boolean;
llmGeneration: boolean;
getExtensionsDirectory(languageId: string): string | undefined;
enableRuby: boolean;
+ enableAccessPathSuggestions: boolean;
}
export class ModelConfigListener extends ConfigListener implements ModelConfig {
@@ -762,6 +767,10 @@ export class ModelConfigListener extends ConfigListener implements ModelConfig {
public get enableRuby(): boolean {
return !!ENABLE_RUBY.getValue();
}
+
+ public get enableAccessPathSuggestions(): boolean {
+ return !!ENABLE_ACCESS_PATH_SUGGESTIONS.getValue();
+ }
}
const GITHUB_DATABASE_SETTING = new Setting("githubDatabase", ROOT_SETTING);
diff --git a/extensions/ql-vscode/src/databases/local-databases-ui.ts b/extensions/ql-vscode/src/databases/local-databases-ui.ts
index 674c1ecd3..f1b802ed8 100644
--- a/extensions/ql-vscode/src/databases/local-databases-ui.ts
+++ b/extensions/ql-vscode/src/databases/local-databases-ui.ts
@@ -235,7 +235,7 @@ async function chooseDatabaseDir(byFolder: boolean): Promise {
return getFirst(chosen);
}
-interface DatabaseSelectionQuickPickItem extends QuickPickItem {
+export interface DatabaseSelectionQuickPickItem extends QuickPickItem {
databaseKind: "new" | "existing";
}
@@ -243,7 +243,7 @@ export interface DatabaseQuickPickItem extends QuickPickItem {
databaseItem: DatabaseItem;
}
-interface DatabaseImportQuickPickItems extends QuickPickItem {
+export interface DatabaseImportQuickPickItems extends QuickPickItem {
importType: "URL" | "github" | "archive" | "folder";
}
diff --git a/extensions/ql-vscode/src/databases/qlpack.ts b/extensions/ql-vscode/src/databases/qlpack.ts
index db2b77e6e..fc8260656 100644
--- a/extensions/ql-vscode/src/databases/qlpack.ts
+++ b/extensions/ql-vscode/src/databases/qlpack.ts
@@ -3,7 +3,7 @@ import { glob } from "glob";
import { basename } from "path";
import { load } from "js-yaml";
import { readFile } from "fs-extra";
-import { getQlPackPath } from "../common/ql";
+import { getQlPackFilePath } from "../common/ql";
import type { CodeQLCliServer, QlpacksInfo } from "../codeql-cli/cli";
import { extLogger } from "../common/logging/vscode";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
@@ -31,7 +31,7 @@ async function findDbschemePack(
): Promise<{ name: string; isLibraryPack: boolean }> {
for (const { packDir, packName } of packs) {
if (packDir !== undefined) {
- const qlpackPath = await getQlPackPath(packDir);
+ const qlpackPath = await getQlPackFilePath(packDir);
if (qlpackPath !== undefined) {
const qlpack = load(await readFile(qlpackPath, "utf8")) as {
diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts
index 5e409398d..8e4680139 100644
--- a/extensions/ql-vscode/src/extension.ts
+++ b/extensions/ql-vscode/src/extension.ts
@@ -215,8 +215,9 @@ function getCommands(
"codeQL.restartLegacyQueryServerOnConfigChange": restartQueryServer,
"codeQL.restartQueryServerOnExternalConfigChange": restartQueryServer,
"codeQL.copyVersion": async () => {
- const text = `CodeQL extension version: ${extension?.packageJSON
- .version} \nCodeQL CLI version: ${await getCliVersion()} \nPlatform: ${platform()} ${arch()}`;
+ const text = `CodeQL extension version: ${
+ extension?.packageJSON.version
+ } \nCodeQL CLI version: ${await getCliVersion()} \nPlatform: ${platform()} ${arch()}`;
await env.clipboard.writeText(text);
void showAndLogInformationMessage(extLogger, text);
},
diff --git a/extensions/ql-vscode/src/local-queries/quick-query.ts b/extensions/ql-vscode/src/local-queries/quick-query.ts
index 60d61765b..53ca5677e 100644
--- a/extensions/ql-vscode/src/local-queries/quick-query.ts
+++ b/extensions/ql-vscode/src/local-queries/quick-query.ts
@@ -11,7 +11,7 @@ import { getPrimaryDbscheme, getQlPackForDbscheme } from "../databases/qlpack";
import type { ProgressCallback } from "../common/vscode/progress";
import { UserCancellationException } from "../common/vscode/progress";
import { getErrorMessage } from "../common/helpers-pure";
-import { FALLBACK_QLPACK_FILENAME, getQlPackPath } from "../common/ql";
+import { FALLBACK_QLPACK_FILENAME, getQlPackFilePath } from "../common/ql";
import type { App } from "../common/app";
import type { ExtensionApp } from "../common/vscode/vscode-app";
@@ -119,7 +119,7 @@ export async function displayQuickQuery(
const dbscheme = await getPrimaryDbscheme(datasetFolder);
const qlpack = (await getQlPackForDbscheme(cliServer, dbscheme))
.dbschemePack;
- const qlPackFile = await getQlPackPath(queriesDir);
+ const qlPackFile = await getQlPackFilePath(queriesDir);
const qlFile = join(queriesDir, QUICK_QUERY_QUERY_NAME);
const shouldRewrite = await checkShouldRewrite(qlPackFile, qlpack);
diff --git a/extensions/ql-vscode/src/local-queries/skeleton-query-wizard.ts b/extensions/ql-vscode/src/local-queries/skeleton-query-wizard.ts
index e306f18ef..61a7de920 100644
--- a/extensions/ql-vscode/src/local-queries/skeleton-query-wizard.ts
+++ b/extensions/ql-vscode/src/local-queries/skeleton-query-wizard.ts
@@ -36,7 +36,7 @@ import { redactableError } from "../common/errors";
import type { App } from "../common/app";
import type { QueryTreeViewItem } from "../queries-panel/query-tree-view-item";
import { containsPath, pathsEqual } from "../common/files";
-import { getQlPackPath } from "../common/ql";
+import { getQlPackFilePath } from "../common/ql";
import { getQlPackLanguage } from "../common/qlpack-language";
type QueryLanguagesToDatabaseMap = Record;
@@ -111,7 +111,7 @@ export class SkeletonQueryWizard {
// Try to detect if there is already a qlpack in this location. We will assume that
// the user hasn't changed the language of the qlpack.
- const qlPackPath = await getQlPackPath(this.qlPackStoragePath);
+ const qlPackPath = await getQlPackFilePath(this.qlPackStoragePath);
// If we are creating or using a qlpack in the user's selected folder, we will also
// create the query in that folder
@@ -248,7 +248,7 @@ export class SkeletonQueryWizard {
const matchingQueryPackPath = matchingQueryPacks[0];
- const qlPackPath = await getQlPackPath(matchingQueryPackPath);
+ const qlPackPath = await getQlPackFilePath(matchingQueryPackPath);
if (!qlPackPath) {
return undefined;
}
diff --git a/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts b/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts
index b1f391951..9962164ef 100644
--- a/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts
+++ b/extensions/ql-vscode/src/model-editor/extension-pack-picker.ts
@@ -9,7 +9,7 @@ import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import type { ProgressCallback } from "../common/vscode/progress";
import { UserCancellationException } from "../common/vscode/progress";
import type { DatabaseItem } from "../databases/local-databases";
-import { getQlPackPath, QLPACK_FILENAMES } from "../common/ql";
+import { getQlPackFilePath, QLPACK_FILENAMES } from "../common/ql";
import { getErrorMessage } from "../common/helpers-pure";
import type { ExtensionPack } from "./shared/extension-pack";
import type { NotificationLogger } from "../common/logging";
@@ -208,7 +208,7 @@ async function readExtensionPack(
path: string,
language: string,
): Promise {
- const qlpackPath = await getQlPackPath(path);
+ const qlpackPath = await getQlPackFilePath(path);
if (!qlpackPath) {
throw new Error(
`Could not find any of ${QLPACK_FILENAMES.join(", ")} in ${path}`,
diff --git a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepos.stories.tsx b/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepos.stories.tsx
index 2139f95bc..7b8f08878 100644
--- a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepos.stories.tsx
+++ b/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepos.stories.tsx
@@ -1,6 +1,7 @@
import type { Meta, StoryFn } from "@storybook/react";
import { faker } from "@faker-js/faker";
+import { customAlphabet } from "nanoid";
import { VariantAnalysisContainer } from "../../view/variant-analysis/VariantAnalysisContainer";
import { VariantAnalysisAnalyzedRepos } from "../../view/variant-analysis/VariantAnalysisAnalyzedRepos";
@@ -125,11 +126,10 @@ Example.args = {
};
faker.seed(42);
-const uniqueStore = {};
const manyScannedRepos = Array.from({ length: 1000 }, (_, i) => {
const mockedScannedRepo = createMockScannedRepo();
-
+ const nanoid = customAlphabet("123456789");
return {
...mockedScannedRepo,
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
@@ -137,12 +137,8 @@ const manyScannedRepos = Array.from({ length: 1000 }, (_, i) => {
repository: {
...mockedScannedRepo.repository,
// We need to ensure the ID is unique for React keys
- id: faker.helpers.unique(faker.number.int, [], {
- store: uniqueStore,
- }),
- fullName: `octodemo/${faker.helpers.unique(faker.word.sample, [], {
- store: uniqueStore,
- })}`,
+ id: parseInt(nanoid()),
+ fullName: `octodemo/${nanoid()}`,
},
};
});
diff --git a/extensions/ql-vscode/src/variant-analysis/ql-pack-details.ts b/extensions/ql-vscode/src/variant-analysis/ql-pack-details.ts
new file mode 100644
index 000000000..d8d0d31c3
--- /dev/null
+++ b/extensions/ql-vscode/src/variant-analysis/ql-pack-details.ts
@@ -0,0 +1,20 @@
+import type { QueryLanguage } from "../common/query-language";
+
+/**
+ * Details about the original QL pack that is used for triggering
+ * a variant analysis.
+ */
+export interface QlPackDetails {
+ // The absolute paths of the query files.
+ queryFiles: string[];
+
+ // The absolute path to the QL pack that is used for triggering a variant analysis.
+ // If there is no query pack, this is the same as the directory of the query files.
+ qlPackRootPath: string;
+
+ // The absolute path to the QL pack file (a qlpack.yml or codeql-pack.yml) or undefined if
+ // it doesn't exist.
+ qlPackFilePath: string | undefined;
+
+ language: QueryLanguage;
+}
diff --git a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts
index 62ced7fe4..42139504b 100644
--- a/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts
+++ b/extensions/ql-vscode/src/variant-analysis/run-remote-query.ts
@@ -1,6 +1,6 @@
import type { CancellationToken } from "vscode";
import { Uri, window } from "vscode";
-import { relative, join, sep, dirname, parse, basename } from "path";
+import { join, sep, basename, relative } from "path";
import { dump, load } from "js-yaml";
import { copy, writeFile, readFile, mkdirp } from "fs-extra";
import type { DirectoryResult } from "tmp-promise";
@@ -29,27 +29,20 @@ import {
import type { Repository } from "./shared/repository";
import type { DbManager } from "../databases/db-manager";
import {
- getQlPackPath,
+ getQlPackFilePath,
FALLBACK_QLPACK_FILENAME,
QLPACK_FILENAMES,
QLPACK_LOCK_FILENAMES,
} from "../common/ql";
-import type { QueryLanguage } from "../common/query-language";
-import { tryGetQueryMetadata } from "../codeql-cli/query-metadata";
-import { askForLanguage, findLanguage } from "../codeql-cli/query-language";
import type { QlPackFile } from "../packaging/qlpack-file";
import { expandShortPaths } from "../common/short-paths";
+import type { QlPackDetails } from "./ql-pack-details";
/**
* Well-known names for the query pack used by the server.
*/
const QUERY_PACK_NAME = "codeql-remote/query";
-interface GeneratedQueryPack {
- base64Pack: string;
- language: string;
-}
-
/**
* Two possibilities:
* 1. There is no qlpack.yml (or codeql-pack.yml) in this directory. Assume this is a lone query and generate a synthetic qlpack for it.
@@ -59,45 +52,30 @@ interface GeneratedQueryPack {
*/
async function generateQueryPack(
cliServer: CodeQLCliServer,
- queryFile: string,
+ qlPackDetails: QlPackDetails,
tmpDir: RemoteQueryTempDir,
-): Promise {
- const originalPackRoot = await findPackRoot(queryFile);
- const packRelativePath = relative(originalPackRoot, queryFile);
+): Promise {
const workspaceFolders = getOnDiskWorkspaceFolders();
const extensionPacks = await getExtensionPacksToInject(
cliServer,
workspaceFolders,
);
- const mustSynthesizePack =
- (await getQlPackPath(originalPackRoot)) === undefined;
+ const mustSynthesizePack = qlPackDetails.qlPackFilePath === undefined;
const cliSupportsMrvaPackCreate =
await cliServer.cliConstraints.supportsMrvaPackCreate();
- const language: QueryLanguage | undefined = mustSynthesizePack
- ? await askForLanguage(cliServer) // open popup to ask for language if not already hardcoded
- : await findLanguage(cliServer, Uri.file(queryFile));
- if (!language) {
- throw new UserCancellationException("Could not determine language");
- }
-
- let queryPackDir: string;
+ let targetPackPath: string;
let needsInstall: boolean;
if (mustSynthesizePack) {
// This section applies whether or not the CLI supports MRVA pack creation directly.
- queryPackDir = tmpDir.queryPackDir;
+ targetPackPath = tmpDir.queryPackDir;
// Synthesize a query pack for the query.
// copy only the query file to the query pack directory
// and generate a synthetic query pack
- await createNewQueryPack(
- queryFile,
- queryPackDir,
- language,
- packRelativePath,
- );
+ await createNewQueryPack(qlPackDetails, targetPackPath);
// Clear the cliServer cache so that the previous qlpack text is purged from the CLI.
await cliServer.clearCache();
@@ -105,14 +83,8 @@ async function generateQueryPack(
needsInstall = true;
} else if (!cliSupportsMrvaPackCreate) {
// We need to copy the query pack to a temporary directory and then fix it up to work with MRVA.
- queryPackDir = tmpDir.queryPackDir;
- await copyExistingQueryPack(
- cliServer,
- originalPackRoot,
- queryFile,
- queryPackDir,
- packRelativePath,
- );
+ targetPackPath = tmpDir.queryPackDir;
+ await copyExistingQueryPack(cliServer, qlPackDetails, targetPackPath);
// We should already have all the dependencies available, but these older versions of the CLI
// have a bug where they will not search `--additional-packs` during validation in `codeql pack bundle`.
@@ -120,14 +92,14 @@ async function generateQueryPack(
needsInstall = true;
} else {
// The CLI supports creating a MRVA query pack directly from the source pack.
- queryPackDir = originalPackRoot;
+ targetPackPath = qlPackDetails.qlPackRootPath;
// We expect any dependencies to be available already.
needsInstall = false;
}
if (needsInstall) {
// Install the dependencies of the synthesized query pack.
- await cliServer.packInstall(queryPackDir, {
+ await cliServer.packInstall(targetPackPath, {
workspaceFolders,
});
@@ -137,10 +109,23 @@ async function generateQueryPack(
let precompilationOpts: string[];
if (cliSupportsMrvaPackCreate) {
+ if (
+ qlPackDetails.queryFiles.length > 1 &&
+ !(await cliServer.cliConstraints.supportsPackCreateWithMultipleQueries())
+ ) {
+ throw new Error(
+ `Installed CLI version does not allow creating a MRVA pack with multiple queries`,
+ );
+ }
+
+ const queryOpts = qlPackDetails.queryFiles.flatMap((q) => [
+ "--query",
+ join(targetPackPath, relative(qlPackDetails.qlPackRootPath, q)),
+ ]);
+
precompilationOpts = [
"--mrva",
- "--query",
- join(queryPackDir, packRelativePath),
+ ...queryOpts,
// We need to specify the extension packs as dependencies so that they are included in the MRVA pack.
// The version range doesn't matter, since they'll always be found by source lookup.
...extensionPacks.map((p) => `--extension-pack=${p}@*`),
@@ -149,7 +134,7 @@ async function generateQueryPack(
if (await cliServer.cliConstraints.usesGlobalCompilationCache()) {
precompilationOpts = ["--qlx"];
} else {
- const cache = join(originalPackRoot, ".cache");
+ const cache = join(qlPackDetails.qlPackRootPath, ".cache");
precompilationOpts = [
"--qlx",
"--no-default-compilation-cache",
@@ -158,60 +143,61 @@ async function generateQueryPack(
}
if (extensionPacks.length > 0) {
- await addExtensionPacksAsDependencies(queryPackDir, extensionPacks);
+ await addExtensionPacksAsDependencies(targetPackPath, extensionPacks);
}
}
const bundlePath = tmpDir.bundleFile;
void extLogger.log(
- `Compiling and bundling query pack from ${queryPackDir} to ${bundlePath}. (This may take a while.)`,
+ `Compiling and bundling query pack from ${targetPackPath} to ${bundlePath}. (This may take a while.)`,
);
await cliServer.packBundle(
- queryPackDir,
+ targetPackPath,
workspaceFolders,
bundlePath,
tmpDir.compiledPackDir,
precompilationOpts,
);
const base64Pack = (await readFile(bundlePath)).toString("base64");
- return {
- base64Pack,
- language,
- };
+ return base64Pack;
}
async function createNewQueryPack(
- queryFile: string,
- queryPackDir: string,
- language: string | undefined,
- packRelativePath: string,
+ qlPackDetails: QlPackDetails,
+ targetPackPath: string,
) {
- void extLogger.log(`Copying ${queryFile} to ${queryPackDir}`);
- const targetQueryFileName = join(queryPackDir, packRelativePath);
- await copy(queryFile, targetQueryFileName);
+ for (const queryFile of qlPackDetails.queryFiles) {
+ void extLogger.log(`Copying ${queryFile} to ${targetPackPath}`);
+ const relativeQueryPath = relative(qlPackDetails.qlPackRootPath, queryFile);
+ const targetQueryFileName = join(targetPackPath, relativeQueryPath);
+ await copy(queryFile, targetQueryFileName);
+ }
+
void extLogger.log("Generating synthetic query pack");
const syntheticQueryPack = {
name: QUERY_PACK_NAME,
version: "0.0.0",
dependencies: {
- [`codeql/${language}-all`]: "*",
+ [`codeql/${qlPackDetails.language}-all`]: "*",
},
- defaultSuite: generateDefaultSuite(packRelativePath),
+ defaultSuite: generateDefaultSuite(qlPackDetails),
};
+
await writeFile(
- join(queryPackDir, FALLBACK_QLPACK_FILENAME),
+ join(targetPackPath, FALLBACK_QLPACK_FILENAME),
dump(syntheticQueryPack),
);
}
async function copyExistingQueryPack(
cliServer: CodeQLCliServer,
- originalPackRoot: string,
- queryFile: string,
- queryPackDir: string,
- packRelativePath: string,
+ qlPackDetails: QlPackDetails,
+ targetPackPath: string,
) {
- const toCopy = await cliServer.packPacklist(originalPackRoot, false);
+ const toCopy = await cliServer.packPacklist(
+ qlPackDetails.qlPackRootPath,
+ false,
+ );
// Also include query files that contain extensible predicates. These query files are not
// needed for the query to run, but they are needed for the query pack to pass deep validation
@@ -219,19 +205,20 @@ async function copyExistingQueryPack(
if (
await cliServer.cliConstraints.supportsGenerateExtensiblePredicateMetadata()
) {
- const metadata =
- await cliServer.generateExtensiblePredicateMetadata(originalPackRoot);
+ const metadata = await cliServer.generateExtensiblePredicateMetadata(
+ qlPackDetails.qlPackRootPath,
+ );
metadata.extensible_predicates.forEach((predicate) => {
if (predicate.path.endsWith(".ql")) {
- toCopy.push(join(originalPackRoot, predicate.path));
+ toCopy.push(join(qlPackDetails.qlPackRootPath, predicate.path));
}
});
}
[
// also copy the lock file (either new name or old name) and the query file itself. These are not included in the packlist.
- ...QLPACK_LOCK_FILENAMES.map((f) => join(originalPackRoot, f)),
- queryFile,
+ ...QLPACK_LOCK_FILENAMES.map((f) => join(qlPackDetails.qlPackRootPath, f)),
+ ...qlPackDetails.queryFiles,
].forEach((absolutePath) => {
if (absolutePath) {
toCopy.push(absolutePath);
@@ -239,7 +226,7 @@ async function copyExistingQueryPack(
});
let copiedCount = 0;
- await copy(originalPackRoot, queryPackDir, {
+ await copy(qlPackDetails.qlPackRootPath, targetPackPath, {
filter: (file: string) =>
// copy file if it is in the packlist, or it is a parent directory of a file in the packlist
!!toCopy.find((f) => {
@@ -254,29 +241,9 @@ async function copyExistingQueryPack(
}),
});
- void extLogger.log(`Copied ${copiedCount} files to ${queryPackDir}`);
+ void extLogger.log(`Copied ${copiedCount} files to ${targetPackPath}`);
- await fixPackFile(queryPackDir, packRelativePath);
-}
-
-async function findPackRoot(queryFile: string): Promise {
- // recursively find the directory containing qlpack.yml or codeql-pack.yml
- let dir = dirname(queryFile);
- while (!(await getQlPackPath(dir))) {
- dir = dirname(dir);
- if (isFileSystemRoot(dir)) {
- // there is no qlpack.yml or codeql-pack.yml in this directory or any parent directory.
- // just use the query file's directory as the pack root.
- return dirname(queryFile);
- }
- }
-
- return dir;
-}
-
-function isFileSystemRoot(dir: string): boolean {
- const pathObj = parse(dir);
- return pathObj.root === dir && pathObj.base === "";
+ await fixPackFile(targetPackPath, qlPackDetails);
}
interface RemoteQueryTempDir {
@@ -319,35 +286,26 @@ interface PreparedRemoteQuery {
actionBranch: string;
base64Pack: string;
repoSelection: RepositorySelection;
- queryFile: string;
- queryMetadata: QueryMetadata | undefined;
controllerRepo: Repository;
queryStartTime: number;
- language: string;
}
export async function prepareRemoteQueryRun(
cliServer: CodeQLCliServer,
credentials: Credentials,
- uris: Uri[],
+ qlPackDetails: QlPackDetails,
progress: ProgressCallback,
token: CancellationToken,
dbManager: DbManager,
): Promise {
- if (uris.length !== 1) {
- // For now we only support a single file, but we're aiming
- // to support multiple files in the near future.
- throw Error("Exactly one query file must be selected.");
+ for (const queryFile of qlPackDetails.queryFiles) {
+ if (!queryFile.endsWith(".ql")) {
+ throw new UserCancellationException(
+ `Not a CodeQL query file: ${queryFile}`,
+ );
+ }
}
- const uri = uris[0];
-
- if (!uri.fsPath.endsWith(".ql")) {
- throw new UserCancellationException("Not a CodeQL query file.");
- }
-
- const queryFile = uri.fsPath;
-
progress({
maxStep: 4,
step: 1,
@@ -379,16 +337,14 @@ export async function prepareRemoteQueryRun(
const tempDir = await createRemoteQueriesTempDirectory();
- let pack: GeneratedQueryPack;
+ let base64Pack: string;
try {
- pack = await generateQueryPack(cliServer, queryFile, tempDir);
+ base64Pack = await generateQueryPack(cliServer, qlPackDetails, tempDir);
} finally {
await tempDir.remoteQueryDir.cleanup();
}
- const { base64Pack, language } = pack;
-
if (token.isCancellationRequested) {
throw new UserCancellationException("Cancelled");
}
@@ -401,17 +357,13 @@ export async function prepareRemoteQueryRun(
const actionBranch = getActionBranch();
const queryStartTime = Date.now();
- const queryMetadata = await tryGetQueryMetadata(cliServer, queryFile);
return {
actionBranch,
base64Pack,
repoSelection,
- queryFile,
- queryMetadata,
controllerRepo,
queryStartTime,
- language,
};
}
@@ -426,26 +378,26 @@ export async function prepareRemoteQueryRun(
* - Removes any `${workspace}` version references from the qlpack.yml or codeql-pack.yml file. Converts them
* to `*` versions.
*
- * @param queryPackDir The directory containing the query pack
- * @param packRelativePath The relative path to the query pack from the root of the query pack
+ * @param targetPackPath The path to the directory containing the target pack
+ * @param qlPackDetails The details of the original QL pack
*/
async function fixPackFile(
- queryPackDir: string,
- packRelativePath: string,
+ targetPackPath: string,
+ qlPackDetails: QlPackDetails,
): Promise {
- const packPath = await getQlPackPath(queryPackDir);
+ const packPath = await getQlPackFilePath(targetPackPath);
// This should not happen since we create the pack ourselves.
if (!packPath) {
throw new Error(
`Could not find ${QLPACK_FILENAMES.join(
" or ",
- )} file in '${queryPackDir}'`,
+ )} file in '${targetPackPath}'`,
);
}
const qlpack = load(await readFile(packPath, "utf8")) as QlPackFile;
- updateDefaultSuite(qlpack, packRelativePath);
+ updateDefaultSuite(qlpack, qlPackDetails);
removeWorkspaceRefs(qlpack);
await writeFile(packPath, dump(qlpack));
@@ -483,7 +435,7 @@ async function addExtensionPacksAsDependencies(
queryPackDir: string,
extensionPacks: string[],
): Promise {
- const qlpackFile = await getQlPackPath(queryPackDir);
+ const qlpackFile = await getQlPackFilePath(queryPackDir);
if (!qlpackFile) {
throw new Error(
`Could not find ${QLPACK_FILENAMES.join(
@@ -509,19 +461,23 @@ async function addExtensionPacksAsDependencies(
await writeFile(qlpackFile, dump(syntheticQueryPack));
}
-function updateDefaultSuite(qlpack: QlPackFile, packRelativePath: string) {
+function updateDefaultSuite(qlpack: QlPackFile, qlPackDetails: QlPackDetails) {
delete qlpack.defaultSuiteFile;
- qlpack.defaultSuite = generateDefaultSuite(packRelativePath);
+ qlpack.defaultSuite = generateDefaultSuite(qlPackDetails);
}
-function generateDefaultSuite(packRelativePath: string) {
+function generateDefaultSuite(qlPackDetails: QlPackDetails) {
+ const queries = qlPackDetails.queryFiles.map((query) => {
+ const relativePath = relative(qlPackDetails.qlPackRootPath, query);
+ return {
+ query: relativePath.replace(/\\/g, "/"),
+ };
+ });
return [
{
description: "Query suite for variant analysis",
},
- {
- query: packRelativePath.replace(/\\/g, "/"),
- },
+ ...queries,
];
}
diff --git a/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis-filter-sort.ts b/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis-filter-sort.ts
index 9d2d153bc..794439e13 100644
--- a/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis-filter-sort.ts
+++ b/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis-filter-sort.ts
@@ -146,8 +146,8 @@ export function filterAndSortRepositoriesWithResults<
filterSortState.repositoryIds.length > 0
) {
return repositories
- .filter(
- (repo) => filterSortState.repositoryIds?.includes(repo.repository.id),
+ .filter((repo) =>
+ filterSortState.repositoryIds?.includes(repo.repository.id),
)
.sort(compareWithResults(filterSortState));
}
diff --git a/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis.ts b/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis.ts
index 1c862b793..73347426f 100644
--- a/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis.ts
+++ b/extensions/ql-vscode/src/variant-analysis/shared/variant-analysis.ts
@@ -159,6 +159,7 @@ export interface VariantAnalysisSubmission {
// unclear what it will look like in the future.
export interface VariantAnalysisQueries {
language: QueryLanguage;
+ count: number;
}
export async function isVariantAnalysisComplete(
diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts
index b5452c59d..4cd52f26f 100644
--- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts
+++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-manager.ts
@@ -22,6 +22,7 @@ import { DisposableObject } from "../common/disposable-object";
import { VariantAnalysisMonitor } from "./variant-analysis-monitor";
import type {
VariantAnalysis,
+ VariantAnalysisQueries,
VariantAnalysisRepositoryTask,
VariantAnalysisScannedRepository,
VariantAnalysisScannedRepositoryResult,
@@ -87,7 +88,10 @@ import type { QueryTreeViewItem } from "../queries-panel/query-tree-view-item";
import { RequestError } from "@octokit/request-error";
import { handleRequestError } from "./custom-errors";
import { createMultiSelectionCommand } from "../common/vscode/selection-commands";
-import { askForLanguage } from "../codeql-cli/query-language";
+import { askForLanguage, findLanguage } from "../codeql-cli/query-language";
+import type { QlPackDetails } from "./ql-pack-details";
+import { findPackRoot, getQlPackFilePath } from "../common/ql";
+import { tryGetQueryMetadata } from "../codeql-cli/query-metadata";
const maxRetryCount = 3;
@@ -191,26 +195,22 @@ export class VariantAnalysisManager
throw new Error("Please select a .ql file to run as a variant analysis");
}
- await this.runVariantAnalysisCommand(fileUri);
+ await this.runVariantAnalysisCommand([fileUri]);
}
private async runVariantAnalysisFromContextEditor(uri: Uri) {
- await this.runVariantAnalysisCommand(uri);
+ await this.runVariantAnalysisCommand([uri]);
}
private async runVariantAnalysisFromExplorer(fileURIs: Uri[]): Promise {
- if (fileURIs.length !== 1) {
- throw new Error("Can only run a single query at a time");
- }
-
- return this.runVariantAnalysisCommand(fileURIs[0]);
+ return this.runVariantAnalysisCommand(fileURIs);
}
private async runVariantAnalysisFromQueriesPanel(
queryTreeViewItem: QueryTreeViewItem,
): Promise {
if (queryTreeViewItem.path !== undefined) {
- await this.runVariantAnalysisCommand(Uri.file(queryTreeViewItem.path));
+ await this.runVariantAnalysisCommand([Uri.file(queryTreeViewItem.path)]);
}
}
@@ -223,6 +223,9 @@ export class VariantAnalysisManager
});
const language = await askForLanguage(this.cliServer);
+ if (!language) {
+ return;
+ }
progress({
maxStep: 8,
@@ -263,8 +266,18 @@ export class VariantAnalysisManager
return;
}
+ const qlPackFilePath = await getQlPackFilePath(packDir);
+
+ // Build up details to pass to the functions that run the variant analysis.
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: problemQueries,
+ qlPackRootPath: packDir,
+ qlPackFilePath,
+ language,
+ };
+
await this.runVariantAnalysis(
- problemQueries.map((q) => Uri.file(q)),
+ qlPackDetails,
(p) =>
progress({
...p,
@@ -294,10 +307,43 @@ export class VariantAnalysisManager
return problemQueries;
}
- private async runVariantAnalysisCommand(uri: Uri): Promise {
+ private async runVariantAnalysisCommand(queryFiles: Uri[]): Promise {
+ if (queryFiles.length === 0) {
+ throw new Error("Please select a .ql file to run as a variant analysis");
+ }
+
+ const qlPackRootPath = await findPackRoot(queryFiles[0].fsPath);
+ const qlPackFilePath = await getQlPackFilePath(qlPackRootPath);
+
+ // Make sure that all remaining queries have the same pack root
+ for (let i = 1; i < queryFiles.length; i++) {
+ const packRoot = await findPackRoot(queryFiles[i].fsPath);
+ if (packRoot !== qlPackRootPath) {
+ throw new Error(
+ "Please select queries that all belong to the same query pack",
+ );
+ }
+ }
+
+ // Open popup to ask for language if not already hardcoded
+ const language = qlPackFilePath
+ ? await findLanguage(this.cliServer, queryFiles[0])
+ : await askForLanguage(this.cliServer);
+
+ if (!language) {
+ throw new UserCancellationException("Could not determine query language");
+ }
+
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: queryFiles.map((uri) => uri.fsPath),
+ qlPackRootPath,
+ qlPackFilePath,
+ language,
+ };
+
return withProgress(
async (progress, token) => {
- await this.runVariantAnalysis([uri], progress, token);
+ await this.runVariantAnalysis(qlPackDetails, progress, token);
},
{
title: "Run Variant Analysis",
@@ -307,7 +353,7 @@ export class VariantAnalysisManager
}
public async runVariantAnalysis(
- uris: Uri[],
+ qlPackDetails: QlPackDetails,
progress: ProgressCallback,
token: CancellationToken,
): Promise {
@@ -323,35 +369,43 @@ export class VariantAnalysisManager
actionBranch,
base64Pack,
repoSelection,
- queryFile,
- queryMetadata,
controllerRepo,
queryStartTime,
- language,
} = await prepareRemoteQueryRun(
this.cliServer,
this.app.credentials,
- uris,
+ qlPackDetails,
progress,
token,
this.dbManager,
);
- const queryName = getQueryName(queryMetadata, queryFile);
- const variantAnalysisLanguage = parseVariantAnalysisQueryLanguage(language);
+ // For now we get the metadata for the first query in the pack.
+ // and use that in the submission and query history. In the future
+ // we'll need to consider how to handle having multiple queries.
+ const firstQueryFile = qlPackDetails.queryFiles[0];
+ const queryMetadata = await tryGetQueryMetadata(
+ this.cliServer,
+ firstQueryFile,
+ );
+ const queryName = getQueryName(queryMetadata, firstQueryFile);
+ const variantAnalysisLanguage = parseVariantAnalysisQueryLanguage(
+ qlPackDetails.language,
+ );
if (variantAnalysisLanguage === undefined) {
throw new UserCancellationException(
- `Found unsupported language: ${language}`,
+ `Found unsupported language: ${qlPackDetails.language}`,
);
}
- const queryText = await readFile(queryFile, "utf8");
+ const queryText = await readFile(firstQueryFile, "utf8");
- const queries =
- uris.length === 1
+ const queries: VariantAnalysisQueries | undefined =
+ qlPackDetails.queryFiles.length === 1
? undefined
: {
- language: variantAnalysisLanguage,
+ language: qlPackDetails.language,
+ count: qlPackDetails.queryFiles.length,
};
const variantAnalysisSubmission: VariantAnalysisSubmission = {
@@ -360,7 +414,7 @@ export class VariantAnalysisManager
controllerRepoId: controllerRepo.id,
query: {
name: queryName,
- filePath: queryFile,
+ filePath: firstQueryFile,
pack: base64Pack,
language: variantAnalysisLanguage,
text: queryText,
diff --git a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts
index 2aebd1fb9..65f5151a6 100644
--- a/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts
+++ b/extensions/ql-vscode/src/variant-analysis/variant-analysis-view.ts
@@ -218,9 +218,15 @@ export class VariantAnalysisView
}
private getTitle(variantAnalysis: VariantAnalysis | undefined): string {
- return variantAnalysis
- ? `${variantAnalysis.query.name} - Variant Analysis Results`
- : `Variant Analysis ${this.variantAnalysisId} - Results`;
+ if (!variantAnalysis) {
+ return `Variant Analysis ${this.variantAnalysisId} - Results`;
+ }
+
+ if (variantAnalysis.queries) {
+ return `Variant Analysis using multiple queries - Results`;
+ } else {
+ return `${variantAnalysis.query.name} - Variant Analysis Results`;
+ }
}
private async showDataFlows(dataFlows: DataFlowPaths): Promise {
diff --git a/extensions/ql-vscode/src/view/compare/Compare.tsx b/extensions/ql-vscode/src/view/compare/Compare.tsx
index 65dc7d0db..5b2b5a51d 100644
--- a/extensions/ql-vscode/src/view/compare/Compare.tsx
+++ b/extensions/ql-vscode/src/view/compare/Compare.tsx
@@ -25,7 +25,7 @@ const Message = styled.div`
padding: 1.5rem;
`;
-export function Compare(_: Record): JSX.Element {
+export function Compare(_: Record): React.JSX.Element {
const [queryInfo, setQueryInfo] =
useState(null);
const [comparison, setComparison] = useState(
diff --git a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx
index 4b43b1573..d7846edcf 100644
--- a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx
+++ b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPaths.tsx
@@ -32,7 +32,7 @@ export const DataFlowPaths = ({
dataFlowPaths,
}: {
dataFlowPaths: DataFlowPathsDomainModel;
-}): JSX.Element => {
+}): React.JSX.Element => {
const [selectedCodeFlow, setSelectedCodeFlow] = useState(
dataFlowPaths.codeFlows[0],
);
diff --git a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx
index 798577a3b..9267b81f0 100644
--- a/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx
+++ b/extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx
@@ -9,7 +9,7 @@ export type DataFlowPathsViewProps = {
export function DataFlowPathsView({
dataFlowPaths: initialDataFlowPaths,
-}: DataFlowPathsViewProps): JSX.Element {
+}: DataFlowPathsViewProps): React.JSX.Element {
const [dataFlowPaths, setDataFlowPaths] = useState<
DataFlowPathsDomainModel | undefined
>(initialDataFlowPaths);
diff --git a/extensions/ql-vscode/src/view/method-modeling/MethodModeling.tsx b/extensions/ql-vscode/src/view/method-modeling/MethodModeling.tsx
index cf0048e68..47872ee59 100644
--- a/extensions/ql-vscode/src/view/method-modeling/MethodModeling.tsx
+++ b/extensions/ql-vscode/src/view/method-modeling/MethodModeling.tsx
@@ -64,7 +64,7 @@ export const MethodModeling = ({
method,
isModelingInProgress,
onChange,
-}: MethodModelingProps): JSX.Element => {
+}: MethodModelingProps): React.JSX.Element => {
return (
diff --git a/extensions/ql-vscode/src/view/method-modeling/MethodModelingInputs.tsx b/extensions/ql-vscode/src/view/method-modeling/MethodModelingInputs.tsx
index bb9d1c920..78d96f391 100644
--- a/extensions/ql-vscode/src/view/method-modeling/MethodModelingInputs.tsx
+++ b/extensions/ql-vscode/src/view/method-modeling/MethodModelingInputs.tsx
@@ -39,7 +39,7 @@ export const MethodModelingInputs = ({
modelingStatus,
isModelingInProgress,
onChange,
-}: MethodModelingInputsProps): JSX.Element => {
+}: MethodModelingInputsProps): React.JSX.Element => {
const inputProps = {
language,
method,
diff --git a/extensions/ql-vscode/src/view/method-modeling/MethodModelingView.tsx b/extensions/ql-vscode/src/view/method-modeling/MethodModelingView.tsx
index a12d257a7..fd9742c7b 100644
--- a/extensions/ql-vscode/src/view/method-modeling/MethodModelingView.tsx
+++ b/extensions/ql-vscode/src/view/method-modeling/MethodModelingView.tsx
@@ -16,7 +16,9 @@ type Props = {
initialViewState?: MethodModelingPanelViewState;
};
-export function MethodModelingView({ initialViewState }: Props): JSX.Element {
+export function MethodModelingView({
+ initialViewState,
+}: Props): React.JSX.Element {
const [viewState, setViewState] = useState<
MethodModelingPanelViewState | undefined
>(initialViewState);
diff --git a/extensions/ql-vscode/src/view/model-editor/MethodName.tsx b/extensions/ql-vscode/src/view/model-editor/MethodName.tsx
index 7e239d9c2..bf1892394 100644
--- a/extensions/ql-vscode/src/view/model-editor/MethodName.tsx
+++ b/extensions/ql-vscode/src/view/model-editor/MethodName.tsx
@@ -22,7 +22,7 @@ const TypeMethodName = (method: Method) => {
);
};
-export const MethodName = (method: Method): JSX.Element => {
+export const MethodName = (method: Method): React.JSX.Element => {
return (
{method.packageName && <>{method.packageName}.>}
diff --git a/extensions/ql-vscode/src/view/model-editor/ModelEditor.tsx b/extensions/ql-vscode/src/view/model-editor/ModelEditor.tsx
index b59f5e9cc..c0d868f54 100644
--- a/extensions/ql-vscode/src/view/model-editor/ModelEditor.tsx
+++ b/extensions/ql-vscode/src/view/model-editor/ModelEditor.tsx
@@ -85,7 +85,7 @@ export function ModelEditor({
initialMethods = [],
initialModeledMethods = {},
initialHideModeledMethods = INITIAL_HIDE_MODELED_METHODS_VALUE,
-}: Props): JSX.Element {
+}: Props): React.JSX.Element {
const [viewState, setViewState] = useState(
initialViewState,
);
diff --git a/extensions/ql-vscode/src/view/model-editor/ModelInputDropdown.tsx b/extensions/ql-vscode/src/view/model-editor/ModelInputDropdown.tsx
index e50b5f566..999e651af 100644
--- a/extensions/ql-vscode/src/view/model-editor/ModelInputDropdown.tsx
+++ b/extensions/ql-vscode/src/view/model-editor/ModelInputDropdown.tsx
@@ -27,7 +27,7 @@ export const ModelInputDropdown = ({
modeledMethod,
modelingStatus,
onChange,
-}: Props): JSX.Element => {
+}: Props): React.JSX.Element => {
const options = useMemo(() => {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
diff --git a/extensions/ql-vscode/src/view/model-editor/ModelOutputDropdown.tsx b/extensions/ql-vscode/src/view/model-editor/ModelOutputDropdown.tsx
index 5c5053903..a03d72042 100644
--- a/extensions/ql-vscode/src/view/model-editor/ModelOutputDropdown.tsx
+++ b/extensions/ql-vscode/src/view/model-editor/ModelOutputDropdown.tsx
@@ -27,7 +27,7 @@ export const ModelOutputDropdown = ({
modeledMethod,
modelingStatus,
onChange,
-}: Props): JSX.Element => {
+}: Props): React.JSX.Element => {
const options = useMemo(() => {
const modelsAsDataLanguage = getModelsAsDataLanguage(language);
diff --git a/extensions/ql-vscode/src/view/model-editor/ModelTypeDropdown.tsx b/extensions/ql-vscode/src/view/model-editor/ModelTypeDropdown.tsx
index 98b9bf7c1..7842a9c23 100644
--- a/extensions/ql-vscode/src/view/model-editor/ModelTypeDropdown.tsx
+++ b/extensions/ql-vscode/src/view/model-editor/ModelTypeDropdown.tsx
@@ -31,7 +31,7 @@ export const ModelTypeDropdown = ({
modeledMethod,
modelingStatus,
onChange,
-}: Props): JSX.Element => {
+}: Props): React.JSX.Element => {
const options = useMemo(() => {
const baseOptions: Array<{ value: ModeledMethodType; label: string }> = [
{ value: "none", label: "Unmodeled" },
diff --git a/extensions/ql-vscode/src/view/model-editor/ModelTypeTextbox.tsx b/extensions/ql-vscode/src/view/model-editor/ModelTypeTextbox.tsx
index 48a2de7df..d52ab1306 100644
--- a/extensions/ql-vscode/src/view/model-editor/ModelTypeTextbox.tsx
+++ b/extensions/ql-vscode/src/view/model-editor/ModelTypeTextbox.tsx
@@ -15,12 +15,16 @@ type Props = {
"aria-label"?: string;
};
+const stopClickPropagation = (e: React.MouseEvent) => {
+ e.stopPropagation();
+};
+
export const ModelTypeTextbox = ({
modeledMethod,
typeInfo,
onChange,
...props
-}: Props): JSX.Element => {
+}: Props): React.JSX.Element => {
const [value, setValue] = useState(
modeledMethod[typeInfo],
);
@@ -48,5 +52,12 @@ export const ModelTypeTextbox = ({
500,
);
- return ;
+ return (
+
+ );
};
diff --git a/extensions/ql-vscode/src/view/results/AlertTableNoResults.tsx b/extensions/ql-vscode/src/view/results/AlertTableNoResults.tsx
index 51bd4c5ff..5e10849cd 100644
--- a/extensions/ql-vscode/src/view/results/AlertTableNoResults.tsx
+++ b/extensions/ql-vscode/src/view/results/AlertTableNoResults.tsx
@@ -6,7 +6,7 @@ interface Props {
showRawResults: () => void;
}
-export function AlertTableNoResults(props: Props): JSX.Element {
+export function AlertTableNoResults(props: Props): React.JSX.Element {
if (props.nonemptyRawResults) {
return (
diff --git a/extensions/ql-vscode/src/view/results/AlertTableTruncatedMessage.tsx b/extensions/ql-vscode/src/view/results/AlertTableTruncatedMessage.tsx
index c2c1565ea..865ca8bd3 100644
--- a/extensions/ql-vscode/src/view/results/AlertTableTruncatedMessage.tsx
+++ b/extensions/ql-vscode/src/view/results/AlertTableTruncatedMessage.tsx
@@ -2,7 +2,9 @@ interface Props {
numTruncatedResults: number;
}
-export function AlertTableTruncatedMessage(props: Props): JSX.Element | null {
+export function AlertTableTruncatedMessage(
+ props: Props,
+): React.JSX.Element | null {
if (props.numTruncatedResults === 0) {
return null;
}
diff --git a/extensions/ql-vscode/src/view/results/EmptyQueryResultsMessage.tsx b/extensions/ql-vscode/src/view/results/EmptyQueryResultsMessage.tsx
index 93107ce41..da58e2d3f 100644
--- a/extensions/ql-vscode/src/view/results/EmptyQueryResultsMessage.tsx
+++ b/extensions/ql-vscode/src/view/results/EmptyQueryResultsMessage.tsx
@@ -18,7 +18,7 @@ const Container = styled.span`
text-align: center;
`;
-export function EmptyQueryResultsMessage(): JSX.Element {
+export function EmptyQueryResultsMessage(): React.JSX.Element {
return (
diff --git a/extensions/ql-vscode/src/view/results/ProblemsViewCheckbox.tsx b/extensions/ql-vscode/src/view/results/ProblemsViewCheckbox.tsx
index de0e0f2f9..59a1a2bab 100644
--- a/extensions/ql-vscode/src/view/results/ProblemsViewCheckbox.tsx
+++ b/extensions/ql-vscode/src/view/results/ProblemsViewCheckbox.tsx
@@ -10,7 +10,7 @@ interface Props {
handleCheckboxChanged: (event: React.ChangeEvent) => void;
}
-export function ProblemsViewCheckbox(props: Props): JSX.Element | null {
+export function ProblemsViewCheckbox(props: Props): React.JSX.Element | null {
const { selectedTable, problemsViewSelected, handleCheckboxChanged } = props;
if (selectedTable !== ALERTS_TABLE_NAME) {
diff --git a/extensions/ql-vscode/src/view/results/RawTableValue.tsx b/extensions/ql-vscode/src/view/results/RawTableValue.tsx
index e9afdfe42..7036b415d 100644
--- a/extensions/ql-vscode/src/view/results/RawTableValue.tsx
+++ b/extensions/ql-vscode/src/view/results/RawTableValue.tsx
@@ -13,7 +13,7 @@ export default function RawTableValue({
value,
databaseUri,
onSelected,
-}: Props): JSX.Element {
+}: Props): React.JSX.Element {
switch (value.type) {
case "boolean":
return {value.value.toString()};
diff --git a/extensions/ql-vscode/src/view/results/ResultCount.tsx b/extensions/ql-vscode/src/view/results/ResultCount.tsx
index 49ae94284..2311a652a 100644
--- a/extensions/ql-vscode/src/view/results/ResultCount.tsx
+++ b/extensions/ql-vscode/src/view/results/ResultCount.tsx
@@ -14,7 +14,7 @@ function getResultCount(resultSet: ResultSet): number {
}
}
-export function ResultCount(props: Props): JSX.Element | null {
+export function ResultCount(props: Props): React.JSX.Element | null {
if (!props.resultSet) {
return null;
}
diff --git a/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx b/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx
index c073b10f8..29f62c72f 100644
--- a/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx
+++ b/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx
@@ -23,7 +23,7 @@ export function ClickableLocation({
label,
databaseUri,
onClick: onClick,
-}: Props): JSX.Element {
+}: Props): React.JSX.Element {
const handleClick = useCallback(
(e: React.MouseEvent) => {
e.preventDefault();
diff --git a/extensions/ql-vscode/src/view/results/locations/Location.tsx b/extensions/ql-vscode/src/view/results/locations/Location.tsx
index 8f45c194d..85a325aeb 100644
--- a/extensions/ql-vscode/src/view/results/locations/Location.tsx
+++ b/extensions/ql-vscode/src/view/results/locations/Location.tsx
@@ -22,7 +22,7 @@ export function Location({
databaseUri,
title,
onClick,
-}: Props): JSX.Element {
+}: Props): React.JSX.Element {
const displayLabel = useMemo(() => convertNonPrintableChars(label), [label]);
if (loc === undefined) {
diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx
index 67f19c79b..3a72c3548 100644
--- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx
+++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx
@@ -51,7 +51,7 @@ export function VariantAnalysis({
variantAnalysis: initialVariantAnalysis,
repoStates: initialRepoStates = [],
repoResults: initialRepoResults = [],
-}: VariantAnalysisProps): JSX.Element {
+}: VariantAnalysisProps): React.JSX.Element {
const [variantAnalysis, setVariantAnalysis] = useState<
VariantAnalysisDomainModel | undefined
>(initialVariantAnalysis);
diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisHeader.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisHeader.tsx
index d6191808b..bdd9b5e11 100644
--- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisHeader.tsx
+++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisHeader.tsx
@@ -21,6 +21,7 @@ import {
defaultFilterSortState,
filterAndSortRepositoriesWithResults,
} from "../../variant-analysis/shared/variant-analysis-filter-sort";
+import { ViewTitle } from "../common";
type VariantAnalysisHeaderProps = {
variantAnalysis: VariantAnalysis;
@@ -50,6 +51,29 @@ const Row = styled.div`
align-items: center;
`;
+const QueryInfo = ({
+ variantAnalysis,
+ onOpenQueryFileClick,
+ onViewQueryTextClick,
+}: {
+ variantAnalysis: VariantAnalysis;
+ onOpenQueryFileClick: () => void;
+ onViewQueryTextClick: () => void;
+}) => {
+ if (variantAnalysis.queries) {
+ return {variantAnalysis.queries?.count} queries;
+ } else {
+ return (
+
+ );
+ }
+};
+
export const VariantAnalysisHeader = ({
variantAnalysis,
repositoryStates,
@@ -117,9 +141,8 @@ export const VariantAnalysisHeader = ({
return (
-
diff --git a/extensions/ql-vscode/src/view/webview-definition.ts b/extensions/ql-vscode/src/view/webview-definition.ts
index b23b8150c..ff9265d11 100644
--- a/extensions/ql-vscode/src/view/webview-definition.ts
+++ b/extensions/ql-vscode/src/view/webview-definition.ts
@@ -1,3 +1,3 @@
export type WebviewDefinition = {
- component: JSX.Element;
+ component: React.JSX.Element;
};
diff --git a/extensions/ql-vscode/supported_cli_versions.json b/extensions/ql-vscode/supported_cli_versions.json
index d29e63e4d..318248126 100644
--- a/extensions/ql-vscode/supported_cli_versions.json
+++ b/extensions/ql-vscode/supported_cli_versions.json
@@ -1,5 +1,5 @@
[
- "v2.16.0",
+ "v2.16.1",
"v2.15.5",
"v2.14.6",
"v2.13.5",
diff --git a/extensions/ql-vscode/test/e2e/README.md b/extensions/ql-vscode/test/e2e/README.md
new file mode 100644
index 000000000..c91c80283
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/README.md
@@ -0,0 +1,20 @@
+## VS Code CodeQL E2E Tests
+
+When running the tests locally on a mac a different processor has to be emulated, which makes everythign VERY slow. Therefore we need to add higher timeouts in the test, so that they pass locally.
+
+### How to use locally
+
+Setup
+
+- install playwright if you haven't yet (`npx playwright install`)
+- go to the e2e test folder on your terminal
+- make sure docker is running
+- run `docker-compose build`
+- run `docker-compose up`
+
+Run tests
+
+- run `npx playwright test --ui` from the e2e test folder to follow the test while it's running. This UI has a 'locator' tool with which elements on the test screen can be found
+- use `npx playwright test --debug` to follow the test in real time and interact with the interface, e.g. press enter or input into fields, stop and start
+
+During the test elements are created in the docker volume, e.g. the downloaded database or query data. This might interfer with other tests or when running a test twice. If that happens restart your docker volume by using `docker-compose down -v` and `docker-compose up`. Sometimes already existing queries from former runs change the input the extension needs.
diff --git a/extensions/ql-vscode/test/e2e/docker-compose.yml b/extensions/ql-vscode/test/e2e/docker-compose.yml
new file mode 100644
index 000000000..3cece128c
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/docker-compose.yml
@@ -0,0 +1,55 @@
+version: "3.8"
+
+services:
+ code-server:
+ build:
+ context: docker
+ dockerfile: Dockerfile
+ platform: linux/amd64
+ container_name: code-server
+ user: "1000"
+ volumes:
+ - local-data:/home/coder/.local/share/code-server
+ - local-user-data:/home/coder/.local/share/code-server/User
+ - ./docker/config/config.yaml:/home/coder/.config/code-server/config.yaml
+ - ./docker/User/settings.json:/home/coder/.local/share/code-server/User/settings.json
+ - project-data:/home/coder/project
+ ports:
+ - 8080:8080
+ restart: unless-stopped
+ depends_on:
+ code-server-init:
+ condition: service_completed_successfully
+ code-server-init:
+ build:
+ context: docker
+ dockerfile: Dockerfile
+ platform: linux/amd64
+ user: "1000"
+ volumes:
+ - local-data:/home/coder/.local/share/code-server
+ - local-user-data:/home/coder/.local/share/code-server/User
+ - ./docker/config/config.yaml:/home/coder/.config/code-server/config.yaml
+ - ./docker/User/settings.json:/home/coder/.local/share/code-server/User/settings.json
+ - project-data:/home/coder/project
+ entrypoint: |
+ /usr/bin/entrypoint.sh --install-extension GitHub.vscode-codeql
+ restart: "no"
+ depends_on:
+ - files-init
+ files-init:
+ image: alpine:3.19.0
+ restart: "no"
+ # Since we're not running the code-server container using the same user as our host user,
+ # we need to set the permissions on the mounted volumes to match the user inside the container.
+ entrypoint: |
+ /bin/sh -c "chown 1000:1000 /home/coder/.local/share/code-server /home/coder/.local/share/code-server/User /home/coder/project"
+ volumes:
+ - local-data:/home/coder/.local/share/code-server
+ - local-user-data:/home/coder/.local/share/code-server/User
+ - project-data:/home/coder/project
+
+volumes:
+ local-data:
+ local-user-data:
+ project-data:
diff --git a/extensions/ql-vscode/test/e2e/docker/Dockerfile b/extensions/ql-vscode/test/e2e/docker/Dockerfile
new file mode 100644
index 000000000..e9774eef2
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/docker/Dockerfile
@@ -0,0 +1,16 @@
+FROM codercom/code-server:4.20.0
+
+USER root
+
+RUN apt-get update \
+ && apt-get install -y \
+ unzip \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN wget -q -O /tmp/codeql.zip https://github.com/github/codeql-cli-binaries/releases/download/v2.15.5/codeql-linux64.zip \
+ && unzip -q /tmp/codeql.zip -d /opt \
+ && rm -rf /tmp/codeql.zip
+
+ENV PATH="/opt/codeql:${PATH}"
+
+USER 1000
diff --git a/extensions/ql-vscode/test/e2e/docker/User/settings.json b/extensions/ql-vscode/test/e2e/docker/User/settings.json
new file mode 100644
index 000000000..8dfd44b28
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/docker/User/settings.json
@@ -0,0 +1,6 @@
+{
+ "workbench.startupEditor": "none",
+ "security.workspace.trust.enabled": false,
+ "codeQL.cli.executablePath": "/opt/codeql/codeql",
+ "codeQL.telemetry.enableTelemetry": false
+}
diff --git a/extensions/ql-vscode/test/e2e/docker/config/config.yaml b/extensions/ql-vscode/test/e2e/docker/config/config.yaml
new file mode 100644
index 000000000..e1340d4e9
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/docker/config/config.yaml
@@ -0,0 +1,6 @@
+bind-addr: 127.0.0.1:8080
+auth: none
+cert: false
+disable-workspace-trust: true
+disable-telemetry: true
+disable-update-check: true
diff --git a/extensions/ql-vscode/test/e2e/playwright.config.ts b/extensions/ql-vscode/test/e2e/playwright.config.ts
new file mode 100644
index 000000000..74b7d8195
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/playwright.config.ts
@@ -0,0 +1,36 @@
+import { defineConfig, devices } from "@playwright/test";
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+export default defineConfig({
+ testDir: ".",
+
+ timeout: 5 * 60 * 1000,
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: "html",
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: "http://localhost:8080",
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: "on-first-retry",
+ },
+
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: "chromium",
+ use: { ...devices["Desktop Chrome"] },
+ },
+ ],
+});
diff --git a/extensions/ql-vscode/test/e2e/run-query.spec.ts b/extensions/ql-vscode/test/e2e/run-query.spec.ts
new file mode 100644
index 000000000..6007a279f
--- /dev/null
+++ b/extensions/ql-vscode/test/e2e/run-query.spec.ts
@@ -0,0 +1,79 @@
+import { test, expect } from "@playwright/test";
+
+test("run query and open it from history", async ({ page }) => {
+ await page.goto("/?folder=/home/coder/project");
+
+ await page.getByRole("tab", { name: "CodeQL" }).locator("a").click();
+
+ // decline extension telemetry
+ await page.getByRole("button", { name: "No", exact: true }).click({
+ timeout: 60000,
+ });
+
+ await page.keyboard.press("Control+Shift+P");
+ await page.keyboard.type("Create Query");
+ await page.keyboard.press("Enter");
+
+ await page.getByLabel("JavaScript, javascript").locator("a").click({
+ timeout: 60000,
+ });
+
+ // select folder for first query
+ await page
+ .getByText(
+ "Results0 SelectedPress 'Enter' to confirm your input or 'Escape' to cancelOK",
+ )
+ .press("Enter");
+
+ // download database
+ await page
+ .getByRole("button", { name: "Download database" })
+ .click({ timeout: 60000 });
+ await page.getByPlaceholder("https://github.com//<").press("Enter");
+ await page
+ .locator("#list_id_3_0")
+ .getByText("javascript")
+ .click({ timeout: 60000 });
+
+ await page.keyboard.press("Control+Shift+P");
+ await page.keyboard.type("Run Query on selected");
+ await page.keyboard.press("Enter");
+
+ // check if results page is visible
+ await expect(page.getByText("CodeQL Query Results")).toBeVisible({
+ timeout: 600000,
+ });
+
+ // wait for query history item to be finished
+ await expect(
+ page
+ .locator("#list_id_6_0")
+ .getByLabel("Hello world on d3/d3 -")
+ .locator("div")
+ .first(),
+ ).toBeVisible({ timeout: 60000 });
+
+ // close results page and open query from history
+ await page
+ .getByLabel("CodeQL Query Results, Editor Group")
+ .getByLabel("Close (Ctrl+F4)")
+ .click();
+
+ await expect(
+ page
+ .frameLocator(".webview")
+ .frameLocator('iframe[title="CodeQL Query Results"]')
+ .getByText("#selectalerts32 resultsShow"),
+ ).not.toBeVisible();
+
+ await page
+ .locator("#list_id_6_0")
+ .getByLabel("Hello world on d3/d3 -")
+ .locator("div")
+ .first()
+ .click();
+
+ await expect(
+ page.getByLabel("CodeQL Query Results", { exact: true }).locator("div"),
+ ).toBeVisible({ timeout: 60000 });
+});
diff --git a/extensions/ql-vscode/test/unit-tests/codeql-cli/distribution/releases-api-consumer.test.ts b/extensions/ql-vscode/test/unit-tests/codeql-cli/distribution/releases-api-consumer.test.ts
index 62055657c..a4d29f272 100644
--- a/extensions/ql-vscode/test/unit-tests/codeql-cli/distribution/releases-api-consumer.test.ts
+++ b/extensions/ql-vscode/test/unit-tests/codeql-cli/distribution/releases-api-consumer.test.ts
@@ -115,7 +115,7 @@ describe("Releases API consumer", () => {
await expect(
consumer.getLatestRelease(new Range("5.*.*")),
- ).rejects.toThrowError();
+ ).rejects.toThrow();
});
it("picked release passes additional compatibility test if an additional compatibility test is specified", async () => {
@@ -140,7 +140,7 @@ describe("Releases API consumer", () => {
(asset) => asset.name === "otherExampleAsset.txt",
),
),
- ).rejects.toThrowError();
+ ).rejects.toThrow();
});
it("picked release is the most recent prerelease when includePrereleases is set", async () => {
diff --git a/extensions/ql-vscode/test/unit-tests/common/ql.test.ts b/extensions/ql-vscode/test/unit-tests/common/ql.test.ts
index 2f4a1cac9..9991ab5ab 100644
--- a/extensions/ql-vscode/test/unit-tests/common/ql.test.ts
+++ b/extensions/ql-vscode/test/unit-tests/common/ql.test.ts
@@ -2,9 +2,9 @@ import { join } from "path";
import { dirSync } from "tmp-promise";
import type { DirResult } from "tmp";
import { writeFile } from "fs-extra";
-import { getQlPackPath } from "../../../src/common/ql";
+import { getQlPackFilePath } from "../../../src/common/ql";
-describe("getQlPackPath", () => {
+describe("getQlPackFilePath", () => {
let tmpDir: DirResult;
beforeEach(() => {
@@ -22,14 +22,14 @@ describe("getQlPackPath", () => {
it("should find a qlpack.yml when it exists", async () => {
await writeFile(join(tmpDir.name, "qlpack.yml"), "name: test");
- const result = await getQlPackPath(tmpDir.name);
+ const result = await getQlPackFilePath(tmpDir.name);
expect(result).toEqual(join(tmpDir.name, "qlpack.yml"));
});
it("should find a codeql-pack.yml when it exists", async () => {
await writeFile(join(tmpDir.name, "codeql-pack.yml"), "name: test");
- const result = await getQlPackPath(tmpDir.name);
+ const result = await getQlPackFilePath(tmpDir.name);
expect(result).toEqual(join(tmpDir.name, "codeql-pack.yml"));
});
@@ -37,12 +37,12 @@ describe("getQlPackPath", () => {
await writeFile(join(tmpDir.name, "qlpack.yml"), "name: test");
await writeFile(join(tmpDir.name, "codeql-pack.yml"), "name: test");
- const result = await getQlPackPath(tmpDir.name);
+ const result = await getQlPackFilePath(tmpDir.name);
expect(result).toEqual(join(tmpDir.name, "qlpack.yml"));
});
it("should find nothing when it doesn't exist", async () => {
- const result = await getQlPackPath(tmpDir.name);
+ const result = await getQlPackFilePath(tmpDir.name);
expect(result).toEqual(undefined);
});
});
diff --git a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-results-manager.test.ts b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-results-manager.test.ts
index 5faec408f..5035aaf52 100644
--- a/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-results-manager.test.ts
+++ b/extensions/ql-vscode/test/vscode-tests/activated-extension/variant-analysis/variant-analysis-results-manager.test.ts
@@ -154,7 +154,7 @@ describe(VariantAnalysisResultsManager.name, () => {
async function* generateInParts() {
const partLength = fileContents.length / 5;
for (let i = 0; i < 5; i++) {
- yield fileContents.slice(i * partLength, (i + 1) * partLength);
+ yield fileContents.subarray(i * partLength, (i + 1) * partLength);
}
}
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 97fe6065f..b223845fd 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
@@ -1,4 +1,4 @@
-import { CancellationTokenSource, commands, Uri, window } from "vscode";
+import { CancellationTokenSource, commands, window, Uri } from "vscode";
import { extLogger } from "../../../../src/common/logging/vscode";
import { setRemoteControllerRepo } from "../../../../src/config";
import * as ghApiClient from "../../../../src/variant-analysis/gh-api/gh-api-client";
@@ -26,6 +26,7 @@ import type { ExtensionPackMetadata } from "../../../../src/model-editor/extensi
import type { QlPackLockFile } from "../../../../src/packaging/qlpack-lock-file";
//import { expect } from "@jest/globals";
import "../../../matchers/toExistInCodeQLPack";
+import type { QlPackDetails } from "../../../../src/variant-analysis/ql-pack-details";
describe("Variant Analysis Manager", () => {
let cli: CodeQLCliServer;
@@ -99,10 +100,18 @@ describe("Variant Analysis Manager", () => {
});
it("should run a variant analysis that is part of a qlpack", async () => {
- const fileUri = getFile("data-remote-qlpack/in-pack.ql");
+ const filePath = getFileOrDir("data-remote-qlpack/in-pack.ql");
+ const qlPackRootPath = getFileOrDir("data-remote-qlpack");
+ const qlPackFilePath = getFileOrDir("data-remote-qlpack/qlpack.yml");
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: [filePath],
+ qlPackRootPath,
+ qlPackFilePath,
+ language: QueryLanguage.Javascript,
+ };
await variantAnalysisManager.runVariantAnalysis(
- [fileUri],
+ qlPackDetails,
progress,
cancellationTokenSource.token,
);
@@ -120,10 +129,17 @@ describe("Variant Analysis Manager", () => {
});
it("should run a remote query that is not part of a qlpack", async () => {
- const fileUri = getFile("data-remote-no-qlpack/in-pack.ql");
+ const filePath = getFileOrDir("data-remote-no-qlpack/in-pack.ql");
+ const qlPackRootPath = getFileOrDir("data-remote-no-qlpack");
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: [filePath],
+ qlPackRootPath,
+ qlPackFilePath: undefined,
+ language: QueryLanguage.Javascript,
+ };
await variantAnalysisManager.runVariantAnalysis(
- [fileUri],
+ qlPackDetails,
progress,
cancellationTokenSource.token,
);
@@ -141,10 +157,22 @@ describe("Variant Analysis Manager", () => {
});
it("should run a remote query that is nested inside a qlpack", async () => {
- const fileUri = getFile("data-remote-qlpack-nested/subfolder/in-pack.ql");
+ const filePath = getFileOrDir(
+ "data-remote-qlpack-nested/subfolder/in-pack.ql",
+ );
+ const qlPackRootPath = getFileOrDir("data-remote-qlpack-nested");
+ const qlPackFilePath = getFileOrDir(
+ "data-remote-qlpack-nested/codeql-pack.yml",
+ );
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: [filePath],
+ qlPackRootPath,
+ qlPackFilePath,
+ language: QueryLanguage.Javascript,
+ };
await variantAnalysisManager.runVariantAnalysis(
- [fileUri],
+ qlPackDetails,
progress,
cancellationTokenSource.token,
);
@@ -162,10 +190,17 @@ describe("Variant Analysis Manager", () => {
});
it("should cancel a run before uploading", async () => {
- const fileUri = getFile("data-remote-no-qlpack/in-pack.ql");
+ const filePath = getFileOrDir("data-remote-no-qlpack/in-pack.ql");
+ const qlPackRootPath = getFileOrDir("data-remote-no-qlpack");
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: [filePath],
+ qlPackRootPath,
+ qlPackFilePath: undefined,
+ language: QueryLanguage.Javascript,
+ };
const promise = variantAnalysisManager.runVariantAnalysis(
- [fileUri],
+ qlPackDetails,
progress,
cancellationTokenSource.token,
);
@@ -202,6 +237,8 @@ describe("Variant Analysis Manager", () => {
it("should run a remote query that is part of a qlpack", async () => {
await doVariantAnalysisTest({
queryPath: "data-remote-qlpack/in-pack.ql",
+ qlPackRootPath: "data-remote-qlpack",
+ qlPackFilePath: "data-remote-qlpack/qlpack.yml",
expectedPackName: "github/remote-query-pack",
filesThatExist: ["in-pack.ql", "lib.qll"],
filesThatDoNotExist: [],
@@ -212,6 +249,8 @@ describe("Variant Analysis Manager", () => {
it("should run a remote query that is not part of a qlpack", async () => {
await doVariantAnalysisTest({
queryPath: "data-remote-no-qlpack/in-pack.ql",
+ qlPackRootPath: "data-remote-no-qlpack",
+ qlPackFilePath: undefined,
expectedPackName: "codeql-remote/query",
filesThatExist: ["in-pack.ql"],
filesThatDoNotExist: ["lib.qll", "not-in-pack.ql"],
@@ -222,6 +261,8 @@ describe("Variant Analysis Manager", () => {
it("should run a remote query that is nested inside a qlpack", async () => {
await doVariantAnalysisTest({
queryPath: "data-remote-qlpack-nested/subfolder/in-pack.ql",
+ qlPackRootPath: "data-remote-qlpack-nested",
+ qlPackFilePath: "data-remote-qlpack-nested/codeql-pack.yml",
expectedPackName: "github/remote-query-pack",
filesThatExist: ["subfolder/in-pack.ql", "otherfolder/lib.qll"],
filesThatDoNotExist: ["subfolder/not-in-pack.ql"],
@@ -239,6 +280,8 @@ describe("Variant Analysis Manager", () => {
await cli.setUseExtensionPacks(true);
await doVariantAnalysisTest({
queryPath: "data-remote-qlpack-nested/subfolder/in-pack.ql",
+ qlPackRootPath: "data-remote-qlpack-nested",
+ qlPackFilePath: "data-remote-qlpack-nested/codeql-pack.yml",
expectedPackName: "github/remote-query-pack",
filesThatExist: [
"subfolder/in-pack.ql",
@@ -275,16 +318,23 @@ describe("Variant Analysis Manager", () => {
const queryToRun =
"Security/CWE/CWE-020/ExternalAPIsUsedWithUntrustedData.ql";
- const extraQuery = "Telemetry/ExtractorInformation.ql";
+ // Recent versions of the CLI don't preserve queries with extensible predicates in MRVA packs,
+ // because all the necessary info is in the `.packinfo` file.
+ const extraQueries =
+ (await cli.cliConstraints.preservesExtensiblePredicatesInMrvaPack())
+ ? ["Telemetry/ExtractorInformation.ql"]
+ : [];
+
+ const qlPackRootPath = join(process.env.TEST_CODEQL_PATH, "java/ql/src");
+ const queryPath = join(qlPackRootPath, queryToRun);
+ const qlPackFilePath = join(qlPackRootPath, "qlpack.yml");
await doVariantAnalysisTest({
- queryPath: join(
- process.env.TEST_CODEQL_PATH,
- "java/ql/src",
- queryToRun,
- ),
+ queryPath,
+ qlPackRootPath,
+ qlPackFilePath,
expectedPackName: "codeql/java-queries",
- filesThatExist: [queryToRun, extraQuery],
+ filesThatExist: [queryToRun, ...extraQueries],
filesThatDoNotExist: [],
qlxFilesThatExist: [],
dependenciesToCheck: ["codeql/java-all"],
@@ -295,6 +345,8 @@ describe("Variant Analysis Manager", () => {
async function doVariantAnalysisTest({
queryPath,
+ qlPackRootPath,
+ qlPackFilePath,
expectedPackName,
filesThatExist,
qlxFilesThatExist,
@@ -306,6 +358,8 @@ describe("Variant Analysis Manager", () => {
checkVersion = true,
}: {
queryPath: string;
+ qlPackRootPath: string;
+ qlPackFilePath: string | undefined;
expectedPackName: string;
filesThatExist: string[];
qlxFilesThatExist: string[];
@@ -313,9 +367,16 @@ describe("Variant Analysis Manager", () => {
dependenciesToCheck?: string[];
checkVersion?: boolean;
}) {
- const fileUri = getFile(queryPath);
+ const filePath = getFileOrDir(queryPath);
+ const qlPackDetails: QlPackDetails = {
+ queryFiles: [filePath],
+ qlPackRootPath: getFileOrDir(qlPackRootPath),
+ qlPackFilePath: qlPackFilePath && getFileOrDir(qlPackFilePath),
+ language: QueryLanguage.Javascript,
+ };
+
await variantAnalysisManager.runVariantAnalysis(
- [fileUri],
+ qlPackDetails,
progress,
cancellationTokenSource.token,
);
@@ -324,7 +385,7 @@ describe("Variant Analysis Manager", () => {
expect(executeCommandSpy).toHaveBeenCalledWith(
"codeQL.monitorNewVariantAnalysis",
expect.objectContaining({
- query: expect.objectContaining({ filePath: fileUri.fsPath }),
+ query: expect.objectContaining({ filePath }),
}),
);
@@ -390,16 +451,19 @@ describe("Variant Analysis Manager", () => {
);
}
- function getFile(file: string): Uri {
- if (isAbsolute(file)) {
- return Uri.file(file);
+ function getFileOrDir(path: string): string {
+ // Use `Uri.file(path).fsPath` to make sure the path is in the correct format for the OS (i.e. forward/backward slashes).
+ if (isAbsolute(path)) {
+ return Uri.file(path).fsPath;
} else {
- return Uri.file(join(baseDir, file));
+ return Uri.file(join(baseDir, path)).fsPath;
}
}
});
describe("runVariantAnalysisFromPublishedPack", () => {
+ // Temporarily disabling this until we add a way to receive multiple queries in the
+ // runVariantAnalysis function.
it("should download pack for correct language and identify problem queries", async () => {
const showQuickPickSpy = jest
.spyOn(window, "showQuickPick")
@@ -419,15 +483,17 @@ describe("Variant Analysis Manager", () => {
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
expect(runVariantAnalysisMock).toHaveBeenCalledTimes(1);
- const queries: Uri[] = runVariantAnalysisMock.mock.calls[0][0];
+ console.log(runVariantAnalysisMock.mock.calls[0][0]);
+ const queries: string[] =
+ runVariantAnalysisMock.mock.calls[0][0].queryFiles;
// Should include queries. Just check that at least one known query exists.
// It doesn't particularly matter which query we check for.
expect(
- queries.find((q) => q.fsPath.includes("PostMessageStar.ql")),
+ queries.find((q) => q.includes("PostMessageStar.ql")),
).toBeDefined();
// Should not include non-problem queries.
expect(
- queries.find((q) => q.fsPath.includes("LinesOfCode.ql")),
+ queries.find((q) => q.includes("LinesOfCode.ql")),
).not.toBeDefined();
});
});
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 b98d018ca..04e555fd1 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
@@ -86,6 +86,14 @@ describe("Variant Analysis Submission Integration", () => {
it("shows the error message", async () => {
await showQlDocument("query.ql");
+ // Select target language for your query
+ quickPickSpy.mockResolvedValueOnce(
+ mockedQuickPickItem({
+ label: "JavaScript",
+ language: "javascript",
+ }),
+ );
+
await commandManager.execute("codeQL.runVariantAnalysis");
expect(showErrorMessageSpy).toHaveBeenCalledWith(
diff --git a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-queries/local-databases.test.ts b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-queries/local-databases.test.ts
index f86543d62..1fdfa67db 100644
--- a/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-queries/local-databases.test.ts
+++ b/extensions/ql-vscode/test/vscode-tests/minimal-workspace/local-queries/local-databases.test.ts
@@ -296,9 +296,7 @@ describe("local databases", () => {
Uri.parse("file:/sourceArchive-uri/"),
);
(db as any).contents.sourceArchiveUri = undefined;
- expect(() => db.resolveSourceFile("abc")).toThrowError(
- "Scheme is missing",
- );
+ expect(() => db.resolveSourceFile("abc")).toThrow("Scheme is missing");
});
it("should fail to resolve when not a file uri", () => {
@@ -308,7 +306,7 @@ describe("local databases", () => {
Uri.parse("file:/sourceArchive-uri/"),
);
(db as any).contents.sourceArchiveUri = undefined;
- expect(() => db.resolveSourceFile("http://abc")).toThrowError(
+ expect(() => db.resolveSourceFile("http://abc")).toThrow(
"Invalid uri scheme",
);
});
diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/github-databases/api.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/github-databases/api.test.ts
index e18b26a5a..f5dbadd6c 100644
--- a/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/github-databases/api.test.ts
+++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/github-databases/api.test.ts
@@ -123,7 +123,7 @@ describe("listDatabases", () => {
it("throws an error", async () => {
await expect(
listDatabases(owner, repo, credentials, config),
- ).rejects.toThrowError("Not found");
+ ).rejects.toThrow("Not found");
});
});
@@ -150,7 +150,7 @@ describe("listDatabases", () => {
it("throws an error", async () => {
await expect(
listDatabases(owner, repo, credentials, config),
- ).rejects.toThrowError("Internal server error");
+ ).rejects.toThrow("Internal server error");
});
});
});
@@ -199,7 +199,7 @@ describe("listDatabases", () => {
it("throws an error", async () => {
await expect(
listDatabases(owner, repo, credentials, config),
- ).rejects.toThrowError("Internal server error");
+ ).rejects.toThrow("Internal server error");
expect(mockListCodeqlDatabases).not.toHaveBeenCalled();
});
});
@@ -270,7 +270,7 @@ describe("listDatabases", () => {
it("throws an error", async () => {
await expect(
listDatabases(owner, repo, credentials, config),
- ).rejects.toThrowError("Not found");
+ ).rejects.toThrow("Not found");
});
});
@@ -297,7 +297,7 @@ describe("listDatabases", () => {
it("throws an error", async () => {
await expect(
listDatabases(owner, repo, credentials, config),
- ).rejects.toThrowError("Internal server error");
+ ).rejects.toThrow("Internal server error");
});
});
});
diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/local-databases-ui.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/local-databases-ui.test.ts
index 05c324651..1d6020787 100644
--- a/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/local-databases-ui.test.ts
+++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/databases/local-databases-ui.test.ts
@@ -7,14 +7,42 @@ import {
createFileSync,
pathExistsSync,
} from "fs-extra";
-import { Uri } from "vscode";
+import { CancellationTokenSource, Uri, window } from "vscode";
+
+import type {
+ DatabaseImportQuickPickItems,
+ DatabaseQuickPickItem,
+ DatabaseSelectionQuickPickItem,
+} from "../../../../src/databases/local-databases-ui";
import { DatabaseUI } from "../../../../src/databases/local-databases-ui";
import { testDisposeHandler } from "../../test-dispose-handler";
import { createMockApp } from "../../../__mocks__/appMock";
import { QueryLanguage } from "../../../../src/common/query-language";
+import { mockedQuickPickItem, mockedObject } from "../../utils/mocking.helpers";
describe("local-databases-ui", () => {
+ const storageDir = dirSync({ unsafeCleanup: true }).name;
+ const db1 = createDatabase(storageDir, "db1-imported", QueryLanguage.Cpp);
+ const db2 = createDatabase(storageDir, "db2-notimported", QueryLanguage.Cpp);
+ const db3 = createDatabase(storageDir, "db3-invalidlanguage", "hucairz");
+
+ // these two should be deleted
+ const db4 = createDatabase(
+ storageDir,
+ "db2-notimported-with-db-info",
+ QueryLanguage.Cpp,
+ ".dbinfo",
+ );
+ const db5 = createDatabase(
+ storageDir,
+ "db2-notimported-with-codeql-database.yml",
+ QueryLanguage.Cpp,
+ "codeql-database.yml",
+ );
+
+ const app = createMockApp({});
+
describe("fixDbUri", () => {
const fixDbUri = (DatabaseUI.prototype as any).fixDbUri;
it("should choose current directory normally", async () => {
@@ -64,30 +92,6 @@ describe("local-databases-ui", () => {
});
it("should delete orphaned databases", async () => {
- const storageDir = dirSync({ unsafeCleanup: true }).name;
- const db1 = createDatabase(storageDir, "db1-imported", QueryLanguage.Cpp);
- const db2 = createDatabase(
- storageDir,
- "db2-notimported",
- QueryLanguage.Cpp,
- );
- const db3 = createDatabase(storageDir, "db3-invalidlanguage", "hucairz");
-
- // these two should be deleted
- const db4 = createDatabase(
- storageDir,
- "db2-notimported-with-db-info",
- QueryLanguage.Cpp,
- ".dbinfo",
- );
- const db5 = createDatabase(
- storageDir,
- "db2-notimported-with-codeql-database.yml",
- QueryLanguage.Cpp,
- "codeql-database.yml",
- );
-
- const app = createMockApp({});
const databaseUI = new DatabaseUI(
app,
{
@@ -98,6 +102,7 @@ describe("local-databases-ui", () => {
onDidChangeCurrentDatabaseItem: () => {
/**/
},
+ setCurrentDatabaseItem: () => {},
} as any,
{
onLanguageContextChanged: () => {
@@ -108,7 +113,6 @@ describe("local-databases-ui", () => {
storageDir,
storageDir,
);
-
await databaseUI.handleRemoveOrphanedDatabases();
expect(pathExistsSync(db1)).toBe(true);
@@ -121,6 +125,130 @@ describe("local-databases-ui", () => {
databaseUI.dispose(testDisposeHandler);
});
+ describe("getDatabaseItem", () => {
+ const progress = jest.fn();
+ const token = new CancellationTokenSource().token;
+ describe("when there is a current database", () => {
+ const databaseUI = new DatabaseUI(
+ app,
+ {
+ databaseItems: [{ databaseUri: Uri.file(db1) }],
+ onDidChangeDatabaseItem: () => {
+ /**/
+ },
+ onDidChangeCurrentDatabaseItem: () => {
+ /**/
+ },
+ setCurrentDatabaseItem: () => {},
+ currentDatabaseItem: { databaseUri: Uri.file(db1) },
+ } as any,
+ {
+ onLanguageContextChanged: () => {
+ /**/
+ },
+ } as any,
+ {} as any,
+ storageDir,
+ storageDir,
+ );
+
+ it("should return current database", async () => {
+ const databaseItem = await databaseUI.getDatabaseItem(progress, token);
+
+ expect(databaseItem).toEqual({ databaseUri: Uri.file(db1) });
+ });
+ });
+
+ describe("when there is no current database", () => {
+ const databaseManager = {
+ databaseItems: [
+ { databaseUri: Uri.file(db1) },
+ { databaseUri: Uri.file(db2) },
+ ],
+ onDidChangeDatabaseItem: () => {
+ /**/
+ },
+ onDidChangeCurrentDatabaseItem: () => {
+ /**/
+ },
+ setCurrentDatabaseItem: () => {},
+ currentDatabaseItem: undefined,
+ } as any;
+
+ const databaseUI = new DatabaseUI(
+ app,
+ databaseManager,
+ {
+ onLanguageContextChanged: () => {
+ /**/
+ },
+ } as any,
+ {} as any,
+ storageDir,
+ storageDir,
+ );
+
+ it("should prompt for a database and select existing one", async () => {
+ const showQuickPickSpy = jest
+ .spyOn(window, "showQuickPick")
+ .mockResolvedValueOnce(
+ mockedQuickPickItem(
+ mockedObject({
+ databaseKind: "existing",
+ }),
+ ),
+ )
+ .mockResolvedValueOnce(
+ mockedQuickPickItem(
+ mockedObject({
+ databaseItem: { databaseUri: Uri.file(db2) },
+ }),
+ ),
+ );
+
+ const setCurrentDatabaseItemSpy = jest.spyOn(
+ databaseManager,
+ "setCurrentDatabaseItem",
+ );
+
+ await databaseUI.getDatabaseItem(progress, token);
+
+ expect(showQuickPickSpy).toHaveBeenCalledTimes(2);
+ expect(setCurrentDatabaseItemSpy).toHaveBeenCalledWith({
+ databaseUri: Uri.file(db2),
+ });
+ });
+
+ it("should prompt for a database and import a new one", async () => {
+ const showQuickPickSpy = jest
+ .spyOn(window, "showQuickPick")
+ .mockResolvedValueOnce(
+ mockedQuickPickItem(
+ mockedObject({
+ databaseKind: "new",
+ }),
+ ),
+ )
+ .mockResolvedValueOnce(
+ mockedQuickPickItem(
+ mockedObject({
+ importType: "github",
+ }),
+ ),
+ );
+
+ const handleChooseDatabaseGithubSpy = jest
+ .spyOn(databaseUI as any, "handleChooseDatabaseGithub")
+ .mockResolvedValue(undefined);
+
+ await databaseUI.getDatabaseItem(progress, token);
+
+ expect(showQuickPickSpy).toHaveBeenCalledTimes(2);
+ expect(handleChooseDatabaseGithubSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+
function createDatabase(
storageDir: string,
dbName: string,
diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/local-queries/query-resolver.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/local-queries/query-resolver.test.ts
index 9e4dec27b..20114aac6 100644
--- a/extensions/ql-vscode/test/vscode-tests/no-workspace/local-queries/query-resolver.test.ts
+++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/local-queries/query-resolver.test.ts
@@ -112,7 +112,7 @@ describe("resolveQueries", () => {
"tags contain": ["ide-contextual-queries/print-ast"],
},
),
- ).rejects.toThrowError(
+ ).rejects.toThrow(
'No my query queries (kind "graph", tagged "ide-contextual-queries/print-ast") could be found in the current library path (tried searching the following packs: my-qlpack). Try upgrading the CodeQL libraries. If that doesn\'t work, then my query queries are not yet available for this language.',
);
});
diff --git a/extensions/ql-vscode/tsconfig.json b/extensions/ql-vscode/tsconfig.json
index 19759b3dc..93f7cb0f2 100644
--- a/extensions/ql-vscode/tsconfig.json
+++ b/extensions/ql-vscode/tsconfig.json
@@ -24,5 +24,5 @@
"noEmit": true
},
"include": ["src/**/*.ts"],
- "exclude": ["node_modules", "test", "**/view"]
+ "exclude": ["node_modules", "*.config.ts", "test", "**/view"]
}